Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
hammock.apache.ApacheInterpreter.scala Maven / Gradle / Ivy
package hammock
package apache
import cats._
import cats.data._
import cats.implicits._
import cats.effect.Sync
import java.io.{BufferedReader , InputStreamReader }
import org.apache.http.{Header , HttpEntity , HttpResponse => ApacheResponse }
import org.apache.http.client.HttpClient
import org.apache.http.client.methods._
import org.apache.http.{entity => apache}
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.message.BasicHeader
import org.apache.http.util.EntityUtils
import Uri ._
import scala.annotation.tailrec
object ApacheInterpreter {
def apply [F [_]](implicit F : InterpTrans [F ]): InterpTrans [F ] = F
implicit def instance [F [_]: Sync ](
implicit
client: HttpClient = HttpClientBuilder .create().build()): InterpTrans [F ] =
new InterpTrans [F ] {
def trans : HttpF ~> F = transK andThen λ[Kleisli [F , HttpClient , *] ~> F ](_.run(client))
}
def transK [F [_]: Sync ]: HttpF ~> Kleisli [F , HttpClient , *] = {
def responseToEntity (response: ApacheResponse ): F [Entity ] = Sync [F ].delay {
Option (response.getEntity)
.map(_.getContent)
.map { content =>
val rd = new BufferedReader (new InputStreamReader (content))
Entity .StringEntity (readBuffer(rd))
} getOrElse Entity .EmptyEntity
}
def doReq (reqF: HttpF [HttpResponse ]): Kleisli [F , HttpClient , HttpResponse ] = Kleisli { client =>
for {
req <- mapRequest(reqF)
resp <- Sync [F ].delay(client.execute(req))
entity <- responseToEntity(resp)
status <- Status .get(resp.getStatusLine.getStatusCode).pure[F ]
responseHeaders <- resp.getAllHeaders.map(h => h.getName -> h.getValue).toMap.pure[F ]
_ <- Sync [F ].delay(EntityUtils .consume(resp.getEntity))
} yield HttpResponse (status, responseHeaders, entity)
}
λ[HttpF ~> Kleisli [F , HttpClient , *]] {
case req: Options => doReq(req)
case req: Get => doReq(req)
case req: Head => doReq(req)
case req: Post => doReq(req)
case req: Put => doReq(req)
case req: Delete => doReq(req)
case req: Trace => doReq(req)
case req: Patch => doReq(req)
}
}
def mapRequest [F [_]: Sync ](f: HttpF [HttpResponse ]): F [HttpUriRequest ] = {
def mapContentType (contentType: ContentType ): F [apache.ContentType ] =
Sync [F ].delay(apache.ContentType .parse(contentType.name))
def mapEntity (entity: Entity ): F [HttpEntity ] = entity match {
case Entity .StringEntity (body, contentType) =>
mapContentType(contentType) map (parsedContentType => new apache.StringEntity (body, parsedContentType))
case Entity .ByteArrayEntity (body, contentType) =>
mapContentType(contentType) map (parsedContentType => new apache.ByteArrayEntity (body, parsedContentType))
case Entity .EmptyEntity => Sync [F ].delay(new apache.BasicHttpEntity ())
}
def prepareHeaders (headers: Map [String , String ]): Array [Header ] =
headers.map { case (k, v) => new BasicHeader (k, v) }.toArray
f match {
case Get (HttpRequest (uri, headers, _)) =>
Sync [F ].delay {
val req = new HttpGet (uri.show)
req.setHeaders(prepareHeaders(headers))
req
}
case Options (HttpRequest (uri, headers, _)) =>
Sync [F ].delay {
val req = new HttpOptions (uri.show)
req.setHeaders(prepareHeaders(headers))
req
}
case Head (HttpRequest (uri, headers, _)) =>
Sync [F ].delay {
val req = new HttpHead (uri.show)
req.setHeaders(prepareHeaders(headers))
req
}
case Post (HttpRequest (uri, headers, entity)) =>
for {
req <- Sync [F ].delay(new HttpPost (uri.show))
_ <- Sync [F ].delay(req.setHeaders(prepareHeaders(headers)))
_ <- if (entity.isDefined) {
mapEntity(entity.get) >>= (apacheEntity => Sync [F ].delay(req.setEntity(apacheEntity)))
} else ().pure[F ]
} yield req
case Put (HttpRequest (uri, headers, maybeEntity)) =>
for {
req <- Sync [F ].delay(new HttpPut (uri.show))
_ <- Sync [F ].delay(req.setHeaders(prepareHeaders(headers)))
_ <- if (maybeEntity.isDefined) {
mapEntity(maybeEntity.get) >>= (apacheEntity => Sync [F ].delay(req.setEntity(apacheEntity)))
} else ().pure[F ]
} yield req
case Delete (HttpRequest (uri, headers, _)) =>
Sync [F ].delay {
val req = new HttpDelete (uri.show)
req.setHeaders(prepareHeaders(headers))
req
}
case Trace (HttpRequest (uri, headers, _)) =>
Sync [F ].delay {
val req = new HttpTrace (uri.show)
req.setHeaders(prepareHeaders(headers))
req
}
case Patch (HttpRequest (uri, headers, entity)) =>
for {
req <- Sync [F ].delay(new HttpPatch (uri.show))
_ <- Sync [F ].delay(req.setHeaders(prepareHeaders(headers)))
_ <- if (entity.isDefined) {
mapEntity(entity.get) >>= (apacheEntity => Sync [F ].delay(req.setEntity(apacheEntity)))
} else ().pure[F ]
} yield req
}
}
private def readBuffer (reader: BufferedReader ): String = {
@tailrec
def go (reader: BufferedReader , acc: Array [String ]): Array [String ] = {
val line = reader.readLine()
if (line != null )
go(reader, acc :+ line)
else
acc
}
go(reader, Array .empty).mkString("" )
}
}