diff --git a/idealingua-v1/idealingua-v1-runtime-rpc-http4s/src/test/scala/izumi/idealingua/runtime/rpc/http4s/fixtures/TestServices.scala b/idealingua-v1/idealingua-v1-runtime-rpc-http4s/src/test/scala/izumi/idealingua/runtime/rpc/http4s/fixtures/TestServices.scala index f4beff85..cfaced6d 100644 --- a/idealingua-v1/idealingua-v1-runtime-rpc-http4s/src/test/scala/izumi/idealingua/runtime/rpc/http4s/fixtures/TestServices.scala +++ b/idealingua-v1/idealingua-v1-runtime-rpc-http4s/src/test/scala/izumi/idealingua/runtime/rpc/http4s/fixtures/TestServices.scala @@ -24,10 +24,11 @@ class TestServices[F[+_, +_]: IO2]( rejectedNames: Set[String] ): IRTServerMiddleware[F, C] = new IRTServerMiddleware[F, C] { override def priority: Int = 0 - override def prepare(methodId: IRTMethodId)(context: C, parsedBody: Json): F[Throwable, Unit] = { - F.when(rejectedNames.contains(context.user)) { - F.fail(new IRTUnathorizedRequestContextException(s"Rejected for users: $rejectedNames.")) - } + override def apply(methodId: IRTMethodId)(context: C, parsedBody: Json)(next: => F[Throwable, Json]): F[Throwable, Json] = { + F.ifThenElse(rejectedNames.contains(context.user))( + F.fail(new IRTUnathorizedRequestContextException(s"Rejected for users: $rejectedNames.")), + next, + ) } } final val wsStorage: WsSessionsStorage[F, AuthContext] = new WsSessionsStorageImpl[F, AuthContext](logger) diff --git a/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMethod.scala b/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMethod.scala index cc846b89..6169b25e 100644 --- a/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMethod.scala +++ b/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMethod.scala @@ -8,6 +8,7 @@ trait IRTServerMethod[F[+_, +_], C] { def methodId: IRTMethodId def invoke(context: C, parsedBody: Json): F[Throwable, Json] + /** Contramap eval on context C2 -> C. If context is missing IRTUnathorizedRequestContextException will raise. */ final def contramap[C2](updateContext: (C2, Json) => F[Throwable, Option[C]])(implicit E: Error2[F]): IRTServerMethod[F, C2] = new IRTServerMethod[F, C2] { override def methodId: IRTMethodId = self.methodId override def invoke(context: C2, parsedBody: Json): F[Throwable, Json] = { @@ -16,6 +17,14 @@ trait IRTServerMethod[F[+_, +_], C] { .flatMap(self.invoke(_, parsedBody)) } } + + /** Wrap invocation with function '(Context, Body)(Method.Invoke) => Result' . */ + final def wrap(middleware: (C, Json) => F[Throwable, Json] => F[Throwable, Json]): IRTServerMethod[F, C] = new IRTServerMethod[F, C] { + override def methodId: IRTMethodId = self.methodId + override def invoke(context: C, parsedBody: Json): F[Throwable, Json] = { + middleware(context, parsedBody)(self.invoke(context, parsedBody)) + } + } } object IRTServerMethod { diff --git a/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMiddleware.scala b/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMiddleware.scala index f4a7aa10..b22bd29e 100644 --- a/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMiddleware.scala +++ b/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMiddleware.scala @@ -4,5 +4,10 @@ import io.circe.Json trait IRTServerMiddleware[F[_, _], C] { def priority: Int - def prepare(methodId: IRTMethodId)(context: C, parsedBody: Json): F[Throwable, Unit] + def apply( + methodId: IRTMethodId + )(context: C, + parsedBody: Json, + )(next: => F[Throwable, Json] + ): F[Throwable, Json] } diff --git a/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMultiplexor.scala b/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMultiplexor.scala index 343b9181..7774c702 100644 --- a/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMultiplexor.scala +++ b/idealingua-v1/idealingua-v1-runtime-rpc-scala/src/main/scala/izumi/idealingua/runtime/rpc/IRTServerMultiplexor.scala @@ -12,6 +12,7 @@ trait IRTServerMultiplexor[F[+_, +_], C] { .flatMap(_.invoke(context, parsedBody)) } + /** Contramap eval on context C2 -> C. If context is missing IRTUnathorizedRequestContextException will raise. */ final def contramap[C2]( updateContext: (C2, Json) => F[Throwable, Option[C]] )(implicit io2: IO2[F] @@ -19,13 +20,13 @@ trait IRTServerMultiplexor[F[+_, +_], C] { val mappedMethods = self.methods.map { case (k, v) => k -> v.contramap(updateContext) } new IRTServerMultiplexor.FromMethods(mappedMethods) } - - final def wrap(middleware: IRTServerMiddleware[F, C])(implicit io2: IO2[F]): IRTServerMultiplexor[F, C] = { + /** Wrap invocation with function '(Context, Body)(Method.Invoke) => Result' . */ + final def wrap(middleware: IRTServerMiddleware[F, C]): IRTServerMultiplexor[F, C] = { val wrappedMethods = self.methods.map { case (methodId, method) => - val wrappedMethod: IRTServerMethod[F, C] = method.contramap[C] { + val wrappedMethod: IRTServerMethod[F, C] = method.wrap { case (ctx, body) => - middleware.prepare(methodId)(ctx, body).as(Some(ctx)) + next => middleware(method.methodId)(ctx, body)(next) } methodId -> wrappedMethod }