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

sttp.tapir.server.armeria.cats.ArmeriaCatsServerOptions.scala Maven / Gradle / Ivy

There is a newer version: 1.11.4
Show newest version
package sttp.tapir.server.armeria.cats

import cats.effect.std.Dispatcher
import cats.effect.{Async, Sync}
import com.linecorp.armeria.common.CommonPools
import org.slf4j.{Logger, LoggerFactory}
import scala.util.control.NonFatal
import sttp.tapir.server.armeria.ArmeriaServerOptions
import sttp.tapir.server.interceptor.log.DefaultServerLog
import sttp.tapir.server.interceptor.{CustomiseInterceptors, Interceptor}
import sttp.tapir.{Defaults, TapirFile}

final case class ArmeriaCatsServerOptions[F[_]](
    dispatcher: Dispatcher[F],
    createFile: () => F[TapirFile],
    deleteFile: TapirFile => F[Unit],
    interceptors: List[Interceptor[F]]
) extends ArmeriaServerOptions[F] {
  def prependInterceptor(i: Interceptor[F]): ArmeriaCatsServerOptions[F] =
    copy(interceptors = i :: interceptors)

  def appendInterceptor(i: Interceptor[F]): ArmeriaCatsServerOptions[F] =
    copy(interceptors = interceptors :+ i)
}

object ArmeriaCatsServerOptions {

  /** Allows customising the interceptors used by the server interpreter. */
  def customiseInterceptors[F[_]](
      dispatcher: Dispatcher[F]
  )(implicit F: Async[F]): CustomiseInterceptors[F, ArmeriaCatsServerOptions[F]] = {
    CustomiseInterceptors(
      createOptions = (ci: CustomiseInterceptors[F, ArmeriaCatsServerOptions[F]]) => {
        ArmeriaCatsServerOptions[F](
          dispatcher,
          () => defaultCreateFile()(F),
          file => defaultDeleteFile(file)(F),
          ci.interceptors
        )
      }
    ).serverLog(defaultServerLog)
  }

  private val logger: Logger = LoggerFactory.getLogger(this.getClass.getPackage.getName)

  def defaultCreateFile[F[_]: Async](): F[TapirFile] = blocking(Defaults.createTempFile())

  def defaultDeleteFile[F[_]: Async](file: TapirFile): F[Unit] = blocking(Defaults.deleteFile()(file))

  def defaultServerLog[F[_]: Async]: DefaultServerLog[F] = DefaultServerLog[F](
    doLogWhenReceived = debugLog(_, None),
    doLogWhenHandled = debugLog[F],
    doLogAllDecodeFailures = debugLog[F],
    doLogExceptions = (msg: String, ex: Throwable) => Sync[F].delay(logger.warn(msg, ex)),
    noLog = Async[F].pure(())
  )

  def default[F[_]: Async](dispatcher: Dispatcher[F]): ArmeriaCatsServerOptions[F] = customiseInterceptors(dispatcher).options

  private def debugLog[F[_]: Async](msg: String, exOpt: Option[Throwable]): F[Unit] =
    Sync[F].delay(exOpt match {
      case None     => logger.debug(msg)
      case Some(ex) => logger.debug(msg, ex)
    })

  private def blocking[F[_], T](body: => T)(implicit F: Async[F]): F[T] = {
    F.async { cb =>
      F.delay {
        val javaFuture = CommonPools
          .blockingTaskExecutor()
          .submit(new Runnable {
            override def run(): Unit = {
              try {
                cb(Right(body))
              } catch {
                case NonFatal(ex) =>
                  cb(Left(ex))
              }
            }
          })
        Some(F.void(F.delay { javaFuture.cancel(true) }))
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy