package org.lyranthe.fs2_grpc package java_runtime package server import cats.effect.{ConcurrentEffect, Effect} import cats.effect.concurrent.{Deferred, Ref} import cats.syntax.all._ import io.grpc._ class Fs2UnaryServerCallListener[F[_], Request, Response] private ( request: Ref[F, Option[Request]], isComplete: Deferred[F, Unit], val isCancelled: Deferred[F, Unit], val call: Fs2ServerCall[F, Request, Response] )(implicit F: Effect[F]) extends ServerCall.Listener[Request] with Fs2ServerCallListener[F, F, Request, Response] { import Fs2UnaryServerCallListener._ override def onCancel(): Unit = { isCancelled.complete(()).unsafeRun() } override def onMessage(message: Request): Unit = { request.access .flatMap[Unit] { case (curValue, modify) => if (curValue.isDefined) F.raiseError(statusException(TooManyRequests)) else modify(message.some).void } .unsafeRun() } override def onHalfClose(): Unit = isComplete.complete(()).unsafeRun() override def source: F[Request] = for { _ <- isComplete.get valueOrNone <- request.get value <- valueOrNone.fold[F[Request]](F.raiseError(statusException(NoMessage)))(F.pure) } yield value } object Fs2UnaryServerCallListener { val TooManyRequests: String = "Too many requests" val NoMessage: String = "No message for unary call" private val statusException: String => StatusRuntimeException = msg => new StatusRuntimeException(Status.INTERNAL.withDescription(msg)) class PartialFs2UnaryServerCallListener[F[_]](val dummy: Boolean = false) extends AnyVal { def apply[Request, Response]( call: ServerCall[Request, Response], options: ServerCallOptions = ServerCallOptions.default )(implicit F: ConcurrentEffect[F] ): F[Fs2UnaryServerCallListener[F, Request, Response]] = for { request <- Ref.of[F, Option[Request]](none) isComplete <- Deferred[F, Unit] isCancelled <- Deferred[F, Unit] serverCall <- Fs2ServerCall[F, Request, Response](call, options) } yield new Fs2UnaryServerCallListener[F, Request, Response](request, isComplete, isCancelled, serverCall) } def apply[F[_]] = new PartialFs2UnaryServerCallListener[F] }