From affc2e0d9317269493044d935cfa9d9e854f1528 Mon Sep 17 00:00:00 2001 From: Guntis Smaukstelis Date: Wed, 17 May 2023 01:20:01 +0300 Subject: [PATCH] Migrate from Blaze to Ember --- build.sbt | 7 +++--- src/main/scala/fetch/FetchService.scala | 4 +-- src/main/scala/server/Main.scala | 25 ++++++++++--------- src/main/scala/server/Server.scala | 33 ++++++++++++++++++------- web/.env.development | 2 +- 5 files changed, 44 insertions(+), 27 deletions(-) diff --git a/build.sbt b/build.sbt index b54c592..85adeea 100644 --- a/build.sbt +++ b/build.sbt @@ -8,13 +8,14 @@ lazy val root = (project in file(".")) Compile / mainClass := Some("server.Main") ) -val http4sVersion = "0.23.16" +val http4sVersion = "0.23.18" val circeVersion = "0.14.1" libraryDependencies ++= Seq( "org.http4s" %% "http4s-dsl" % http4sVersion, - "org.http4s" %% "http4s-blaze-server" % "0.23.9", - "org.http4s" %% "http4s-blaze-client" % "0.23.13", + "org.http4s" %% "http4s-server" % http4sVersion, + "org.http4s" %% "http4s-ember-server" % http4sVersion, + "org.http4s" %% "http4s-ember-client" % http4sVersion, "org.http4s" %% "http4s-circe" % http4sVersion, "ch.qos.logback" % "logback-classic" % "1.2.9", diff --git a/src/main/scala/fetch/FetchService.scala b/src/main/scala/fetch/FetchService.scala index 8bd3968..3ca7ee8 100644 --- a/src/main/scala/fetch/FetchService.scala +++ b/src/main/scala/fetch/FetchService.scala @@ -3,9 +3,9 @@ package fetch import cats.effect._ import cats.implicits._ import org.http4s._ -import org.http4s.blaze.client.BlazeClientBuilder import org.http4s.client.Client import org.http4s.headers.Authorization +import org.http4s.ember.client.EmberClientBuilder import pureconfig._ import pureconfig.generic.auto._ @@ -45,7 +45,7 @@ object FetchService { private def fetchFiles(fileNames: List[String]): IO[List[Either[Throwable, (String, String)]]] = { val IOUrls = baseUrl.map(baseUrl => fileNames.map(baseUrl / _)) - BlazeClientBuilder[IO](global).resource.use { client => + EmberClientBuilder.default[IO].build.use { client => IOUrls.flatMap(_.traverse(url => makeRequest(client, url))) } } diff --git a/src/main/scala/server/Main.scala b/src/main/scala/server/Main.scala index 826d7c5..7714fc1 100644 --- a/src/main/scala/server/Main.scala +++ b/src/main/scala/server/Main.scala @@ -1,22 +1,23 @@ package server import cats.effect._ +import cats.implicits.catsSyntaxTuple2Parallel import db.DBService import fetch.{FetchService, FileNameService} -import fs2.Stream object Main extends IOApp { def run(args: List[String]): IO[ExitCode] = { val fetchTask = FileNameService.generateCurrentHour.flatMap(FetchService.fetchSingleFile) - Stream( - Server.run, - Scheduler.scheduleTask(fetchTask) - .evalMap { case (name, content) => - IO(println(s"fetched: $name")) *> - DBService.save(name, content).attempt.flatMap { - case Right(savedName) => IO(println(s"File saved: $savedName")) - case Left(err) => IO(println(s"Error: $err")) - } - } - ).parJoinUnbounded.compile.drain.as(ExitCode.Success) + val scheduler = Scheduler.scheduleTask(fetchTask) + .evalMap { case (name, content) => + IO(println(s"fetched: $name")) *> + DBService.save(name, content).attempt.flatMap { + case Right(savedName) => IO(println(s"File saved: $savedName")) + case Left(err) => IO(println(s"Error: $err")) + } + }.compile.drain // Convert Stream[IO, Unit] to IO[Unit] + + val server = Server.run // This is an IO[Server] + + (server, scheduler).parMapN((_, _) => ExitCode.Success) } } \ No newline at end of file diff --git a/src/main/scala/server/Server.scala b/src/main/scala/server/Server.scala index 4fdb9e7..8cce7f9 100644 --- a/src/main/scala/server/Server.scala +++ b/src/main/scala/server/Server.scala @@ -2,6 +2,7 @@ package server import cats.effect._ import cats.implicits.toTraverseOps +import com.comcast.ip4s.IpLiteralSyntax import db.DBService import fetch.FetchService import parse.{Parser, WeatherData} @@ -9,14 +10,18 @@ import server.ValidateRoutes.{AggKey, CityList, DateTimeRange, ValidDate} import io.circe.{Json, Printer} import org.http4s._ import org.http4s.dsl.io._ +import org.http4s.implicits._ import org.http4s.server.{Router, staticcontent} -import org.http4s.server.blaze.BlazeServerBuilder +import org.http4s.server.middleware.CORS +import org.http4s.server.middleware.CORSConfig +import org.http4s.server.staticcontent.FileService +import org.http4s.ember.server.EmberServerBuilder import io.circe.syntax._ import parse.Aggregate.AggregateValueImplicits.aggregateValueEncoder import parse.Aggregate.{AggregateKey, UserQuery} import fs2.Stream -import org.http4s.server.middleware.CORS -import org.http4s.server.staticcontent.FileService + +import scala.concurrent.duration.DurationInt object Server { @@ -91,16 +96,26 @@ object Server { } } - val apiRoutesCors = CORS(apiRoutes) + val corsConfig = CORSConfig.default + .withAnyOrigin(true) + .withAnyMethod(true) + .withAllowedMethods(Some(Set(Method.GET, Method.POST))) + .withAllowCredentials(false) + .withMaxAge(1.day) + + val apiRoutesCors = CORS(apiRoutes, corsConfig) private val httpApp = Router( "/" -> staticcontent.fileService[IO](FileService.Config("./web/dist")), "/api" -> apiRoutesCors ).orNotFound - def run: Stream[IO, ExitCode] = - BlazeServerBuilder[IO] - .bindHttp(8080, "0.0.0.0") - .withHttpApp(httpApp) - .serve + def run: IO[ExitCode] = + EmberServerBuilder + .default[IO] + .withHost(ipv4"0.0.0.0") + .withPort(port"8080") + .withHttpApp(httpApp) + .build + .useForever } diff --git a/web/.env.development b/web/.env.development index 59148f7..abf41e8 100644 --- a/web/.env.development +++ b/web/.env.development @@ -1 +1 @@ -VITE_API_HOST=http://localhost:8080 +VITE_API_HOST=http://0.0.0.0:8080