All Downloads are FREE. Search and download functionalities are using the official Maven repository.

izumi.idealingua.runtime.rpc.http4s.clients.WsRpcDispatcher.scala Maven / Gradle / Ivy

The newest version!
package izumi.idealingua.runtime.rpc.http4s.clients

import io.circe.Json
import izumi.functional.bio.{Async2, Entropy2, F, Temporal2}
import izumi.idealingua.runtime.rpc.*
import izumi.idealingua.runtime.rpc.http4s.clients.WsRpcDispatcher.IRTDispatcherWs
import izumi.idealingua.runtime.rpc.http4s.clients.WsRpcDispatcherFactory.WsRpcClientConnection
import izumi.idealingua.runtime.rpc.http4s.ws.{RawResponse, WsSessionId}
import logstage.LogIO2

import java.util.concurrent.TimeoutException
import scala.concurrent.duration.FiniteDuration

class WsRpcDispatcher[F[+_, +_]: Async2](
  connection: WsRpcClientConnection[F],
  timeout: FiniteDuration,
  codec: IRTClientMultiplexor[F],
  logger: LogIO2[F],
  entropy2: Entropy2[F],
) extends IRTDispatcherWs[F] {

  override def sessionId: Option[WsSessionId] = {
    connection.sessionId
  }

  override def authorize(headers: Map[String, String]): F[Throwable, Unit] = {
    connection.authorize(headers, timeout)
  }

  override def dispatch(input: IRTMuxRequest): F[Throwable, IRTMuxResponse] = {
    dispatchFor(connection, codec)(timeout)(input)
  }

  protected def dispatchFor(
    connection: WsRpcClientConnection[F],
    codec: IRTClientMultiplexor[F],
  )(timeout: FiniteDuration
  )(request: IRTMuxRequest
  ): F[Throwable, IRTMuxResponse] = {
    for {
      _           <- logger.trace(s"${request.method -> "method"}: Going to perform $request")
      encoded     <- codec.encode(request)
      rpcPacketId <- RpcPacketId.random(entropy2)
      rpcPacket    = buildRequest(rpcPacketId, request.method, encoded)
      res <- connection.requestAndAwait(rpcPacketId, rpcPacket, Some(request.method), timeout).flatMap {
        case Some(value: RawResponse.EmptyRawResponse) =>
          F.fail(new IRTGenericFailure(s"${request.method -> "method"}, $rpcPacketId: empty response: $value"))

        case Some(value: RawResponse.GoodRawResponse) =>
          logger.debug(s"${request.method -> "method"}, $rpcPacketId: Have response: $value") *>
          codec.decode(value.data, value.method)

        case Some(value: RawResponse.BadRawResponse) =>
          logger.debug(s"${request.method -> "method"}, $rpcPacketId: Have response: $value") *>
          F.fail(new IRTGenericFailure(s"${request.method -> "method"}, $rpcPacketId: generic failure: ${value.error}"))

        case None =>
          F.fail(new TimeoutException(s"${request.method -> "method"}, $rpcPacketId: No response in $timeout"))
      }
    } yield res
  }

  protected def buildRequest(rpcPacketId: RpcPacketId, method: IRTMethodId, body: Json): RpcPacket = {
    RpcPacket.rpcRequest(rpcPacketId, method, body)
  }
}

object WsRpcDispatcher {
  trait IRTDispatcherWs[F[_, _]] extends IRTDispatcher[F] {
    def sessionId: Option[WsSessionId]
    def authorize(headers: Map[String, String]): F[Throwable, Unit]
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy