Skip to content

Commit

Permalink
rewrite Server to use latest ZIO
Browse files Browse the repository at this point in the history
  • Loading branch information
dnaumenko committed Jul 22, 2019
1 parent 5cd3183 commit f881612
Showing 1 changed file with 70 additions and 61 deletions.
131 changes: 70 additions & 61 deletions server/src/main/scala/com/septimalmind/Server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,54 +19,93 @@ import org.http4s.Request
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.{AuthMiddleware, Router}
import org.http4s.syntax.kleisli._
import zio.IO
import zio.{IO, ZIO}
import zio.interop.catz._
import zio.console.putStrLn
import cats.effect._
import org.http4s._
import org.http4s.dsl.io._

object Server extends App with RuntimeContext {
import scala.util.Try

private val tokenService = new TokenService[IO]
private val userRepo = new UserRepo[IO]
private val sessionRepo = new UserSessionRepo[IO]
object Server extends zio.App with RuntimeContext {
private val port = 8080

lazy val loginAPI = new LoginServiceWrappedServer[IO, RequestContext](new LoginService[IO](logger, tokenService, userRepo, sessionRepo))
override def run(args: List[String]): ZIO[Server.Environment, Nothing, Int] = {
import zio.interop.catz._

val program = for {
services <- ZIO.fromTry(Try(createServices()))
_ <- putStrLn(s"list of IDL:\n${services.map(_.serviceId.value).mkString("\n", "\n", "\n") -> "APIs"}")
router = createHttpRouter(services)
server <- ZIO.runtime.flatMap { implicit rt =>
BlazeServerBuilder[IO[Throwable, ?]]
.bindHttp(port, "0.0.0.0")
.withExecutionContext(scala.concurrent.ExecutionContext.global)
.withHttpApp(router)
.serve
.compile
.drain
}
} yield server

val adminAPI = new UserProfileServiceWrappedServer[IO, AdminRequest](new ProfileService[IO]).contramap[RequestContext] {
case i: AdminRequest => i
case _ => throw new IllegalArgumentException("REJECTED. unknown request context")
program.foldM(err => zio.console.putStrLn(s"Execution failed with: $err") *> ZIO.succeed(1), _ => ZIO.succeed(0))
}

val services = Set(loginAPI, adminAPI): Set[IRTWrappedService[IO, RequestContext]]
private def createServices() = {
val tokenService = new TokenService[IO]
val userRepo = new UserRepo[IO]
val sessionRepo = new UserSessionRepo[IO]

val idlRouter = "/v2/" -> setupIDLRuntime(
services,
Set.empty,
logger
)
val legacyRouter = "/v1/" -> prepareHttp4sRouter
val loginAPI = new LoginServiceWrappedServer[IO, RequestContext](new LoginService[IO](logger, tokenService, userRepo, sessionRepo))

val allRoutes = Router(List(idlRouter, idlRouter): _*).orNotFound
val adminAPI: IRTWrappedService[IO, RequestContext] = new UserProfileServiceWrappedServer[IO, AdminRequest](new ProfileService[IO]).contramap[RequestContext] {
case i: AdminRequest => i
case _ => throw new IllegalArgumentException("REJECTED. unknown request context")
}

private val port = 8080
Set(loginAPI, adminAPI)
}

logger.info(s"starting your server on ${port -> "port"}")
private def createHttpRouter(services: Set[IRTWrappedService[IO, RequestContext]]) = {
val idlRouter = "/v2/" -> setupIDLRuntime(
services,
Set.empty,
logger
)
val heartbeatRoute = "/v1/" -> HttpRoutes.of {
case GET -> Root / "heartbeat" =>
Sync[IO[Throwable, ?]]
.pure(Response(Status.Ok, headers = Headers.of(Header("Response-Issuer", "PUT_SERVICE_NAME_HERE"))))
}

val serviceNames = services.map(_.serviceId.value)
Router(List(idlRouter, heartbeatRoute): _*).orNotFound
}

logger.info(s"list of IDL:\n${serviceNames.mkString("\n", "\n", "\n") -> "APIs"}")
private def setupIDLRuntime(services: Set[IRTWrappedService[IO, RequestContext]],
clients: Set[IRTWrappedClient], logger: IzLogger)
(implicit bio: BIORunner[IO], timer: Timer[IO[Throwable, ?]]): HttpRoutes[IO[Throwable, ?]] = {
def prepareRequest(request: Request[IO[Throwable, ?]]) : Option[RequestContext] = {
lazy val networkContext = NetworkContext(request.remoteAddr.getOrElse("0.0.0.0"))
import org.http4s.syntax.string._
val privateScheme = "Api-Key".ci
request.headers.find(_.name == "Authorization".ci).map(_.value.split(" ").toList match {
case "Bearer" :: token :: Nil =>
ClientRequest.fromHeader(token, networkContext)
case scheme :: token :: Nil if scheme.ci == privateScheme =>
AdminRequest.fromHeader(token, networkContext)
case _ =>
Some(GuestRequest(networkContext))
}).getOrElse(Some(GuestRequest(networkContext)))
}

val server = BlazeServerBuilder[IO[Throwable, ?]]
.bindHttp(8080, "0.0.0.0")
.withExecutionContext(scala.concurrent.ExecutionContext.global)
.withHttpApp(allRoutes)
.serve
.compile
.drain
bio.unsafeRun(server)
def setupWsContext(rt: Http4sRuntime[IO, RequestContext, RequestContext, String, Unit, Unit], logger: IzLogger, codec: IRTClientMultiplexor[IO]) = {
val listeners: Set[WsSessionListener[String]] = Set.empty
val wsContextProvider: WsContextProvider[IO, RequestContext, String] = new IdContextProvider[rt.type](rt.self)
val wsSessionStorage: WsSessionsStorage[IO, String, RequestContext] = new WsSessionsStorageImpl[rt.type](rt.self, logger, codec)
(listeners, wsContextProvider, wsSessionStorage)
}

def setupIDLRuntime(services: Set[IRTWrappedService[IO, RequestContext]], clients: Set[IRTWrappedClient], logger: IzLogger)(implicit bio: BIORunner[IO], timer: Timer[IO[Throwable, ?]]) = {
val clientMultiplexor: IRTClientMultiplexor[IO] = new IRTClientMultiplexor[IO](clients)
val serverMultiplexor = new IRTServerMultiplexor[IO, RequestContext, RequestContext](services, ContextExtender.id)

Expand All @@ -88,38 +127,8 @@ object Server extends App with RuntimeContext {
listeners.toSeq,
logger,
printer
) {

}
) {}

server.service
}

private def prepareRequest(request: Request[IO[Throwable, ?]]) : Option[RequestContext] = {
lazy val networkContext = NetworkContext(request.remoteAddr.getOrElse("0.0.0.0"))
import org.http4s.syntax.string._
val privateScheme = "Api-Key".ci
request.headers.find(_.name == "Authorization".ci).map(_.value.split(" ").toList match {
case "Bearer" :: token :: Nil =>
ClientRequest.fromHeader(token, networkContext)
case scheme :: token :: Nil if scheme.ci == privateScheme =>
AdminRequest.fromHeader(token, networkContext)
case _ =>
Some(GuestRequest(networkContext))
}).getOrElse(Some(GuestRequest(networkContext)))
}

private def setupWsContext(rt: Http4sRuntime[IO, RequestContext, RequestContext, String, Unit, Unit], logger: IzLogger, codec: IRTClientMultiplexor[IO]) = {
val listeners: Set[WsSessionListener[String]] = Set.empty
val wsContextProvider: WsContextProvider[IO, RequestContext, String] = new IdContextProvider[rt.type](rt.self)
val wsSessionStorage: WsSessionsStorage[IO, String, RequestContext] = new WsSessionsStorageImpl[rt.type](rt.self, logger, codec)
(listeners, wsContextProvider, wsSessionStorage)
}

private def prepareHttp4sRouter: HttpRoutes[IO[Throwable, ?]] =
HttpRoutes.of {
case GET -> Root / "heartbeat" =>
Sync[IO[Throwable, ?]]
.pure(Response(Status.Ok, headers = Headers.of(Header("Response-Issuer", "PUT_SERVICE_NAME_HERE"))))
}
}

0 comments on commit f881612

Please sign in to comment.