cats.data.Kleisli Scala Examples
The following examples show how to use cats.data.Kleisli.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example.
Example 1
Source File: NatchezHttp4sModule.scala From skunk with MIT License | 8 votes |
// Copyright (c) 2018-2020 by Rob Norris // This software is licensed under the MIT License (MIT). // For more information see LICENSE or https://opensource.org/licenses/MIT package natchez.http4s import cats.~> import cats.data.{ Kleisli, OptionT } import cats.effect.Bracket import cats.implicits._ import natchez.{ EntryPoint, Kernel, Span } import org.http4s.HttpRoutes import natchez.Trace import natchez.Tags import scala.util.control.NonFatal import org.http4s.Response import cats.effect.Resource import cats.Defer import natchez.TraceValue import cats.Monad object implicits { // Given an entry point and HTTP Routes in Kleisli[F, Span[F], ?] return routes in F. A new span // is created with the URI path as the name, either as a continuation of the incoming trace, if // any, or as a new root. This can likely be simplified, I just did what the types were saying // and it works so :shrug: private def liftT[F[_]: Bracket[?[_], Throwable]]( entryPoint: EntryPoint[F])( routes: HttpRoutes[Kleisli[F, Span[F], ?]] ): HttpRoutes[F] = Kleisli { req => type G[A] = Kleisli[F, Span[F], A] val lift = λ[F ~> G](fa => Kleisli(_ => fa)) val kernel = Kernel(req.headers.toList.map(h => (h.name.value -> h.value)).toMap) val spanR = entryPoint.continueOrElseRoot(req.uri.path, kernel) OptionT { spanR.use { span => val lower = λ[G ~> F](_(span)) routes.run(req.mapK(lift)).mapK(lower).map(_.mapK(lower)).value } } } implicit class EntryPointOps[F[_]](self: EntryPoint[F]) { private def dummySpan( implicit ev: Monad[F] ): Span[F] = new Span[F] { val kernel: F[Kernel] = Kernel(Map.empty).pure[F] def put(fields: (String, TraceValue)*): F[Unit] = Monad[F].unit def span(name: String): Resource[F, Span[F]] = Monad[Resource[F, ?]].pure(this) } def liftT(routes: HttpRoutes[Kleisli[F, Span[F], ?]])( implicit ev: Bracket[F, Throwable] ): HttpRoutes[F] = implicits.liftT(self)(routes) def natchezMiddleware[F[_]: Bracket[?[_], Throwable]: Trace](routes: HttpRoutes[F]): HttpRoutes[F] = Kleisli { req => val addRequestFields: F[Unit] = Trace[F].put( Tags.http.method(req.method.name), Tags.http.url(req.uri.renderString) ) def addResponseFields(res: Response[F]): F[Unit] = Trace[F].put( Tags.http.status_code(res.status.code.toString) ) def addErrorFields(e: Throwable): F[Unit] = Trace[F].put( Tags.error(true), "error.message" -> e.getMessage, "error.stacktrace" -> e.getStackTrace.mkString("\n"), ) OptionT { routes(req).onError { case NonFatal(e) => OptionT.liftF(addRequestFields *> addErrorFields(e)) } .value.flatMap { case Some(handler) => addRequestFields *> addResponseFields(handler).as(handler.some) case None => Option.empty[Response[F]].pure[F] } } } }
Example 2
Source File: ExampleApp.scala From caliban with Apache License 2.0 | 5 votes |
package caliban.http4s import caliban.ExampleData._ import caliban.ExampleService.ExampleService import caliban.{ ExampleApi, ExampleService, Http4sAdapter } import cats.data.Kleisli import cats.effect.Blocker import org.http4s.StaticFile import org.http4s.implicits._ import org.http4s.server.Router import org.http4s.server.blaze.BlazeServerBuilder import org.http4s.server.middleware.CORS import zio._ import zio.blocking.Blocking import zio.interop.catz._ import scala.concurrent.ExecutionContext object ExampleApp extends App { type ExampleTask[A] = RIO[ZEnv with ExampleService, A] override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] = ZIO .runtime[ZEnv with ExampleService] .flatMap(implicit runtime => for { blocker <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext) interpreter <- ExampleApi.api.interpreter _ <- BlazeServerBuilder[ExampleTask](ExecutionContext.global) .bindHttp(8088, "localhost") .withHttpApp( Router[ExampleTask]( "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)), "/ws/graphql" -> CORS(Http4sAdapter.makeWebSocketService(interpreter)), "/graphiql" -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None)) ).orNotFound ) .resource .toManaged .useForever } yield () ) .provideCustomLayer(ExampleService.make(sampleCharacters)) .exitCode }
Example 3
Source File: Issue121.scala From guardrail with MIT License | 5 votes |
package core.issues import cats.effect.IO import cats.data.Kleisli import org.http4s._ import org.http4s.client.{ Client => Http4sClient } import org.http4s.client.blaze._ import org.http4s.headers._ import org.http4s.implicits._ import org.http4s.multipart._ import cats.instances.future._ import org.scalatest.concurrent.ScalaFutures import org.scalatest.time.SpanSugar._ import org.scalatest.{ EitherValues, FunSuite, Matchers } import io.circe._ class Issue121Suite extends FunSuite with Matchers with EitherValues with ScalaFutures { override implicit val patienceConfig = PatienceConfig(10 seconds, 1 second) test("http4s server can respond with 204") { import issues.issue121.server.http4s.{ DeleteFooResponse, Handler, Resource } val route = new Resource[IO]().routes(new Handler[IO] { override def deleteFoo(respond: DeleteFooResponse.type)(id: Long): IO[DeleteFooResponse] = IO.pure(respond.NoContent) }) val client = Http4sClient.fromHttpApp[IO](route.orNotFound) val req = Request[IO](method = Method.DELETE, uri = Uri.unsafeFromString("/entity")).withEntity(UrlForm("id" -> "1234")) client .fetch(req)({ case Status.NoContent(resp) => IO.pure({ resp.status should equal(Status.NoContent) resp.contentType should equal(None) resp.contentLength should equal(None) () }) }) .unsafeRunSync() } test("http4s client can respond with 204") { import issues.issue121.client.http4s.Client def noContentResponse: Http4sClient[IO] = Http4sClient.fromHttpApp[IO](Kleisli.pure(Response[IO](Status.NoContent))) Client .httpClient(noContentResponse, "http://localhost:80") .deleteFoo(1234) .attempt .unsafeRunSync() .fold( _ => fail("Error"), _.fold( handleNoContent = () ) ) } }
Example 4
Source File: Issue542.scala From guardrail with MIT License | 5 votes |
package core.issues import cats.effect.IO import cats.data.Kleisli import org.http4s._ import org.http4s.circe._ import org.http4s.client.{ Client => Http4sClient } import org.http4s.headers._ import org.http4s.implicits._ import cats.instances.future._ import org.scalatest.concurrent.ScalaFutures import org.scalatest.time.SpanSugar._ import org.scalatest.{ EitherValues, FunSuite, Matchers, OptionValues } import tests.scalatest.EitherTValues class Issue542Suite extends FunSuite with Matchers with EitherValues with ScalaFutures with EitherTValues with OptionValues { override implicit val patienceConfig = PatienceConfig(10 seconds, 1 second) test("base64 bytes can be sent") { import base64.server.http4s.{ FooResponse, Handler, Resource } import base64.server.http4s.definitions.Foo import base64.server.http4s.Implicits.Base64String val route = new Resource[IO]().routes(new Handler[IO] { def foo(respond: FooResponse.type)(): IO[FooResponse] = IO.pure(respond.Ok(Foo(Some(new Base64String("foo".getBytes()))))) }) val client = Http4sClient.fromHttpApp[IO](route.orNotFound) val req = Request[IO](method = Method.GET, uri = Uri.unsafeFromString("/foo")) client .fetch(req)({ case Status.Ok(resp) => resp.status should equal(Status.Ok) resp.contentType should equal(Some(`Content-Type`(MediaType.application.json))) resp.contentLength should equal(Some(16)) jsonOf[IO, Foo].decode(resp, strict = false).rightValue }) .unsafeRunSync() .value .value .data should equal("foo".getBytes()) } test("base64 bytes can be received") { import base64.client.http4s.Client import base64.client.http4s.definitions.Foo import base64.client.http4s.Implicits.Base64String import org.http4s.dsl._ def staticClient: Http4sClient[IO] = { implicit val fooOkEncoder = jsonEncoderOf[IO, Foo] val response = new Http4sDsl[IO] { def route: HttpApp[IO] = Kleisli.liftF(Ok(Foo(Some(Base64String("foo".getBytes()))))) } Http4sClient.fromHttpApp[IO](response.route) } Client .httpClient(staticClient, "http://localhost:80") .foo() .attempt .unsafeRunSync() .fold( _ => fail("Error"), _.fold( handleOk = _.value.value.data should equal("foo".getBytes()) ) ) } }
Example 5
Source File: CassandraOffsetStore.scala From aecor with MIT License | 5 votes |
package aecor.runtime.akkapersistence.readside import java.util.UUID import aecor.data.TagConsumer import aecor.runtime.KeyValueStore import aecor.util.effect._ import akka.persistence.cassandra.Session.Init import akka.persistence.cassandra.session.scaladsl.CassandraSession import cats.Functor import cats.data.Kleisli import cats.effect.Effect import cats.implicits._ object CassandraOffsetStore { final case class Queries(keyspace: String, tableName: String = "consumer_offset") { def createTableQuery: String = s"CREATE TABLE IF NOT EXISTS $keyspace.$tableName (consumer_id text, tag text, offset uuid, PRIMARY KEY ((consumer_id, tag)))" def updateOffsetQuery: String = s"UPDATE $keyspace.$tableName SET offset = ? where consumer_id = ? AND tag = ?" def deleteOffsetQuery: String = s"DELETE FROM $keyspace.$tableName where consumer_id = ? AND tag = ?" def selectOffsetQuery: String = s"SELECT offset FROM $keyspace.$tableName WHERE consumer_id = ? AND tag = ?" } def apply[F[_]]: Builder[F] = builderInstance.asInstanceOf[Builder[F]] private val builderInstance = new Builder[Any]() final class Builder[F[_]] private[CassandraOffsetStore] () { def createTable(config: Queries)(implicit F: Functor[F]): Init[F] = Kleisli(_.execute(config.createTableQuery).void) def apply(session: CassandraSession, config: CassandraOffsetStore.Queries)( implicit F: Effect[F] ): CassandraOffsetStore[F] = new CassandraOffsetStore(session, config) } } class CassandraOffsetStore[F[_]] private[akkapersistence] ( session: CassandraSession, config: CassandraOffsetStore.Queries )(implicit F: Effect[F]) extends KeyValueStore[F, TagConsumer, UUID] { private val selectOffsetStatement = session.prepare(config.selectOffsetQuery) private val updateOffsetStatement = session.prepare(config.updateOffsetQuery) private val deleteOffsetStatement = session.prepare(config.deleteOffsetQuery) override def setValue(key: TagConsumer, value: UUID): F[Unit] = F.fromFuture { updateOffsetStatement } .map { stmt => stmt .bind() .setUUID("offset", value) .setString("tag", key.tag.value) .setString("consumer_id", key.consumerId.value) } .flatMap(x => F.fromFuture(session.executeWrite(x))) .void override def getValue(key: TagConsumer): F[Option[UUID]] = F.fromFuture { selectOffsetStatement } .map(_.bind(key.consumerId.value, key.tag.value)) .flatMap(x => F.fromFuture(session.selectOne(x))) .map(_.map(_.getUUID("offset"))) override def deleteValue(key: TagConsumer): F[Unit] = F.fromFuture { deleteOffsetStatement } .map(_.bind(key.consumerId.value, key.tag.value)) .flatMap(x => F.fromFuture(session.executeWrite(x))) .void }
Example 6
Source File: Session.scala From aecor with MIT License | 5 votes |
package akka.persistence.cassandra import java.util.concurrent.Executor import cats.data.Kleisli import cats.effect.{ Async, ContextShift } import com.datastax.driver.core.{ ResultSet, TypeCodec, Session => DatastaxSession } import scala.concurrent.ExecutionContext import scala.util.control.NonFatal trait Session[F[_]] { def execute(query: String): F[ResultSet] def registerCodec[A](codec: TypeCodec[A]): F[Unit] } object Session { type Init[F[_]] = Kleisli[F, Session[F], Unit] def Init[F[_]](f: Session[F] => F[Unit]): Init[F] = Kleisli(f) private val immediateExecutor = new Executor { override def execute(command: Runnable): Unit = command.run() } private val immediateExecutionContext = ExecutionContext.fromExecutor(immediateExecutor) def apply[F[_]](datastaxSession: DatastaxSession)(implicit F: Async[F], contextShift: ContextShift[F]): Session[F] = new Session[F] { final override def execute(query: String): F[ResultSet] = contextShift.evalOn(immediateExecutionContext) { F.async { cb => val future = datastaxSession.executeAsync(query) val runnable = new Runnable { override def run(): Unit = try { cb(Right(future.get())) } catch { case NonFatal(e) => cb(Left(e)) } } future.addListener(runnable, immediateExecutor) } } override def registerCodec[A](codec: TypeCodec[A]): F[Unit] = F.delay { datastaxSession.getCluster.getConfiguration.getCodecRegistry.register(codec) () } } }
Example 7
Source File: Minimal2.scala From skunk with MIT License | 5 votes |
// Copyright (c) 2018-2020 by Rob Norris // This software is licensed under the MIT License (MIT). // For more information see LICENSE or https://opensource.org/licenses/MIT package example import cats.Parallel import cats.effect._ import cats.implicits._ import skunk._ import skunk.implicits._ import skunk.codec.all._ import natchez.Trace import cats.data.Kleisli import natchez.Span import natchez.jaeger.Jaeger import natchez.EntryPoint import io.jaegertracing.Configuration.SamplerConfiguration import io.jaegertracing.Configuration.ReporterConfiguration object Minimal2 extends IOApp { def session[F[_]: Concurrent: ContextShift: Trace]: Resource[F, Session[F]] = Session.single( host = "localhost", port = 5432, user = "jimmy", database = "world", password = Some("banana"), // debug = true ) case class Country(code: String, name: String, pop: Int) val select: Query[String, Country] = sql""" select code, name, population from country WHERE name like $varchar """.query(bpchar(3) ~ varchar ~ int4) .gmap[Country] def lookup[F[_]: Sync: Trace](pat: String, s: Session[F]): F[Unit] = Trace[F].span("lookup") { Trace[F].put("pattern" -> pat) *> s.prepare(select).use { pq => pq.stream(pat, 1024) .evalMap(c => Sync[F].delay(println(s"⭐️⭐ $c"))) .compile .drain } } def runF[F[_]: Concurrent: ContextShift: Trace: Parallel]: F[ExitCode] = session.use { s => List("A%", "B%").parTraverse(p => lookup(p, s)) } as ExitCode.Success def tracer[F[_]: Sync]: Resource[F, EntryPoint[F]] = { Jaeger.entryPoint[F]("skunk-http4s-example") { c => Sync[F].delay { c.withSampler(SamplerConfiguration.fromEnv) .withReporter(ReporterConfiguration.fromEnv) .getTracer } } } def run(args: List[String]): IO[ExitCode] = tracer[IO].use { t => t.root("root").use { s => runF[Kleisli[IO, Span[IO], ?]].run(s) *> runF[Kleisli[IO, Span[IO], ?]].run(s) } } }
Example 8
Source File: LoginTest.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.endpoint import cats.data.Kleisli import cats.effect.IO import domain.authentication.{LoginRequest, SignupRequest} import domain.users.{Role, User} import org.http4s.circe.{jsonEncoderOf, jsonOf} import org.http4s.client.dsl.Http4sClientDsl import org.http4s.{EntityDecoder, EntityEncoder, HttpApp, Request, Response} import org.http4s.implicits._ import org.http4s.headers.Authorization import io.circe.generic.auto._ import org.http4s.dsl.Http4sDsl trait LoginTest extends Http4sClientDsl[IO] with Http4sDsl[IO] { implicit val userEnc: EntityEncoder[IO, User] = jsonEncoderOf implicit val userDec: EntityDecoder[IO, User] = jsonOf implicit val signUpRequestEnc: EntityEncoder[IO, SignupRequest] = jsonEncoderOf implicit val signUpRequestDec: EntityDecoder[IO, SignupRequest] = jsonOf implicit val loginRequestEnc: EntityEncoder[IO, LoginRequest] = jsonEncoderOf implicit val loginRequestDec: EntityDecoder[IO, LoginRequest] = jsonOf def signUpAndLogIn( userSignUp: SignupRequest, userEndpoint: HttpApp[IO], ): IO[(User, Option[Authorization])] = for { signUpRq <- POST(userSignUp, uri"/users") signUpResp <- userEndpoint.run(signUpRq) user <- signUpResp.as[User] loginBody = LoginRequest(userSignUp.userName, userSignUp.password) loginRq <- POST(loginBody, uri"/users/login") loginResp <- userEndpoint.run(loginRq) } yield { user -> loginResp.headers.get(Authorization) } def signUpAndLogInAsAdmin( userSignUp: SignupRequest, userEndpoint: Kleisli[IO, Request[IO], Response[IO]], ): IO[(User, Option[Authorization])] = signUpAndLogIn(userSignUp.copy(role = Role.Admin), userEndpoint) def signUpAndLogInAsCustomer( userSignUp: SignupRequest, userEndpoint: Kleisli[IO, Request[IO], Response[IO]], ): IO[(User, Option[Authorization])] = signUpAndLogIn(userSignUp.copy(role = Role.Customer), userEndpoint) }
Example 9
Source File: HttpMetricsMiddleware.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http.metrics import cats.data.{Kleisli, OptionT} import cats.effect.Sync import cats.syntax.flatMap._ import cats.syntax.functor._ import com.codahale.metrics._ import com.smartbackpackerapp.common.Log import com.smartbackpackerapp.http.ApiVersion import org.http4s.AuthedService import org.http4s.Uri.Path object HttpMetricsMiddleware { def apply[F[_]](registry: MetricRegistry, service: AuthedService[String, F]) (implicit F: Sync[F], L: Log[F]): AuthedService[String, F] = { Kleisli { req => OptionT.liftF(F.delay(System.nanoTime())).flatMap { start => service(req).semiflatMap { response => HttpMetrics.parse(req.req.uri.path).fold(F.delay(response)) { path => for { _ <- F.delay(registry.meter(s"requests-$path").mark()) _ <- if (response.status.isSuccess) F.delay(registry.meter(s"success-$path").mark()) else F.delay(registry.meter(s"failure-${response.status.code}-$path").mark()) time <- F.delay((System.nanoTime() - start) / 1000000) _ <- F.delay(registry.histogram(s"response-time-$path").update(time)) _ <- L.info(s"HTTP Response Time: $time ms") } yield response } } } } } } object HttpMetrics { def parse(path: Path): Option[String] = { if (path.contains("/traveling")) Some(s"$ApiVersion-traveling") else if (path.contains("/airlines")) Some(s"$ApiVersion-airlines") else if (path.contains("/ranking")) Some(s"$ApiVersion-ranking") else if (path.contains("/health")) Some(s"$ApiVersion-health") else if (path.contains("/countries")) Some(s"$ApiVersion-countries") else None } }
Example 10
Source File: JwtTokenAuthMiddleware.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http.auth import cats.data.{EitherT, Kleisli, OptionT} import cats.effect.Sync import cats.syntax.applicativeError._ import cats.syntax.functor._ import com.smartbackpackerapp.http.auth.JwtTokenAuthMiddleware.AuthConfig import org.http4s.Credentials.Token import org.http4s.dsl.Http4sDsl import org.http4s.{AuthScheme, AuthedService, Request} import org.http4s.headers.Authorization import org.http4s.server.AuthMiddleware import tsec.jws.mac.JWTMac import tsec.mac.imports._ object JwtTokenAuthMiddleware { def apply[F[_] : Sync](apiToken: Option[String]): F[AuthMiddleware[F, String]] = new Middleware[F](apiToken).middleware case class AuthConfig(jwtKey: MacSigningKey[HMACSHA256]) } class Middleware[F[_]](apiToken: Option[String])(implicit F: Sync[F]) { private val ifEmpty = F.raiseError[AuthMiddleware[F, String]](new Exception("Api Token not found")) private def generateJwtKey(token: String): F[MacSigningKey[HMACSHA256]] = { F.catchNonFatal(HMACSHA256.buildKeyUnsafe(token.getBytes)) } val middleware: F[AuthMiddleware[F, String]] = apiToken.fold(ifEmpty) { token => generateJwtKey(token).map { jwtKey => val config = AuthConfig(jwtKey) new JwtTokenAuthMiddleware[F](config).middleware } } } class JwtTokenAuthMiddleware[F[_] : Sync](config: AuthConfig) extends Http4sDsl[F] { private val onFailure: AuthedService[String, F] = Kleisli(req => OptionT.liftF(Forbidden(req.authInfo))) private def bearerTokenFromRequest(request: Request[F]): OptionT[F, String] = OptionT.fromOption[F] { request.headers.get(Authorization).collect { case Authorization(Token(AuthScheme.Bearer, token)) => token } } private def verifyToken(request: Request[F], jwtKey: MacSigningKey[HMACSHA256]): OptionT[F, String] = for { token <- bearerTokenFromRequest(request) verified <- OptionT.liftF(JWTMac.verifyAndParse[F, HMACSHA256](token, jwtKey)) accessToken <- OptionT.fromOption[F](verified.body.subject) } yield accessToken private def authUser(jwtKey: MacSigningKey[HMACSHA256]): Kleisli[F, Request[F], Either[String, String]] = Kleisli { request => verifyToken(request, jwtKey).value.map { option => Either.cond[String, String](option.isDefined, option.get, "Unable to authorize token") }.recoverWith { case MacVerificationError(msg) => EitherT.leftT(msg).value } } def middleware: AuthMiddleware[F, String] = AuthMiddleware(authUser(config.jwtKey), onFailure) }
Example 11
Source File: Http4sUtils.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http import cats.{Applicative, Monad} import cats.data.{Kleisli, OptionT} import cats.effect.IO import monix.eval.Task import monix.execution.Scheduler.Implicits.global import org.http4s.server.AuthMiddleware import org.http4s.{EntityBody, Request} import scala.concurrent.Await import scala.concurrent.duration.Duration object Http4sUtils { private def authUser[F[_]](implicit F: Applicative[F]): Kleisli[OptionT[F, ?], Request[F], String] = Kleisli(_ => OptionT.liftF(F.pure("access_token"))) def middleware[F[_]: Monad]: AuthMiddleware[F, String] = AuthMiddleware.apply[F, String](authUser) val taskMiddleware: AuthMiddleware[Task, String] = middleware[Task] val ioMiddleware: AuthMiddleware[IO, String] = middleware[IO] implicit class ByteVector2String(body: EntityBody[IO]) { def asString: String = { val array = body.compile.toVector.unsafeRunSync().toArray new String(array.map(_.toChar)) } } implicit class ByteVector2StringTask(body: EntityBody[Task]) { def asString: String = { val array = Await.result(body.compile.toVector.runAsync, Duration.Inf).toArray new String(array.map(_.toChar)) } } }
Example 12
Source File: TaskMT.scala From Waves with MIT License | 5 votes |
package com.wavesplatform.lang.v1.task import cats.data.Kleisli import cats.implicits._ import cats.{Eval, Functor, Monad} import com.wavesplatform.lang.EvalF import monix.execution.atomic.{Atomic, AtomicBuilder} trait TaskMT[F[_], S, E, R] { protected[task] val inner: Kleisli[Eval, EvalRef[S], F[Either[E, R]]] def run[RS <: Atomic[S]](initial: S)(implicit b: AtomicBuilder[S, RS]): Eval[(S, F[Either[E, R]])] = { val stateRef = EvalRef.of(initial) for { result <- inner.run(stateRef) finalState <- stateRef.read } yield (finalState, result) } def map[B](f: R => B)(implicit ev: Functor[F]): TaskMT[F, S, E, B] = TaskMT.fromKleisli(inner.map(_.map { case Right(v) => Right(f(v)) case Left(err) => Left(err) })) def flatMap[B](f: R => TaskMT[F, S, E, B])(implicit m: Monad[EvalF[F, ?]]): TaskMT[F, S, E, B] = { TaskMT.fromEvalRef[F, S, E, B] { s => m.flatMap(inner.run(s)) { case Right(v) => f(v).inner.run(s) case Left(err) => m.pure(err.asLeft[B]) } } } def handleErrorWith(f: E => TaskMT[F, S, E, R])(implicit m: Monad[EvalF[F, ?]]): TaskMT[F, S, E, R] = TaskMT.fromEvalRef[F, S, E, R] { s => m.flatMap(inner.run(s)) { case Right(v) => m.pure(v.asRight[E]) case Left(err) => f(err).inner.run(s) } } def handleError()(implicit m: Monad[EvalF[F, ?]]): TaskMT[F, S, E, (Option[R], List[E])] = { TaskMT.fromEvalRef[F, S, E, (Option[R], List[E])] { s => m.flatMap(inner.run(s)) { case Right(v) => m.pure((Some(v), List.empty).asRight[E]) case Left(err) => m.pure((None, List(err)).asRight[E]) } } } } object TaskMT { private[task] def fromKleisli[F[_], S, E, R](in: Kleisli[Eval, EvalRef[S], F[Either[E, R]]]): TaskMT[F, S, E, R] = new TaskMT[F, S, E, R] { override protected[task] val inner: Kleisli[Eval, EvalRef[S], F[Either[E, R]]] = in } def apply[F[_], S, E, R](f: S => Eval[F[Either[E, R]]]): TaskMT[F, S, E, R] = fromEvalRef(_.read flatMap f) private def fromEvalRef[F[_], S, E, R](f: EvalRef[S] => Eval[F[Either[E, R]]]): TaskMT[F, S, E, R] = new TaskMT[F, S, E, R] { override protected[task] val inner: Kleisli[Eval, EvalRef[S], F[Either[E, R]]] = Kleisli(f) } }
Example 13
Source File: TaskMTFunctions.scala From Waves with MIT License | 5 votes |
package com.wavesplatform.lang.v1.task import cats.{Eval, Monad} import cats.data.Kleisli import cats.implicits._ import com.wavesplatform.lang.EvalF trait TaskMTFunctions { def pure[F[_] : Monad, S, E, R](x: R): TaskMT[F, S, E, R] = TaskMT(_ => Eval.now(x.asRight[E].pure[F])) def raiseError[F[_] : Monad, S, E, R](e: E): TaskMT[F, S, E, R] = TaskMT(_ => Eval.now(e.asLeft[R].pure[F])) def liftEither[F[_] : Monad, S, E, R](ei: Either[E, R]): TaskMT[F, S, E, R] = TaskMT.fromKleisli(Kleisli.pure(ei.pure[F])) def get[F[_] : Monad, S, E]: TaskMT[F, S, E, S] = TaskMT(s => Eval.now(s.asRight[E].pure[F])) def set[F[_] : Monad, S, E](s: S): TaskMT[F, S, E, Unit] = TaskMT.fromKleisli(Kleisli(ref => { ref.write(s).map(_.asRight[E].pure[F]) })) def local[F[_], S, E, A](fa: TaskMT[F, S, E, A]): TaskMT[F, S, E, A] = { TaskMT.fromKleisli(Kleisli((ref: EvalRef[S]) => { val newRef = ref.copy() fa.inner.run(newRef) })) } def id[F[_], S, E, A](fa: TaskMT[F, S, E, A]): TaskMT[F, S, E, A] = fa def inspect[F[_] : Monad, S, E, A](f: S => A): TaskMT[F, S, E, A] = get[F, S, E].map(f) def inspectFlat[F[_] : Monad, S, E, A](f: S => TaskMT[F, S, E, A])(implicit m: Monad[EvalF[F, ?]]): TaskMT[F, S, E, A] = get[F, S, E].flatMap(f) def modify[F[_] : Monad, S, E](f: S => S)(implicit m: Monad[EvalF[F, ?]]): TaskMT[F, S, E, Unit] = get[F, S, E].flatMap(f andThen set[F, S, E]) }
Example 14
Source File: ConditionalLoggerSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.extras.loggers import cats.data.Kleisli import cats.effect.Sync import cats.effect.concurrent.Ref import cats.mtl.instances.all._ import cats.syntax.applicativeError._ import cats.syntax.flatMap._ import cats.syntax.order._ import io.odin.loggers.{DefaultLogger, HasContext} import io.odin.syntax._ import io.odin.extras.syntax._ import io.odin.{Level, LoggerMessage, OdinSpec} import monix.eval.Task import monix.execution.schedulers.TestScheduler class ConditionalLoggerSpec extends OdinSpec { implicit private val scheduler: TestScheduler = TestScheduler() type F[A] = Kleisli[Task, Map[String, String], A] case class RefLogger(ref: Ref[F, List[LoggerMessage]]) extends DefaultLogger[F] { def log(msg: LoggerMessage): F[Unit] = ref.update(_ :+ msg) } implicit private val hasContext: HasContext[Map[String, String]] = (env: Map[String, String]) => env it should "use log level of the inner logger in case of success" in { forAll { (messages: List[LoggerMessage], ctx: Map[String, String]) => val fa = for { ref <- Ref.of[F, List[LoggerMessage]](List.empty) _ <- RefLogger(ref) .withMinimalLevel(Level.Info) .withContext .withErrorLevel(Level.Debug)(logger => logger.log(messages)) written <- ref.get } yield written val written = fa.run(ctx).runSyncUnsafe() val expected = messages.filter(_.level >= Level.Info).map(m => m.copy(context = m.context ++ ctx)) written shouldBe expected } } it should "use log level of the conditional logger in case of error" in { forAll { (messages: List[LoggerMessage], ctx: Map[String, String]) => val error = new RuntimeException("Boom") val fa = for { ref <- Ref.of[F, List[LoggerMessage]](List.empty) attempt <- RefLogger(ref) .withMinimalLevel(Level.Info) .withContext .withErrorLevel(Level.Debug)(logger => logger.log(messages) >> Sync[F].raiseError[Unit](error)) .attempt written <- ref.get } yield (attempt, written) val (attempt, written) = fa.run(ctx).runSyncUnsafe() val expected = messages.filter(_.level >= Level.Debug).map(m => m.copy(context = m.context ++ ctx)) attempt shouldBe Left(error) written shouldBe expected } } }
Example 15
Source File: ExampleApp.scala From caliban with Apache License 2.0 | 5 votes |
package caliban.tapir import caliban.interop.tapir._ import caliban.tapir.Endpoints._ import caliban.{ GraphQL, Http4sAdapter } import cats.data.Kleisli import cats.effect.Blocker import org.http4s.StaticFile import org.http4s.implicits._ import org.http4s.server.Router import org.http4s.server.blaze.BlazeServerBuilder import org.http4s.server.middleware.CORS import sttp.tapir.server.ServerEndpoint import zio._ import zio.blocking.Blocking import zio.interop.catz._ import zio.interop.catz.implicits._ import scala.concurrent.ExecutionContext object ExampleApp extends CatsApp { // approach 1: using `Endpoint` and providing the logic val graphql: GraphQL[Any] = addBook.toGraphQL((bookAddLogic _).tupled) |+| deleteBook.toGraphQL((bookDeleteLogic _).tupled) |+| booksListing.toGraphQL((bookListingLogic _).tupled) // approach 2: using the `ServerEndpoint` where logic is already provided type MyIO[+A] = IO[String, A] val addBookEndpoint: ServerEndpoint[(Book, String), String, Unit, Nothing, MyIO] = addBook.serverLogic[MyIO] { case (book, token) => bookAddLogic(book, token).either } val deleteBookEndpoint: ServerEndpoint[(String, String), String, Unit, Nothing, MyIO] = deleteBook.serverLogic[MyIO] { case (title, token) => bookDeleteLogic(title, token).either } val booksListingEndpoint: ServerEndpoint[(Option[Int], Option[Int]), Nothing, List[Book], Nothing, UIO] = booksListing.serverLogic[UIO] { case (year, limit) => bookListingLogic(year, limit).map(Right(_)) } val graphql2: GraphQL[Any] = addBookEndpoint.toGraphQL |+| deleteBookEndpoint.toGraphQL |+| booksListingEndpoint.toGraphQL override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] = (for { blocker <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext) interpreter <- graphql.interpreter _ <- BlazeServerBuilder[Task](ExecutionContext.global) .bindHttp(8088, "localhost") .withHttpApp( Router[Task]( "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)), "/graphiql" -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None)) ).orNotFound ) .resource .toManaged .useForever } yield ()).exitCode }
Example 16
Source File: FederatedApp.scala From caliban with Apache License 2.0 | 5 votes |
package caliban.federation import caliban.Http4sAdapter import caliban.federation.FederationData.characters.sampleCharacters import caliban.federation.FederationData.episodes.sampleEpisodes import cats.data.Kleisli import cats.effect.Blocker import org.http4s.StaticFile import org.http4s.implicits._ import org.http4s.server.Router import org.http4s.server.blaze.BlazeServerBuilder import org.http4s.server.middleware.CORS import zio._ import zio.blocking.Blocking import zio.interop.catz._ import scala.concurrent.ExecutionContext object FederatedApp extends CatsApp { type ExampleTask[A] = RIO[ZEnv, A] val service1 = CharacterService .make(sampleCharacters) .memoize .use(layer => for { blocker <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext) interpreter <- FederatedApi.Characters.api.interpreter.map(_.provideCustomLayer(layer)) _ <- BlazeServerBuilder[ExampleTask](ExecutionContext.global) .bindHttp(8089, "localhost") .withHttpApp( Router[ExampleTask]( "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)), "/graphiql" -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None)) ).orNotFound ) .resource .toManaged .useForever } yield () ) val service2 = EpisodeService .make(sampleEpisodes) .memoize .use(layer => for { blocker <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext) interpreter <- FederatedApi.Episodes.api.interpreter.map(_.provideCustomLayer(layer)) _ <- BlazeServerBuilder[ExampleTask](ExecutionContext.global) .bindHttp(8088, "localhost") .withHttpApp( Router[ExampleTask]( "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)), "/graphiql" -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None)) ).orNotFound ) .resource .toManaged .useForever } yield () ) override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] = (service1 race service2).exitCode }
Example 17
Source File: CartRoutesSpec.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes.secured import cats.data.Kleisli import cats.effect._ import java.util.UUID import org.http4s._ import org.http4s.Method._ import org.http4s.client.dsl.io._ import org.http4s.server.AuthMiddleware import shop.algebras.ShoppingCart import shop.arbitraries._ import shop.domain.auth._ import shop.domain.cart._ import shop.domain.item._ import shop.http.auth.users._ import shop.http.json._ import squants.market.USD import suite._ class CartRoutesSpec extends HttpTestSuite { val authUser = CommonUser(User(UserId(UUID.randomUUID), UserName("user"))) val authMiddleware: AuthMiddleware[IO, CommonUser] = AuthMiddleware(Kleisli.pure(authUser)) def dataCart(cartTotal: CartTotal) = new TestShoppingCart { override def get(userId: UserId): IO[CartTotal] = IO.pure(cartTotal) } test("GET shopping cart [OK]") { forAll { (ct: CartTotal) => IOAssertion { GET(Uri.uri("/cart")).flatMap { req => val routes = new CartRoutes[IO](dataCart(ct)).routes(authMiddleware) assertHttp(routes, req)(Status.Ok, ct) } } } } test("POST add item to shopping cart [OK]") { forAll { (c: Cart) => IOAssertion { POST(c, Uri.uri("/cart")).flatMap { req => val routes = new CartRoutes[IO](new TestShoppingCart).routes(authMiddleware) assertHttpStatus(routes, req)(Status.Created) } } } } } protected class TestShoppingCart extends ShoppingCart[IO] { def add(userId: UserId, itemId: ItemId, quantity: Quantity): IO[Unit] = IO.unit def get(userId: UserId): IO[CartTotal] = IO.pure(CartTotal(List.empty, USD(0))) def delete(userId: UserId): IO[Unit] = IO.unit def removeItem(userId: UserId, itemId: ItemId): IO[Unit] = IO.unit def update(userId: UserId, cart: Cart): IO[Unit] = IO.unit }
Example 18
Source File: KleisliExamples.scala From scala_typeclassopedia with Creative Commons Attribution Share Alike 4.0 International | 5 votes |
package examples import cats.data.Kleisli import cats.implicits._ object KleisliExamples extends App { val twice: Int => Int = _ * 2 val countCats: Int => String = x => if(x ==1) "1 cat" else s"$x cats" val twiceAsManyCats = twice andThen countCats println(twiceAsManyCats(1)) val parse: String => Option[Int] = s => try { Some(s.toInt) } catch { case _: NumberFormatException => None } val reciprocal: Int => Option[Double] = i => if (i != 0) Some(1.0 / i) else None val parseKleisli = Kleisli(parse) val reciprocalKleisli = Kleisli(reciprocal) val parseAndReciprocal = reciprocalKleisli.compose(parseKleisli) val parseAndReciprocal2 = parseKleisli.andThen(reciprocalKleisli) println(parseAndReciprocal("10")) println(parseAndReciprocal2("10")) }
Example 19
Source File: Trees.scala From github with MIT License | 5 votes |
package io.chrisdavenport.github.endpoints.gitdata import cats.implicits._ import cats.data.Kleisli import cats.effect._ import org.http4s._ import org.http4s.client._ import org.http4s.implicits._ import io.chrisdavenport.github.Auth import io.chrisdavenport.github.internals.GithubMedia._ import io.chrisdavenport.github.internals.RequestConstructor import io.chrisdavenport.github.data.GitData._ object Trees { def createTree[F[_]: Sync]( owner: String, repo: String, createTree: CreateTree, auth: Auth ): Kleisli[F, Client[F], Tree] = RequestConstructor.runRequestWithBody[F, CreateTree, Tree]( auth.some, Method.POST, uri"repos" / owner / repo / "git" / "trees", createTree ) }
Example 20
Source File: Commits.scala From github with MIT License | 5 votes |
package io.chrisdavenport.github.endpoints.gitdata import cats.implicits._ import cats.data.Kleisli import cats.effect._ import org.http4s._ import org.http4s.client._ import org.http4s.implicits._ import io.chrisdavenport.github.Auth import io.chrisdavenport.github.internals.GithubMedia._ import io.chrisdavenport.github.internals.RequestConstructor import io.chrisdavenport.github.data.GitData._ def createCommit[F[_]: Sync]( owner: String, repo: String, createCommit: CreateCommit, auth: Auth ): Kleisli[F, Client[F], GitCommit] = RequestConstructor.runRequestWithBody[F, CreateCommit, GitCommit]( auth.some, Method.POST, uri"repos" / owner / repo / "git" / "commits", createCommit ) }
Example 21
Source File: Blobs.scala From github with MIT License | 5 votes |
package io.chrisdavenport.github.endpoints.gitdata import cats.implicits._ import cats.data.Kleisli import cats.effect._ import org.http4s._ import org.http4s.client._ import org.http4s.implicits._ import io.chrisdavenport.github.Auth import io.chrisdavenport.github.internals.GithubMedia._ import io.chrisdavenport.github.internals.RequestConstructor import io.chrisdavenport.github.data.GitData._ object Blobs { def createBlob[F[_]: Sync]( owner: String, repo: String, createBlob: CreateBlob, auth: Auth ): Kleisli[F, Client[F], NewBlob] = RequestConstructor.runRequestWithBody[F, CreateBlob, NewBlob]( auth.some, Method.POST, uri"repos" / owner / repo / "git" / "blobs", createBlob ) }
Example 22
Source File: Tags.scala From github with MIT License | 5 votes |
package io.chrisdavenport.github.endpoints.gitdata import cats.implicits._ import cats.data.Kleisli import cats.effect._ import org.http4s._ import org.http4s.client._ import org.http4s.implicits._ import io.chrisdavenport.github.Auth import io.chrisdavenport.github.internals.GithubMedia._ import io.chrisdavenport.github.internals.RequestConstructor import io.chrisdavenport.github.data.GitData._ object Tags { def createTagFull[F[_]: Sync]( owner: String, repo: String, createTag: CreateTag, auth: Auth ): Kleisli[F, Client[F], (GitTag, GitReference)] = for { tag <- Tags.createTag[F]( owner, repo, createTag, auth ) ref <- References.createReference[F]( owner, repo, CreateReference( "refs/tags/" |+| createTag.tag, createTag.objectSha ), auth ) } yield (tag, ref) }
Example 23
Source File: PaginatedJsonFiles.scala From github with MIT License | 5 votes |
package io.chrisdavenport.github.endpoints.utils import cats.data.Kleisli import cats.effect._ import io.circe.Json import org.http4s._ import org.http4s.dsl.io._ import org.http4s.implicits._ import org.http4s.circe._ trait PaginatedJsonFiles extends JsonFiles with Paginate { def baseUri: Uri def pageFileName: Int => String def extractRequest: PartialFunction[Request[IO], Request[IO]] def paginatedEndpoint(numPages: Int): Kleisli[IO, Request[IO], Response[IO]] = HttpRoutes.of[IO] { extractRequest.andThen { request => val page: Int = getCurrentPage(request) (for { jsonContent <- pages(numPages).get(page) linkHeader <- links(numPages).get(page) } yield Ok(jsonContent).map(_.putHeaders(linkHeader))) .getOrElse { NotFound(s"Page does not exist: $page") } } }.orNotFound private def pages(numPages: Int): Map[Int, Json] = getPageContents(numPages, pageFileName) private def links(numPages: Int): Map[Int, Header] = paginate(baseUri, numPages) }
Example 24
Source File: Http4sServerTests.scala From tapir with Apache License 2.0 | 5 votes |
package sttp.tapir.server.http4s import cats.data.{Kleisli, NonEmptyList} import cats.effect._ import cats.implicits._ import org.http4s.server.Router import org.http4s.server.blaze.BlazeServerBuilder import org.http4s.syntax.kleisli._ import org.http4s.{EntityBody, HttpRoutes, Request, Response} import sttp.tapir.server.tests.ServerTests import sttp.tapir.Endpoint import sttp.tapir._ import sttp.client._ import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint} import sttp.tapir.tests.{Port, PortCounter} import scala.concurrent.ExecutionContext import scala.reflect.ClassTag class Http4sServerTests extends ServerTests[IO, EntityBody[IO], HttpRoutes[IO]] { implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global implicit val contextShift: ContextShift[IO] = IO.contextShift(ec) implicit val timer: Timer[IO] = IO.timer(ec) override def pureResult[T](t: T): IO[T] = IO.pure(t) override def suspendResult[T](t: => T): IO[T] = IO.apply(t) override def route[I, E, O]( e: ServerEndpoint[I, E, O, EntityBody[IO], IO], decodeFailureHandler: Option[DecodeFailureHandler] = None ): HttpRoutes[IO] = { implicit val serverOptions: Http4sServerOptions[IO] = Http4sServerOptions .default[IO] .copy( decodeFailureHandler = decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler) ) e.toRoutes } override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, EntityBody[IO]], fn: I => IO[O])(implicit eClassTag: ClassTag[E] ): HttpRoutes[IO] = { e.toRouteRecoverErrors(fn) } override def server(routes: NonEmptyList[HttpRoutes[IO]], port: Port): Resource[IO, Unit] = { val service: Kleisli[IO, Request[IO], Response[IO]] = routes.reduceK.orNotFound BlazeServerBuilder[IO](ExecutionContext.global) .bindHttp(port, "localhost") .withHttpApp(service) .resource .void } override lazy val portCounter: PortCounter = new PortCounter(56000) if (testNameFilter.isEmpty) { test("should work with a router and routes in a context") { val e = endpoint.get.in("test" / "router").out(stringBody).serverLogic(_ => IO.pure("ok".asRight[Unit])) val routes = e.toRoutes val port = portCounter.next() BlazeServerBuilder[IO](ExecutionContext.global) .bindHttp(port, "localhost") .withHttpApp(Router("/api" -> routes).orNotFound) .resource .use { _ => basicRequest.get(uri"http://localhost:$port/api/test/router").send().map(_.body shouldBe Right("ok")) } .unsafeRunSync() } } }
Example 25
Source File: CorrelationIdMiddleware.scala From scala-server-toolkit with MIT License | 5 votes |
package com.avast.sst.http4s.server.middleware import java.util.UUID import cats.data.{Kleisli, OptionT} import cats.effect.Sync import cats.syntax.functor._ import com.avast.sst.http4s.server.middleware.CorrelationIdMiddleware.CorrelationId import io.chrisdavenport.vault.Key import org.http4s.util.CaseInsensitiveString import org.http4s.{Header, HttpRoutes, Request, Response} import org.slf4j.LoggerFactory class CorrelationIdMiddleware[F[_]: Sync]( correlationIdHeaderName: CaseInsensitiveString, attributeKey: Key[CorrelationId], generator: () => String ) { private val logger = LoggerFactory.getLogger(this.getClass) private val F = Sync[F] def wrap(routes: HttpRoutes[F]): HttpRoutes[F] = Kleisli[OptionT[F, *], Request[F], Response[F]] { request => request.headers.get(correlationIdHeaderName) match { case Some(header) => val requestWithAttribute = request.withAttribute(attributeKey, CorrelationId(header.value)) routes(requestWithAttribute).map(r => r.withHeaders(r.headers.put(header))) case None => for { newCorrelationId <- OptionT.liftF(F.delay(generator())) _ <- log(newCorrelationId) requestWithAttribute = request.withAttribute(attributeKey, CorrelationId(newCorrelationId)) response <- routes(requestWithAttribute) } yield response.withHeaders(response.headers.put(Header(correlationIdHeaderName.value, newCorrelationId))) } } def retrieveCorrelationId(request: Request[F]): Option[CorrelationId] = request.attributes.lookup(attributeKey) private def log(newCorrelationId: String) = { OptionT.liftF { F.delay { if (logger.isDebugEnabled()) { logger.debug(s"Generated new correlation ID: $newCorrelationId") } } } } } object CorrelationIdMiddleware { final case class CorrelationId(value: String) extends AnyVal @SuppressWarnings(Array("scalafix:Disable.toString")) def default[F[_]: Sync]: F[CorrelationIdMiddleware[F]] = { Key.newKey[F, CorrelationId].map { attributeKey => new CorrelationIdMiddleware(CaseInsensitiveString("Correlation-ID"), attributeKey, () => UUID.randomUUID().toString) } } }
Example 26
Source File: Kleislis.scala From freestyle with Apache License 2.0 | 5 votes |
package freestyle.free.cache.redis.rediscala import cats.data.Kleisli import scala.concurrent.Future import _root_.redis.{ Cursor, ByteStringDeserializer => Deserializer, ByteStringSerializer => Serializer } import _root_.redis.commands.{ Keys => KeyCommands, Server => ServerCommands, Strings => StringCommands } private[rediscala] trait StringCommandsCont { def append[Key, Value](key: Key, value: Value)( implicit format: Format[Key], writer: Serializer[Value] ): Ops[Future, Long] = Kleisli((client: StringCommands) => client.append(format(key), value)) def get[Key, Value](key: Key)( implicit format: Format[Key], writer: Deserializer[Value] ): Ops[Future, Option[Value]] = Kleisli((client: StringCommands) => client.get[Value](format(key))) def set[Key: Format, Value: Serializer](key: Key, value: Value): Ops[Future, Boolean] = Kleisli((client: StringCommands) => client.set(key, value)) def mset[Key, Value: Serializer](keyValues: Map[Key, Value])( implicit format: Format[Key]): Ops[Future, Boolean] = { val b = keyValues.map { case (k, v) => (format(k), v) } Kleisli((client: StringCommands) => client.mset(b)) } def setnx[Key: Format, Value: Serializer](key: Key, value: Value): Ops[Future, Boolean] = Kleisli((client: StringCommands) => client.setnx(key, value)) def setxx[Key: Format, Value: Serializer](key: Key, value: Value): Ops[Future, Boolean] = Kleisli((client: StringCommands) => client.set(key, value, XX = true)) } private[rediscala] trait KeyCommandsCont { def del[Key](keys: List[Key])(implicit format: Format[Key]): Ops[Future, Long] = Kleisli((client: KeyCommands) => client.del(keys.map(format): _*)) def exists[Key](key: Key)(implicit format: Format[Key]): Ops[Future, Boolean] = Kleisli((client: KeyCommands) => client.exists(format(key))) def keys[Key]: Ops[Future, Seq[String]] = Kleisli((client: KeyCommands) => client.keys("*")) def scan[Key]: Ops[Future, Cursor[Seq[String]]] = Kleisli((client: KeyCommands) => client.scan(0, Option(1), None)) } private[rediscala] trait ServerCommandsCont { def flushDB: Ops[Future, Boolean] = Kleisli((client: ServerCommands) => client.flushdb) } private[rediscala] object RediscalaCont extends StringCommandsCont with KeyCommandsCont with ServerCommandsCont
Example 27
Source File: PeerSelector.scala From iotchain with MIT License | 5 votes |
package jbok.core.peer import cats.data.Kleisli import cats.effect.Sync import cats.implicits._ import jbok.common.math.N import jbok.core.messages.SignedTransactions import jbok.core.models.Block import scala.util.Random object PeerSelector { type PeerSelector[F[_]] = Kleisli[F, List[Peer[F]], List[Peer[F]]] def apply[F[_]](run: List[Peer[F]] => F[List[Peer[F]]]): PeerSelector[F] = Kleisli(run) def all[F[_]: Sync]: PeerSelector[F] = PeerSelector(Sync[F].pure) def except[F[_]: Sync](peer: Peer[F]): PeerSelector[F] = PeerSelector(_.filterNot(_ == peer).pure[F]) def one[F[_]: Sync](peer: Peer[F]): PeerSelector[F] = PeerSelector(_ => Sync[F].pure(List(peer))) def many[F[_]: Sync](list: List[Peer[F]]): PeerSelector[F] = PeerSelector(_ => Sync[F].pure(list)) def withoutBlock[F[_]: Sync](block: Block): PeerSelector[F] = PeerSelector { peers => peers .traverse[F, Option[Peer[F]]] { peer => peer.hasBlock(block.header.hash).map { case true => None case false => Some(peer) } } .map(_.flatten) } def withoutTxs[F[_]: Sync](stxs: SignedTransactions): PeerSelector[F] = PeerSelector { peers => peers .traverse[F, Option[Peer[F]]] { peer => peer.hasTxs(stxs).map { case true => None case false => Some(peer) } } .map(_.flatten) } def bestPeer[F[_]: Sync](minTD: N): PeerSelector[F] = PeerSelector { peers => peers .traverse(p => p.status.get.map(_.td).map(td => td -> p)) .map(_.filter(_._1 > minTD).sortBy(-_._1).map(_._2)) } def randomSelectSqrt[F[_]: Sync](min: Int): PeerSelector[F] = PeerSelector { peers => val numberOfPeersToSend = math.max(math.sqrt(peers.size).toInt, min) Sync[F].pure(Random.shuffle(peers).take(numberOfPeersToSend)) } }
Example 28
Source File: Server.scala From zio-metrics with Apache License 2.0 | 5 votes |
package zio.metrics.dropwizard import scala.util.Properties.envOrNone import cats.data.Kleisli import org.http4s.server.blaze._ import org.http4s.{ Request, Response } import zio.{ RIO, ZIO } import zio.system.System import zio.clock.Clock import zio.console.Console import zio.random.Random import zio.blocking.Blocking import zio.interop.catz._ import io.circe.Json import org.http4s.circe._ import org.http4s.dsl.impl.Root import org.http4s.dsl.io._ import org.http4s.{ HttpRoutes, Response } import zio.RIO import zio.interop.catz._ import zio.metrics.dropwizard.typeclasses._ import zio.metrics.dropwizard.DropwizardExtractor._ import cats.instances.list._ import com.codahale.metrics.MetricRegistry object Server { val port: Int = envOrNone("HTTP_PORT").fold(9090)(_.toInt) type HttpEnvironment = Clock with Console with System with Random with Blocking type HttpTask[A] = RIO[HttpEnvironment, A] type KleisliApp = Kleisli[HttpTask, Request[HttpTask], Response[HttpTask]] //type HttpApp[R <: Registry] = R => KleisliApp def builder[Ctx]: KleisliApp => HttpTask[Unit] = (app: KleisliApp) => ZIO .runtime[HttpEnvironment] .flatMap { implicit rts => BlazeServerBuilder[HttpTask] .bindHttp(port) .withHttpApp(app) .serve .compile .drain } def serveMetrics: MetricRegistry => HttpRoutes[Server.HttpTask] = registry => HttpRoutes.of[Server.HttpTask] { case GET -> Root / filter => { println(s"filter: $filter") val optFilter = if (filter == "ALL") None else Some(filter) RegistryPrinter .report[List, Json](registry, optFilter)( (k: String, v: Json) => Json.obj((k, v)) ) .map(m => Response[Server.HttpTask](Ok).withEntity(m)) } } }
Example 29
Source File: modelDecoding.scala From seals with Apache License 2.0 | 5 votes |
package dev.tauri.seals package core import cats.{ Monad, Eval } import cats.data.Kleisli import cats.implicits._ final object ModelDecoding { sealed abstract class Proc[F[_], S] extends Monad[F] { def get: F[S] def set(s: S): F[Unit] def raise[A](err: String): F[A] def force[A](proc: F[A], s: S): Either[String, A] def forceAS[A](proc: F[A], s: S): (S, Either[String, A]) } sealed abstract class Api { type F[S, A] implicit def procInstance[S]: Proc[F[S, ?], S] } val Api: Api = Impl type Error = String final case class DecodingError(err: Error) extends Exception(sh"error while decoding model: ${err}") private final object Impl extends Api { override type F[S, A] = Kleisli[Eval, LocRef[S], A] implicit override def procInstance[S]: Proc[F[S, ?], S] = { new Proc[F[S, ?], S] { override def pure[A](x: A) = Kleisli.pure(x) override def flatMap[A, B](fa: Kleisli[Eval, LocRef[S], A])( f: A => Kleisli[Eval, LocRef[S], B] ) = fa.flatMap(f) override def tailRecM[A, B](a: A)(f: A => F[S, Either[A, B]]): F[S, B] = Kleisli.catsDataMonadForKleisli[Eval, LocRef[S]].tailRecM(a)(f) override def raise[A](err: String) = Kleisli { _ => Eval.always(throw new DecodingError(err)) } override def get = Kleisli { ref => ref.get } override def set(s: S) = Kleisli { ref => ref.set(s) } override def force[A](proc: F[S, A], s: S): Either[String, A] = { try Right(proc.run(new LocRef[S](s)).value) catch { case DecodingError(err) => Left(err) } } override def forceAS[A](proc: F[S, A], s: S): (S, Either[String, A]) = { val ref = new LocRef[S](s) val res = try { Right(proc.run(ref).value) } catch { case DecodingError(err) => Left(err) } (ref.get.value, res) } } } } private final class LocRef[A](private[this] var value: A) { def get: Eval[A] = Eval.always(this.value) def set(a: A): Eval[Unit] = Eval.always(this.value = a) } }
Example 30
Source File: SecuredRequestHandler.scala From tsec with MIT License | 5 votes |
package tsec.authentication import cats.ApplicativeError import cats.MonadError import cats.data.{Kleisli, OptionT} import cats.syntax.all._ import org.http4s._ import org.log4s._ import tsec.authorization._ sealed abstract class SecuredRequestHandler[F[_], Identity, User, Auth]( val authenticator: Authenticator[F, Identity, User, Auth] )(implicit F: MonadError[F, Throwable], ME: MonadError[Kleisli[OptionT[F, ?], Request[F], ?], Throwable]) { private[this] val cachedUnauthorized: Response[F] = Response[F](Status.Unauthorized) private[this] val defaultNotAuthenticated: Request[F] => F[Response[F]] = _ => F.pure(cachedUnauthorized) private[tsec] def default[F[_], Identity, User, Auth]( authenticator: Authenticator[F, Identity, User, Auth] )(implicit F: MonadError[F, Throwable]): SecuredRequestHandler[F, Identity, User, Auth] = new SecuredRequestHandler[F, Identity, User, Auth](authenticator) {} }
Example 31
Source File: KamonSupport.scala From kamon-http4s with Apache License 2.0 | 5 votes |
package kamon.http4s package middleware.server import cats.data.{Kleisli, OptionT} import cats.effect.{Resource, Sync} import cats.implicits._ import kamon.Kamon import kamon.context.Storage import kamon.instrumentation.http.HttpServerInstrumentation.RequestHandler import kamon.instrumentation.http.HttpServerInstrumentation import org.http4s.{HttpRoutes, Request, Response} object KamonSupport { def apply[F[_]: Sync](service: HttpRoutes[F], interface: String, port: Int): HttpRoutes[F] = { val httpServerConfig = Kamon.config().getConfig("kamon.instrumentation.http4s.server") val instrumentation = HttpServerInstrumentation.from(httpServerConfig, "http4s.server", interface, port) Kleisli(kamonService[F](service, instrumentation)(_)) } private def kamonService[F[_]](service: HttpRoutes[F], instrumentation: HttpServerInstrumentation) (request: Request[F]) (implicit F: Sync[F]): OptionT[F, Response[F]] = OptionT { getHandler(instrumentation)(request).use { handler => for { resOrUnhandled <- service(request).value.attempt respWithContext <- kamonServiceHandler(handler, resOrUnhandled, instrumentation.settings) } yield respWithContext } } private def processRequest[F[_]](requestHandler: RequestHandler)(implicit F: Sync[F]): Resource[F, RequestHandler] = Resource.make(F.delay(requestHandler.requestReceived()))(h => F.delay(h.responseSent())) private def withContext[F[_]](requestHandler: RequestHandler)(implicit F: Sync[F]): Resource[F, Storage.Scope] = Resource.make(F.delay(Kamon.storeContext(requestHandler.context)))( scope => F.delay(scope.close())) private def getHandler[F[_]](instrumentation: HttpServerInstrumentation)(request: Request[F])(implicit F: Sync[F]): Resource[F, RequestHandler] = for { handler <- Resource.liftF(F.delay(instrumentation.createHandler(buildRequestMessage(request)))) _ <- processRequest(handler) _ <- withContext(handler) } yield handler private def kamonServiceHandler[F[_]](requestHandler: RequestHandler, e: Either[Throwable, Option[Response[F]]], settings: HttpServerInstrumentation.Settings) (implicit F: Sync[F]): F[Option[Response[F]]] = e match { case Left(e) => F.delay { requestHandler.span.fail(e.getMessage) Some(requestHandler.buildResponse(errorResponseBuilder, requestHandler.context)) } *> F.raiseError(e) case Right(None) => F.delay { requestHandler.span.name(settings.unhandledOperationName) val response: Response[F] = requestHandler.buildResponse[Response[F]]( notFoundResponseBuilder, requestHandler.context ) Some(response) } case Right(Some(response)) => F.delay { val a = requestHandler.buildResponse(getResponseBuilder(response), requestHandler.context) Some(a) } } }
Example 32
Source File: StaticResources.scala From temperature-machine with Apache License 2.0 | 5 votes |
package bad.robot.temperature.server import cats.data.Kleisli import cats.effect.IO import org.http4s.CacheDirective.{`max-age`, `public`} import org.http4s.HttpService import org.http4s.Status.Successful import org.http4s.headers.`Cache-Control` import org.http4s.server.staticcontent._ import scala.concurrent.duration._ object StaticResources { def apply(): HttpService[IO] = Kleisli.apply(request => { val resources = resourceService[IO](ResourceService.Config(basePath = "")) val response = if (request.uri.path.endsWith("/")) resources(request.withUri(request.uri.withPath(request.uri.path + "index.html"))) else resources(request) response.map { case Successful(resp) => resp.putHeaders(`Cache-Control`(`public`, `max-age`(Duration(365, DAYS)))) case resp => resp } }) }
Example 33
Source File: HttpUploadTest.scala From temperature-machine with Apache License 2.0 | 5 votes |
package bad.robot.temperature.client import java.net.InetAddress import bad.robot.temperature.rrd.{Host, Seconds} import bad.robot.temperature.{IpAddress, Measurement, SensorReading, Temperature, UnexpectedError, jsonEncoder} import cats.data.Kleisli import cats.effect.IO import org.http4s.Method.PUT import org.http4s.client.{DisposableResponse, Client => Http4sClient} import org.http4s.dsl.io._ import org.http4s.{EntityDecoder, Request} import org.specs2.matcher.DisjunctionMatchers._ import org.specs2.mutable.Specification class HttpUploadTest extends Specification { "Ip address pre-check" >> { IpAddress.currentIpAddress.size must be_>(0) } "Encode a measurement for the wire" >> { def encodeMessageViaEntityEncoder(measurement: Measurement): String = { implicit val encoder = jsonEncoder[Measurement] val request: IO[Request[IO]] = Request(PUT).withBody(measurement) EntityDecoder.decodeString(request.unsafeRunSync()).unsafeRunSync() } val measurement = Measurement(Host("example"), Seconds(1509221361), List(SensorReading("28-0115910f5eff", Temperature(19.75)))) encodeMessageViaEntityEncoder(measurement) must_== """|{ | "host" : { | "name" : "example", | "utcOffset" : null, | "timezone" : null | }, | "seconds" : 1509221361, | "sensors" : [ | { | "name" : "28-0115910f5eff", | "temperature" : { | "celsius" : 19.75 | } | } | ] |}""".stripMargin } "Error response from server" >> { val measurement = Measurement(Host("example"), Seconds(1509221361), List(SensorReading("28-0115910f5eff", Temperature(19.75)))) val error = InternalServerError("I'm an error").map(DisposableResponse(_, IO.pure(()))) val willError: Kleisli[IO, Request[IO], DisposableResponse[IO]] = new Kleisli[IO, Request[IO], DisposableResponse[IO]](_ => error) val client = Http4sClient[IO](willError, IO.pure(())) val upload = HttpUpload(InetAddress.getLoopbackAddress, client) val value = upload.write(measurement) value must be_-\/.like { case UnexpectedError("""Failed to PUT temperature data to http://127.0.0.1:11900/temperature, response was 500 Internal Server Error: Right(I'm an error)""") => ok } } "Request has headers" >> { val measurement = Measurement(Host("example"), Seconds(1509221361), List(SensorReading("28-0115910f5eff", Temperature(19.75)))) var headers = List[String]() val client = Http4sClient[IO](new Kleisli[IO, Request[IO], DisposableResponse[IO]](request => { headers = request.headers.map(_.name.toString()).toList Ok().map(DisposableResponse(_, IO.pure(()))) }), IO.pure(())) val upload = HttpUpload(InetAddress.getLoopbackAddress, client) upload.write(measurement) headers must_== List( "Content-Type", "X-Forwarded-For", "Content-Length" ) } }
Example 34
Source File: RestTemplateInterpreter.scala From hammock with MIT License | 5 votes |
package hammock package resttemplate import java.net.URI import cats._ import cats.implicits._ import cats.data.Kleisli import cats.effect._ import org.springframework.http._ import org.springframework.util.LinkedMultiValueMap import org.springframework.web.client.RestTemplate import scala.collection.JavaConverters._ object RestTemplateInterpreter { def apply[F[_]](implicit F: InterpTrans[F]): InterpTrans[F] = F implicit def instance[F[_]: Sync]( implicit client: RestTemplate = new RestTemplate() ): InterpTrans[F] = new InterpTrans[F] { override def trans: HttpF ~> F = transK andThen λ[Kleisli[F, RestTemplate, *] ~> F](_.run(client)) } def transK[F[_]: Sync]: HttpF ~> Kleisli[F, RestTemplate, *] = { λ[HttpF ~> Kleisli[F, RestTemplate, *]] { case reqF @ (Get(_) | Delete(_) | Head(_) | Options(_) | Trace(_) | Post(_) | Put(_) | Patch(_)) => Kleisli { implicit client => for { req <- mapRequest[F](reqF) res <- execute[F](req) hammockResponse <- mapResponse[F](res) } yield hammockResponse } } } def mapRequest[F[_]: Sync](reqF: HttpF[HttpResponse]): F[RequestEntity[String]] = { def httpEntity: HttpEntity[String] = new HttpEntity( reqF.req.entity.map(_.cata[String](_.body, _.body.map(_.toChar).mkString, Function.const(""))).orNull, new LinkedMultiValueMap[String, String](reqF.req.headers.mapValues(List(_).asJava).asJava) ) def requestEntity(httpMethod: HttpMethod): RequestEntity[String] = new RequestEntity[String](httpEntity.getBody, httpEntity.getHeaders, httpMethod, new URI(reqF.req.uri.show)) (reqF match { case Get(_) => requestEntity(HttpMethod.GET) case Delete(_) => requestEntity(HttpMethod.DELETE) case Head(_) => requestEntity(HttpMethod.HEAD) case Options(_) => requestEntity(HttpMethod.OPTIONS) case Post(_) => requestEntity(HttpMethod.POST) case Put(_) => requestEntity(HttpMethod.PUT) case Trace(_) => requestEntity(HttpMethod.TRACE) case Patch(_) => requestEntity(HttpMethod.PATCH) }).pure[F] } def execute[F[_]: Sync](rtRequest: RequestEntity[String])(implicit client: RestTemplate): F[ResponseEntity[String]] = Sync[F].delay { client.exchange(rtRequest, classOf[String]) } def mapResponse[F[_]: Applicative](response: ResponseEntity[String]): F[HttpResponse] = { def createEntity(response: ResponseEntity[String]): Entity = response.getHeaders.getContentType match { case MediaType.APPLICATION_OCTET_STREAM => Entity.ByteArrayEntity(response.getBody.getBytes) case _ => Entity.StringEntity(response.getBody) } HttpResponse( Status.Statuses(response.getStatusCodeValue), response.getHeaders.toSingleValueMap.asScala.toMap, createEntity(response) ).pure[F] } }
Example 35
Source File: AsyncHttpClientInterpreter.scala From hammock with MIT License | 5 votes |
package hammock package asynchttpclient import cats._ import cats.implicits._ import cats.data.Kleisli import cats.effect._ import org.asynchttpclient._ import java.util.{concurrent => jc} import scala.util._ import scala.collection.JavaConverters._ object AsyncHttpClientInterpreter { def apply[F[_]](implicit F: InterpTrans[F]): InterpTrans[F] = F implicit def instance[F[_]: Async]( implicit client: AsyncHttpClient = new DefaultAsyncHttpClient() ): InterpTrans[F] = new InterpTrans[F] { override def trans: HttpF ~> F = transK andThen λ[Kleisli[F, AsyncHttpClient, *] ~> F](_.run(client)) } def transK[F[_]: Async]: HttpF ~> Kleisli[F, AsyncHttpClient, *] = { def toF[A](future: jc.Future[A]): F[A] = Async[F].async(_(Try(future.get) match { case Failure(err) => Left(err) case Success(a) => Right(a) })) λ[HttpF ~> Kleisli[F, AsyncHttpClient, *]] { case reqF @ (Get(_) | Options(_) | Delete(_) | Head(_) | Options(_) | Trace(_) | Post(_) | Put(_) | Patch(_)) => Kleisli { implicit client => for { req <- mapRequest[F](reqF) ahcResponse <- toF(req.execute()) hammockResponse <- mapResponse[F](ahcResponse) } yield hammockResponse } } } def mapRequest[F[_]: Async](reqF: HttpF[HttpResponse])(implicit client: AsyncHttpClient): F[BoundRequestBuilder] = { def putHeaders(req: BoundRequestBuilder, headers: Map[String, String]): F[Unit] = Async[F].delay { req.setSingleHeaders(headers.map(kv => kv._1.asInstanceOf[CharSequence] -> kv._2).asJava) } *> ().pure[F] def getBuilder(reqF: HttpF[HttpResponse]): BoundRequestBuilder = reqF match { case Get(_) => client.prepareGet(reqF.req.uri.show) case Delete(_) => client.prepareDelete(reqF.req.uri.show) case Head(_) => client.prepareHead(reqF.req.uri.show) case Options(_) => client.prepareOptions(reqF.req.uri.show) case Post(_) => client.preparePost(reqF.req.uri.show) case Put(_) => client.preparePut(reqF.req.uri.show) case Trace(_) => client.prepareTrace(reqF.req.uri.show) case Patch(_) => client.preparePatch(reqF.req.uri.show) } for { req <- getBuilder(reqF).pure[F] _ <- putHeaders(req, reqF.req.headers) _ = reqF.req.entity .foreach(_.cata(str => req.setBody(str.content), bytes => req.setBody(bytes.content), Function.const(()))) } yield req } def mapResponse[F[_]: Applicative](ahcResponse: Response): F[HttpResponse] = { def createEntity(r: Response): Entity = r.getContentType match { case AsyncHttpClientContentType.`application/octet-stream` => Entity.ByteArrayEntity(r.getResponseBodyAsBytes) case _ => Entity.StringEntity(r.getResponseBody) } HttpResponse( Status.Statuses(ahcResponse.getStatusCode), ahcResponse.getHeaders.names.asScala.map(name => (name, ahcResponse.getHeaders.get(name))).toMap, createEntity(ahcResponse) ).pure[F] } }
Example 36
Source File: algebras.scala From freestyle with Apache License 2.0 | 5 votes |
package freestyle.tagless import cats.Id import cats.data.Kleisli import freestyle.tagless.logging.LoggingM import scala.concurrent.Future object algebras { @tagless(true) trait NonLogging { def x: FS[Int] } implicit def nonLoggingFutureHandler: NonLogging.Handler[Future] = new NonLogging.Handler[Future] { def x: Future[Int] = Future.successful(1) } type TestAlgebra[A] = Kleisli[Id, String, A] implicit def nonLoggingTestAlgebraHandler: NonLogging.Handler[TestAlgebra] = new NonLogging.Handler[TestAlgebra] { def x: TestAlgebra[Int] = Kleisli.pure(1) } @module trait App { val nonLogging: NonLogging val loggingM: LoggingM } }
Example 37
Source File: algebras.scala From freestyle with Apache License 2.0 | 5 votes |
package freestyle.free import cats.Id import cats.data.Kleisli import freestyle.free.logging.LoggingM import scala.concurrent.Future object algebras { @free trait NonLogging { def x: FS[Int] } implicit def nonLoggingFutureHandler: NonLogging.Handler[Future] = new NonLogging.Handler[Future] { def x: Future[Int] = Future.successful(1) } type TestAlgebra[A] = Kleisli[Id, String, A] implicit def nonLoggingTestAlgebraHandler: NonLogging.Handler[TestAlgebra] = new NonLogging.Handler[TestAlgebra] { def x: TestAlgebra[Int] = Kleisli.pure(1) } @module trait App { val nonLogging: NonLogging val loggingM: LoggingM } val app = App[App.Op] }
Example 38
Source File: HmacAuthMiddleware.scala From iotchain with MIT License | 5 votes |
package jbok.network.http.server.middleware import java.time.{Duration, Instant} import cats.data.{Kleisli, OptionT} import cats.effect.Sync import jbok.network.http.server.authentication.HMAC import org.http4s.headers.Authorization import org.http4s.util.CaseInsensitiveString import org.http4s.{AuthScheme, Credentials, HttpRoutes, Request, Response, Status} import tsec.mac.jca.{HMACSHA256, MacSigningKey} import scala.concurrent.duration.{FiniteDuration, _} sealed abstract class HmacAuthError(val message: String) extends Exception(message) object HmacAuthError { case object NoAuthHeader extends HmacAuthError("Could not find an Authorization header") case object NoDatetimeHeader extends HmacAuthError("Could not find an X-Datetime header") case object BadMAC extends HmacAuthError("Bad MAC") case object InvalidMacFormat extends HmacAuthError("The MAC is not a valid Base64 string") case object InvalidDatetime extends HmacAuthError("The datetime is not a valid UTC datetime string") case object Timeout extends HmacAuthError("The request time window is closed") } object HmacAuthMiddleware { val defaultDuration: FiniteDuration = 5.minutes private def verifyFromHeader[F[_]]( req: Request[F], key: MacSigningKey[HMACSHA256], duration: FiniteDuration ): Either[HmacAuthError, Unit] = for { authHeader <- req.headers .get(Authorization) .flatMap { t => t.credentials match { case Credentials.Token(scheme, token) if scheme == AuthScheme.Bearer => Some(token) case _ => None } } .toRight(HmacAuthError.NoAuthHeader) datetimeHeader <- req.headers .get(CaseInsensitiveString("X-Datetime")) .toRight(HmacAuthError.NoDatetimeHeader) instant <- HMAC.http.verifyFromHeader( req.method.name, req.uri.renderString, datetimeHeader.value, authHeader, key ) _ <- Either.cond( Instant.now().isBefore(instant.plus(Duration.ofNanos(duration.toNanos))), (), HmacAuthError.Timeout ) } yield () def apply[F[_]: Sync](key: MacSigningKey[HMACSHA256], duration: FiniteDuration = defaultDuration)(routes: HttpRoutes[F]): HttpRoutes[F] = Kleisli { req: Request[F] => verifyFromHeader(req, key, duration) match { case Left(error) => OptionT.some[F](Response[F](Status.Forbidden).withEntity(error.message)) case Right(_) => routes(req) } } }
Example 39
Source File: HttpErrorHandler.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.cpgserver.route import cats.data.{Kleisli, OptionT} import cats.effect.IO import org.http4s.{HttpRoutes, Request, Response} trait HttpErrorHandler { def handle(routes: HttpRoutes[IO]): HttpRoutes[IO] } object HttpErrorHandler { def apply(routes: HttpRoutes[IO])(handler: PartialFunction[Throwable, IO[Response[IO]]]): HttpRoutes[IO] = { Kleisli { req: Request[IO] => OptionT { routes.run(req).value.handleErrorWith { e => if (handler.isDefinedAt(e)) handler(e).map(Option(_)) else IO.raiseError(e) } } } } }
Example 40
Source File: AckerConsumerDemo.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.examples import java.nio.charset.StandardCharsets.UTF_8 import cats.data.Kleisli import cats.effect._ import cats.implicits._ import dev.profunktor.fs2rabbit.config.declaration.{DeclarationExchangeConfig, DeclarationQueueConfig} import dev.profunktor.fs2rabbit.interpreter.RabbitClient import dev.profunktor.fs2rabbit.json.Fs2JsonEncoder import dev.profunktor.fs2rabbit.model.AckResult.Ack import dev.profunktor.fs2rabbit.model.AmqpFieldValue.{LongVal, StringVal} import dev.profunktor.fs2rabbit.model.ExchangeType.Topic import dev.profunktor.fs2rabbit.model._ import fs2._ class AckerConsumerDemo[F[_]: Concurrent: Timer](fs2Rabbit: RabbitClient[F]) { private val queueName = QueueName("testQ") private val exchangeName = ExchangeName("testEX") private val routingKey = RoutingKey("testRK") implicit val stringMessageEncoder = Kleisli[F, AmqpMessage[String], AmqpMessage[Array[Byte]]](s => s.copy(payload = s.payload.getBytes(UTF_8)).pure[F]) def logPipe: Pipe[F, AmqpEnvelope[String], AckResult] = _.evalMap { amqpMsg => putStrLn(s"Consumed: $amqpMsg").as(Ack(amqpMsg.deliveryTag)) } val publishingFlag: PublishingFlag = PublishingFlag(mandatory = true) // Run when there's no consumer for the routing key specified by the publisher and the flag mandatory is true val publishingListener: PublishReturn => F[Unit] = pr => putStrLn(s"Publish listener: $pr") private val mkChannel = fs2Rabbit.createConnection.flatMap(fs2Rabbit.createChannel) val program: F[Unit] = mkChannel.use { implicit channel => for { _ <- fs2Rabbit.declareQueue(DeclarationQueueConfig.default(queueName)) _ <- fs2Rabbit.declareExchange(DeclarationExchangeConfig.default(exchangeName, Topic)) _ <- fs2Rabbit.bindQueue(queueName, exchangeName, routingKey) (acker, consumer) <- fs2Rabbit.createAckerConsumer[String](queueName) publisher <- fs2Rabbit.createPublisherWithListener[AmqpMessage[String]]( exchangeName, routingKey, publishingFlag, publishingListener ) _ <- new Flow[F, String](consumer, acker, logPipe, publisher).flow.compile.drain } yield () } } class Flow[F[_]: Concurrent, A]( consumer: Stream[F, AmqpEnvelope[A]], acker: AckResult => F[Unit], logger: Pipe[F, AmqpEnvelope[A], AckResult], publisher: AmqpMessage[String] => F[Unit] ) { import io.circe.generic.auto._ case class Address(number: Int, streetName: String) case class Person(id: Long, name: String, address: Address) private val jsonEncoder = new Fs2JsonEncoder import jsonEncoder.jsonEncode val jsonPipe: Pipe[Pure, AmqpMessage[Person], AmqpMessage[String]] = _.map(jsonEncode[Person]) val simpleMessage = AmqpMessage("Hey!", AmqpProperties(headers = Map("demoId" -> LongVal(123), "app" -> StringVal("fs2RabbitDemo")))) val classMessage = AmqpMessage(Person(1L, "Sherlock", Address(212, "Baker St")), AmqpProperties.empty) val flow: Stream[F, Unit] = Stream( Stream(simpleMessage).covary[F].evalMap(publisher), Stream(classMessage).covary[F].through(jsonPipe).evalMap(publisher), consumer.through(logger).evalMap(acker) ).parJoin(3) }
Example 41
Source File: AutoAckConsumerDemo.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.examples import java.nio.charset.StandardCharsets.UTF_8 import cats.data.Kleisli import cats.effect._ import cats.implicits._ import dev.profunktor.fs2rabbit.config.declaration.DeclarationQueueConfig import dev.profunktor.fs2rabbit.interpreter.RabbitClient import dev.profunktor.fs2rabbit.json.Fs2JsonEncoder import dev.profunktor.fs2rabbit.model.AckResult.Ack import dev.profunktor.fs2rabbit.model.AmqpFieldValue.{LongVal, StringVal} import dev.profunktor.fs2rabbit.model._ import fs2.{Pipe, Pure, Stream} import io.circe.Encoder class AutoAckConsumerDemo[F[_]: Concurrent](R: RabbitClient[F]) { private val queueName = QueueName("testQ") private val exchangeName = ExchangeName("testEX") private val routingKey = RoutingKey("testRK") implicit val stringMessageEncoder = Kleisli[F, AmqpMessage[String], AmqpMessage[Array[Byte]]](s => s.copy(payload = s.payload.getBytes(UTF_8)).pure[F]) def logPipe: Pipe[F, AmqpEnvelope[String], AckResult] = _.evalMap { amqpMsg => putStrLn(s"Consumed: $amqpMsg").as(Ack(amqpMsg.deliveryTag)) } val program: F[Unit] = R.createConnectionChannel.use { implicit channel => for { _ <- R.declareQueue(DeclarationQueueConfig.default(queueName)) _ <- R.declareExchange(exchangeName, ExchangeType.Topic) _ <- R.bindQueue(queueName, exchangeName, routingKey) publisher <- R.createPublisher[AmqpMessage[String]](exchangeName, routingKey) consumer <- R.createAutoAckConsumer[String](queueName) _ <- new AutoAckFlow[F, String](consumer, logPipe, publisher).flow.compile.drain } yield () } } class AutoAckFlow[F[_]: Concurrent, A]( consumer: Stream[F, AmqpEnvelope[A]], logger: Pipe[F, AmqpEnvelope[A], AckResult], publisher: AmqpMessage[String] => F[Unit] ) { import io.circe.generic.auto._ case class Address(number: Int, streetName: String) case class Person(id: Long, name: String, address: Address) private def jsonEncoder = new Fs2JsonEncoder def encoderPipe[T: Encoder]: Pipe[F, AmqpMessage[T], AmqpMessage[String]] = _.map(jsonEncoder.jsonEncode[T]) val jsonPipe: Pipe[Pure, AmqpMessage[Person], AmqpMessage[String]] = _.map(jsonEncoder.jsonEncode[Person]) val simpleMessage = AmqpMessage("Hey!", AmqpProperties(headers = Map("demoId" -> LongVal(123), "app" -> StringVal("fs2RabbitDemo")))) val classMessage = AmqpMessage(Person(1L, "Sherlock", Address(212, "Baker St")), AmqpProperties.empty) val flow: Stream[F, Unit] = Stream( Stream(simpleMessage).covary[F].evalMap(publisher), Stream(classMessage).covary[F].through(encoderPipe[Person]).evalMap(publisher), consumer.through(logger).through(_.evalMap(putStrLn(_))) ).parJoin(3) }
Example 42
Source File: EnvelopeDecoder.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.effects import cats.{Applicative, ApplicativeError} import cats.data.Kleisli import dev.profunktor.fs2rabbit.model.{AmqpFieldValue, AmqpProperties, ExchangeName, RoutingKey} import dev.profunktor.fs2rabbit.model.AmqpFieldValue._ import cats.implicits._ object EnvelopeDecoder { def apply[F[_], A](implicit e: EnvelopeDecoder[F, A]): EnvelopeDecoder[F, A] = e def properties[F[_]: Applicative]: EnvelopeDecoder[F, AmqpProperties] = Kleisli(e => e.properties.pure[F]) def payload[F[_]: Applicative]: EnvelopeDecoder[F, Array[Byte]] = Kleisli(_.payload.pure[F]) def routingKey[F[_]: Applicative]: EnvelopeDecoder[F, RoutingKey] = Kleisli(e => e.routingKey.pure[F]) def exchangeName[F[_]: Applicative]: EnvelopeDecoder[F, ExchangeName] = Kleisli(e => e.exchangeName.pure[F]) def redelivered[F[_]: Applicative]: EnvelopeDecoder[F, Boolean] = Kleisli(e => e.redelivered.pure[F]) def header[F[_]](name: String)(implicit F: ApplicativeError[F, Throwable]): EnvelopeDecoder[F, AmqpFieldValue] = Kleisli(e => F.catchNonFatal(e.properties.headers(name))) def optHeader[F[_]: Applicative](name: String): EnvelopeDecoder[F, Option[AmqpFieldValue]] = Kleisli(_.properties.headers.get(name).pure[F]) def stringHeader[F[_]: ApplicativeError[?[_], Throwable]](name: String): EnvelopeDecoder[F, String] = headerPF[F, String](name) { case StringVal(a) => a } def intHeader[F[_]: ApplicativeError[?[_], Throwable]](name: String): EnvelopeDecoder[F, Int] = headerPF[F, Int](name) { case IntVal(a) => a } def longHeader[F[_]: ApplicativeError[?[_], Throwable]](name: String): EnvelopeDecoder[F, Long] = headerPF[F, Long](name) { case LongVal(a) => a } def arrayHeader[F[_]: ApplicativeError[?[_], Throwable]](name: String): EnvelopeDecoder[F, collection.Seq[Any]] = headerPF[F, collection.Seq[Any]](name) { case ArrayVal(a) => a } def optStringHeader[F[_]: ApplicativeError[?[_], Throwable]](name: String): EnvelopeDecoder[F, Option[String]] = optHeaderPF[F, String](name) { case StringVal(a) => a } def optIntHeader[F[_]: ApplicativeError[?[_], Throwable]](name: String): EnvelopeDecoder[F, Option[Int]] = optHeaderPF[F, Int](name) { case IntVal(a) => a } def optLongHeader[F[_]: ApplicativeError[?[_], Throwable]](name: String): EnvelopeDecoder[F, Option[Long]] = optHeaderPF[F, Long](name) { case LongVal(a) => a } def optArrayHeader[F[_]: ApplicativeError[?[_], Throwable]]( name: String): EnvelopeDecoder[F, Option[collection.Seq[Any]]] = optHeaderPF[F, collection.Seq[Any]](name) { case ArrayVal(a) => a } private def headerPF[F[_], A](name: String)(pf: PartialFunction[AmqpFieldValue, A])( implicit F: ApplicativeError[F, Throwable]): EnvelopeDecoder[F, A] = Kleisli { env => F.catchNonFatal(pf(env.properties.headers(name))) } private def optHeaderPF[F[_], A](name: String)(pf: PartialFunction[AmqpFieldValue, A])( implicit F: ApplicativeError[F, Throwable]): EnvelopeDecoder[F, Option[A]] = Kleisli(_.properties.headers.get(name).traverse(h => F.catchNonFatal(pf(h)))) }
Example 43
Source File: ConversionResult.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.convert import cats.data.Kleisli import fs2.Stream import docspell.common.MimeType sealed trait ConversionResult[F[_]] { def pdfData: Stream[F, Byte] } object ConversionResult { type Handler[F[_], A] = Kleisli[F, ConversionResult[F], A] def unsupportedFormat[F[_]](mime: MimeType): ConversionResult[F] = UnsupportedFormat[F](mime) def failure[F[_]](ex: Throwable): ConversionResult[F] = Failure[F](ex) def successPdf[F[_]](pdf: Stream[F, Byte]): ConversionResult[F] = SuccessPdf[F](pdf) def successPdfTxt[F[_]](pdf: Stream[F, Byte], txt: F[String]): ConversionResult[F] = SuccessPdfTxt[F](pdf, txt) def inputMalformed[F[_]](mimeType: MimeType, reason: String): ConversionResult[F] = InputMalformed(mimeType, reason) case class UnsupportedFormat[F[_]](mime: MimeType) extends ConversionResult[F] { val pdfData = Stream.empty } case class Failure[F[_]](ex: Throwable) extends ConversionResult[F] { val pdfData = Stream.empty } case class SuccessPdf[F[_]](pdf: Stream[F, Byte]) extends ConversionResult[F] { val pdfData = pdf } case class SuccessPdfTxt[F[_]](pdf: Stream[F, Byte], txt: F[String]) extends ConversionResult[F] { val pdfData = pdf } case class InputMalformed[F[_]](mimeType: MimeType, reason: String) extends ConversionResult[F] { val pdfData = Stream.empty } }
Example 44
Source File: FileChecks.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.convert import java.nio.charset.StandardCharsets import java.nio.file.{Files, Path} import cats.data.Kleisli import cats.effect.IO import fs2.{Pipe, Stream} import docspell.common.MimeType import docspell.convert.ConversionResult.Handler import docspell.files.TikaMimetype trait FileChecks { implicit class FileCheckOps(p: Path) { def isNonEmpty: Boolean = Files.exists(p) && Files.size(p) > 0 def isType(mime: MimeType): Boolean = TikaMimetype.detect[IO](p).map(_ == mime).unsafeRunSync def isPDF: Boolean = isType(MimeType.pdf) def isPlainText: Boolean = isType(MimeType.text("plain")) } def storeFile(file: Path): Pipe[IO, Byte, Path] = in => Stream.eval(in.compile.to(Array).flatMap(bytes => IO(Files.write(file, bytes)))) def storePdfHandler(file: Path): Handler[IO, Path] = storePdfTxtHandler(file, file.resolveSibling("unexpected.txt")).map(_._1) def storePdfTxtHandler(filePdf: Path, fileTxt: Path): Handler[IO, (Path, Path)] = Kleisli({ case ConversionResult.SuccessPdfTxt(pdf, txt) => for { pout <- pdf.through(storeFile(filePdf)).compile.lastOrError str <- txt tout <- IO(Files.write(fileTxt, str.getBytes(StandardCharsets.UTF_8))) } yield (pout, tout) case ConversionResult.SuccessPdf(pdf) => pdf.through(storeFile(filePdf)).compile.lastOrError.map(p => (p, fileTxt)) case ConversionResult.Failure(ex) => throw new Exception(s"Unexpected result (failure: ${ex.getMessage})", ex) case cr => throw new Exception(s"Unexpected result: $cr") }) def commandExists(cmd: String): Boolean = Runtime.getRuntime.exec(Array("which", cmd)).waitFor() == 0 }
Example 45
Source File: Migration.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.fts import cats.Traverse import cats.data.{Kleisli, OptionT} import cats.effect._ import cats.implicits._ import docspell.common._ import docspell.ftsclient._ import docspell.joex.Config import docspell.store.records.RFtsMigration import docspell.store.{AddResult, Store} case class Migration[F[_]]( version: Int, engine: Ident, description: String, task: FtsWork[F] ) object Migration { def apply[F[_]: Effect]( cfg: Config.FullTextSearch, fts: FtsClient[F], store: Store[F], logger: Logger[F] ): Kleisli[F, List[Migration[F]], Unit] = { val ctx = FtsContext(cfg, store, fts, logger) Kleisli(migs => Traverse[List].sequence(migs.map(applySingle[F](ctx))).map(_ => ())) } def applySingle[F[_]: Effect](ctx: FtsContext[F])(m: Migration[F]): F[Unit] = { val insertRecord: F[Option[RFtsMigration]] = for { rec <- RFtsMigration.create(m.version, m.engine, m.description) res <- ctx.store.add( RFtsMigration.insert(rec), RFtsMigration.exists(m.version, m.engine) ) ret <- res match { case AddResult.Success => rec.some.pure[F] case AddResult.EntityExists(_) => None.pure[F] case AddResult.Failure(ex) => Effect[F].raiseError(ex) } } yield ret (for { _ <- OptionT.liftF(ctx.logger.info(s"Apply ${m.version}/${m.description}")) rec <- OptionT(insertRecord) res <- OptionT.liftF(m.task.run(ctx).attempt) ret <- OptionT.liftF(res match { case Right(()) => ().pure[F] case Left(ex) => ctx.logger.error(ex)( s"Applying index migration ${m.version}/${m.description} failed" ) *> ctx.store.transact(RFtsMigration.deleteById(rec.id)) *> Effect[F] .raiseError[Unit]( ex ) }) } yield ret).getOrElseF( ctx.logger.info(s"Migration ${m.version}/${m.description} already applied.") ) } }
Example 46
Source File: FtsWork.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.fts import cats.data.{Kleisli, NonEmptyList} import cats.effect._ import cats.implicits._ import cats.{ApplicativeError, FlatMap, Semigroup} import docspell.common._ import docspell.ftsclient._ import docspell.joex.Config import docspell.joex.scheduler.Context import docspell.store.queries.{QAttachment, QItem} object FtsWork { def apply[F[_]](f: FtsContext[F] => F[Unit]): FtsWork[F] = Kleisli(f) def all[F[_]: FlatMap]( m0: FtsWork[F], mn: FtsWork[F]* ): FtsWork[F] = NonEmptyList.of(m0, mn: _*).reduce(semigroup[F]) implicit def semigroup[F[_]: FlatMap]: Semigroup[FtsWork[F]] = Semigroup.instance((mt1, mt2) => mt1.flatMap(_ => mt2)) // some tasks def log[F[_]](f: Logger[F] => F[Unit]): FtsWork[F] = FtsWork(ctx => f(ctx.logger)) def initialize[F[_]]: FtsWork[F] = FtsWork(_.fts.initialize) def clearIndex[F[_]](coll: Option[Ident]): FtsWork[F] = coll match { case Some(cid) => FtsWork(ctx => ctx.fts.clear(ctx.logger, cid)) case None => FtsWork(ctx => ctx.fts.clearAll(ctx.logger)) } def insertAll[F[_]: Effect](coll: Option[Ident]): FtsWork[F] = FtsWork .all( FtsWork(ctx => ctx.fts.indexData( ctx.logger, ctx.store .transact( QAttachment .allAttachmentMetaAndName(coll, ctx.cfg.migration.indexAllChunk) ) .map(caa => TextData .attachment( caa.item, caa.id, caa.collective, caa.lang, caa.name, caa.content ) ) ) ), FtsWork(ctx => ctx.fts.indexData( ctx.logger, ctx.store .transact(QItem.allNameAndNotes(coll, ctx.cfg.migration.indexAllChunk * 5)) .map(nn => TextData.item(nn.id, nn.collective, Option(nn.name), nn.notes)) ) ) ) object syntax { implicit final class FtsWorkOps[F[_]](mt: FtsWork[F]) { def ++(mn: FtsWork[F])(implicit ev: FlatMap[F]): FtsWork[F] = all(mt, mn) def recoverWith( other: FtsWork[F] )(implicit ev: ApplicativeError[F, Throwable]): FtsWork[F] = Kleisli(ctx => mt.run(ctx).onError({ case _ => other.run(ctx) })) def forContext( cfg: Config.FullTextSearch, fts: FtsClient[F] ): Kleisli[F, Context[F, _], Unit] = mt.local(ctx => FtsContext(cfg, fts, ctx)) } } }
Example 47
Source File: Tracer.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer import cats.Applicative import cats.data.Kleisli import cats.effect.Sync import cats.syntax.all._ import org.http4s.syntax.StringSyntax import org.http4s.{Header, HttpApp, Request} object Tracer extends StringSyntax { private[tracer] val DefaultTraceIdHeader = "Trace-Id" final case class TraceId(value: String) extends AnyVal { override def toString = s"[Trace-Id] - [$value]" } def apply[F[_]](implicit ev: Tracer[F]): Tracer[F] = ev def create[F[_]](headerName: String = DefaultTraceIdHeader): Tracer[F] = new Tracer[F](headerName) } class Tracer[F[_]] private (headerName: String) { import Trace._, Tracer._ def middleware( http: HttpApp[F], logRequest: Boolean = false, logResponse: Boolean = false )(implicit F: Sync[F], L: TracerLog[Trace[F, ?]]): HttpApp[F] = Kleisli { req => val createId: F[(Request[F], TraceId)] = for { id <- GenUUID.make[F] tr <- F.delay(req.putHeaders(Header(headerName, id.value))) } yield (tr, id) for { mi <- getTraceId(req) (tr, id) <- mi.fold(createId)(id => (req, id).pure[F]) _ <- if (logRequest) L.info[Tracer[F]](s"$req").run(id) else F.unit rs <- http(tr).map(_.putHeaders(Header(headerName, id.value))) _ <- if (logResponse) L.info[Tracer[F]](s"$rs").run(id) else F.unit } yield rs } def loggingMiddleware( http: HttpApp[F] )(implicit F: Sync[F], L: TracerLog[Trace[F, ?]]): HttpApp[F] = middleware(http, logRequest = true, logResponse = true) def getTraceId(request: Request[F])(implicit F: Applicative[F]): F[Option[TraceId]] = F.pure(request.headers.get(headerName.ci).map(h => TraceId(h.value))) }
Example 48
Source File: AuthTracedHttpRoute.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.auth import cats.Monad import cats.data.{Kleisli, OptionT} import cats.syntax.flatMap._ import cats.syntax.functor._ import dev.profunktor.tracer.Tracer import dev.profunktor.tracer.Tracer.TraceId import org.http4s.{AuthedRequest, AuthedRoutes, Response} object AuthTracedHttpRoute { case class AuthTracedRequest[F[_], T](traceId: TraceId, request: AuthedRequest[F, T]) def apply[T, F[_]: Monad: Tracer]( pf: PartialFunction[AuthTracedRequest[F, T], F[Response[F]]] ): AuthedRoutes[T, F] = Kleisli[OptionT[F, ?], AuthedRequest[F, T], Response[F]] { req => OptionT { Tracer[F] .getTraceId(req.req) .map(x => AuthTracedRequest[F, T](x.getOrElse(TraceId("-")), req)) .flatMap { tr => val rs: OptionT[F, Response[F]] = pf.andThen(OptionT.liftF(_)).applyOrElse(tr, Function.const(OptionT.none)) rs.value } } } }
Example 49
Source File: TracedHttpRoute.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer import cats.Monad import cats.data.{Kleisli, OptionT} import cats.syntax.flatMap._ import cats.syntax.functor._ import dev.profunktor.tracer.Tracer.TraceId import org.http4s.{HttpRoutes, Request, Response} object TracedHttpRoute { case class TracedRequest[F[_]](traceId: TraceId, request: Request[F]) def apply[F[_]: Monad: Tracer]( pf: PartialFunction[TracedRequest[F], F[Response[F]]] ): HttpRoutes[F] = Kleisli[OptionT[F, ?], Request[F], Response[F]] { req => OptionT { Tracer[F] .getTraceId(req) .map(x => TracedRequest[F](x.getOrElse(TraceId("-")), req)) .flatMap { tr => val rs: OptionT[F, Response[F]] = pf.andThen(OptionT.liftF(_)).applyOrElse(tr, Function.const(OptionT.none)) rs.value } } } }