From f07315b9c17a999d61031dbdbb3fd4107b070868 Mon Sep 17 00:00:00 2001 From: shotexa Date: Mon, 2 Oct 2023 17:37:34 +0400 Subject: [PATCH] refactor: update zio-http to 3.0.0-RC2 and tapir to 1.6.4, remove legacy tapir (#729) Signed-off-by: Shota Jolbordi Signed-off-by: Milos Backonja Signed-off-by: Anton Baliasnikov Signed-off-by: Pat Losoponkul Signed-off-by: Benjamin Voiturier Signed-off-by: shotexa Co-authored-by: Milos Backonja <35807060+milosbackonja@users.noreply.github.com> Co-authored-by: atala-dev Co-authored-by: patlo-iog Co-authored-by: Yurii Shynbuiev - IOHK Co-authored-by: bvoiturier --- build.sbt | 9 ++-- .../io/iohk/atala/mercury/AgentCli.scala | 47 ++++++++++--------- .../io/iohk/atala/mercury/ZioHttpClient.scala | 8 ++-- .../service/HttpURIDereferencerImpl.scala | 23 +++++---- .../agent/notification/WebhookPublisher.scala | 23 +++++---- .../agent/server/DidCommHttpServer.scala | 14 ++---- .../agent/server/http/ZioHttpClient.scala | 7 ++- 7 files changed, 65 insertions(+), 66 deletions(-) diff --git a/build.sbt b/build.sbt index 35e683dfed..ebbea32142 100644 --- a/build.sbt +++ b/build.sbt @@ -48,7 +48,7 @@ lazy val V = new { val zioConfig = "3.0.7" val zioLogging = "2.0.1" val zioJson = "0.3.0" - val zioHttp = "0.0.3" + val zioHttp = "3.0.0-RC2" val zioCatsInterop = "3.3.0" val zioMetricsConnector = "2.1.0" val zioMock = "1.0.0-RC11" @@ -57,8 +57,7 @@ lazy val V = new { // https://mvnrepository.com/artifact/io.circe/circe-core val circe = "0.14.6" - val tapir = "1.6.0" - val tapirLegacy = "1.2.3" // TODO: remove + val tapir = "1.6.4" val typesafeConfig = "1.4.2" val protobuf = "3.1.9" @@ -315,9 +314,7 @@ lazy val D_PrismAgent = new { val tapirSwaggerUiBundle = "com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % V.tapir val tapirJsonZio = "com.softwaremill.sttp.tapir" %% "tapir-json-zio" % V.tapir - // FIXME: using newest tapir (1.6.0) for this dependency needs refactoring, because it has transitive dependency on zio-http 3.0.0, - // if used all imports for zio.http will use ne newest version, which will break the compilation - val tapirZioHttpServer = "com.softwaremill.sttp.tapir" %% "tapir-zio-http-server" % V.tapirLegacy + val tapirZioHttpServer = "com.softwaremill.sttp.tapir" %% "tapir-zio-http-server" % V.tapir val tapirHttp4sServerZio = "com.softwaremill.sttp.tapir" %% "tapir-http4s-server-zio" % V.tapir val http4sBlazeServer = "org.http4s" %% "http4s-blaze-server" % "0.23.12" diff --git a/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/AgentCli.scala b/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/AgentCli.scala index 559b13b9b6..814d28c826 100644 --- a/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/AgentCli.scala +++ b/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/AgentCli.scala @@ -2,9 +2,7 @@ package io.iohk.atala.mercury import scala.jdk.CollectionConverters.* import zio.* - -import zio.http._ -import zio.http.model._ +import zio.http.{Header as _, *} import java.io.IOException import io.iohk.atala.QRcode import io.iohk.atala.mercury._ @@ -252,14 +250,15 @@ object AgentCli extends ZIOAppDefault { } yield () } - def webServer: HttpApp[DidOps & DidAgent & DIDResolver & HttpClient, Throwable] = { + private def webServer: App[DidOps & DidAgent & DIDResolver & HttpClient] = { val header = "content-type" -> MediaTypes.contentTypeEncrypted + val (expectedKey, expectedValue) = header + Http .collectZIO[Request] { - case req @ Method.POST -> !! - if req.headersAsList - .exists(h => h._1.toString.equalsIgnoreCase(header._1) && h._2.toString.equalsIgnoreCase(header._2)) => - req.body.asString + case req @ Method.POST -> Root + if req.rawHeader(expectedKey).fold(false) { _.equalsIgnoreCase(expectedValue) } => + val res = req.body.asString .catchNonFatalOrDie(ex => ZIO.fail(ParseResponse(ex))) .flatMap { data => webServerProgram(data).catchAll { ex => @@ -267,19 +266,21 @@ object AgentCli extends ZIOAppDefault { } } .map(str => Response.text(str)) - case Method.GET -> !! / "test" => ZIO.succeed(Response.text("Test ok!")) + + res + case Method.GET -> Root / "test" => ZIO.succeed(Response.text("Test ok!")) case req => - ZIO.logWarning(s"Recive a not DID Comm v2 messagem: ${req}") *> + ZIO.logWarning(s"Received a not DID Comm v2 message: ${req}") *> ZIO.succeed(Response.text(s"The request must be a POST to root with the Header $header")) } - + .mapError(throwable => Response.fromHttpError(HttpError.InternalServerError(cause = Some(throwable)))) } def startEndpoint: ZIO[DidOps & DidAgent & DIDResolver & HttpClient, IOException, Unit] = for { - _ <- Console.printLine("Setup a endpoint") + _ <- Console.printLine("Setup an endpoint") agentService <- ZIO.service[DidAgent] - defualtPort = UniversalDidResolver + defaultPort = UniversalDidResolver .resolve(agentService.id.value) .get() .getDidCommServices() @@ -287,18 +288,18 @@ object AgentCli extends ZIOAppDefault { .toSeq .headOption .map(s => s.getServiceEndpoint()) - .flatMap(e => URL.fromString(e).toOption) + .flatMap(e => URL.decode(e).toOption) .flatMap(_.port) - .getOrElse(8081) // defualt + .getOrElse(8081) // default - _ <- Console.printLine(s"Inserte endpoint port ($defualtPort defualt) for (http://localhost:port)") + _ <- Console.printLine(s"Insert endpoint port ($defaultPort default) for (http://localhost:port)") port <- Console.readLine.flatMap { - case "" => ZIO.succeed(defualtPort) - case str => ZIO.succeed(str.toIntOption.getOrElse(defualtPort)) + case "" => ZIO.succeed(defaultPort) + case str => ZIO.succeed(str.toIntOption.getOrElse(defaultPort)) } server = { - val config = ServerConfig(address = new java.net.InetSocketAddress(port)) - ServerConfig.live(config)(using Trace.empty) >>> Server.live + val config = Server.Config.default.copy(address = new java.net.InetSocketAddress(port)) + ZLayer.succeed(config) >>> Server.live } _ <- Server .serve(webServer) @@ -318,7 +319,7 @@ object AgentCli extends ZIOAppDefault { // ZIO.when(haveServiceEndpoint)( // ) _ <- Console.printLine("Enter the serviceEndpoint URL (defualt None) or port for http://localhost:port") serviceEndpoint <- Console.readLine.flatMap { - case "" => ZIO.succeed(None) // defualt + case "" => ZIO.succeed(None) // default case str if str.toIntOption.isDefined => ZIO.succeed(str.toIntOption.map(port => s"http://localhost:$port")) case str => ZIO.succeed(Some(str)) } @@ -460,8 +461,8 @@ object AgentCli extends ZIOAppDefault { connectionRequest = ConnectionRequest.fromMessage(msg).toOption.get // TODO .get _ <- ZIO.logInfo("Got ConnectionRequest: " + connectionRequest) _ <- ZIO.logInfo("Creating New PeerDID...") -// peer <- ZIO.succeed(PeerDID.makePeerDid(serviceEndpoint = serviceEndpoint)) TODO -// _ <- ZIO.logInfo(s"My new DID => $peer") + // peer <- ZIO.succeed(PeerDID.makePeerDid(serviceEndpoint = serviceEndpoint)) TODO + // _ <- ZIO.logInfo(s"My new DID => $peer") connectionResponse = ConnectionResponse.makeResponseFromRequest(msg).toOption.get // TODO .get msgToSend = connectionResponse.makeMessage _ <- MessagingService.send(msgToSend) diff --git a/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/ZioHttpClient.scala b/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/ZioHttpClient.scala index b4e768d55e..fec9e2b7d2 100644 --- a/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/ZioHttpClient.scala +++ b/mercury/mercury-library/agent-cli-didcommx/src/main/scala/io/iohk/atala/mercury/ZioHttpClient.scala @@ -1,10 +1,8 @@ package io.iohk.atala.mercury import zio._ -import zio.http._ -import zio.http.model.{Header => _, _} +import zio.http.{Header as _, *} import io.iohk.atala.mercury._ - object ZioHttpClient { val layer = ZLayer.succeed(new ZioHttpClient()) } @@ -22,7 +20,7 @@ class ZioHttpClient extends HttpClient { .map(body => HttpResponse( response.status.code, - response.headers.toSeq.map(h => Header(h.key.toString, h.value.toString)), + response.headers.map(h => Header(h.headerName, h.renderedValue)).toSeq, body ) ) @@ -46,7 +44,7 @@ class ZioHttpClient extends HttpClient { .map(body => HttpResponse( response.status.code, - response.headers.toSeq.map(h => Header(h.key.toString, h.value.toString)), + response.headers.map(h => Header(h.headerName, h.renderedValue)).toSeq, body ) ) diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/HttpURIDereferencerImpl.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/HttpURIDereferencerImpl.scala index 7f060f654d..5cc4060f1d 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/HttpURIDereferencerImpl.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/HttpURIDereferencerImpl.scala @@ -2,8 +2,7 @@ package io.iohk.atala.pollux.core.service import io.iohk.atala.pollux.core.service.URIDereferencerError.{ConnectionError, ResourceNotFound, UnexpectedError} import zio.http.* -import zio.http.model.* -import zio.{IO, ULayer, URLayer, ZIO, ZLayer} +import zio.* import java.net.URI @@ -12,13 +11,19 @@ class HttpURIDereferencerImpl(client: Client) extends URIDereferencer { override def dereference(uri: URI): IO[URIDereferencerError, String] = { val result: ZIO[Client, URIDereferencerError, String] = for { response <- Client.request(uri.toString).mapError(t => ConnectionError(t.getMessage)) - body <- response match - case Response(Status.Ok, _, body, _, None) => - body.asString.mapError(t => UnexpectedError(t.getMessage)) - case Response(Status.NotFound, _, _, _, None) => - ZIO.fail(ResourceNotFound(uri)) - case Response(_, _, _, _, httpError) => - ZIO.fail(UnexpectedError(s"HTTP response error: $httpError")) + body <- response.status match { + case Status.Ok => + response.body.asString.mapError(t => UnexpectedError(t.getMessage)) + case Status.NotFound if !response.status.isError => ZIO.fail(ResourceNotFound(uri)) + case _ if response.status.isError => + val err = response match { + case Response.GetError(error) => Some(error) + case _ => None + } + ZIO.fail(UnexpectedError(s"HTTP response error: $err")) + case _ => + ZIO.fail(UnexpectedError("Unknown error")) + } } yield body result.provide(ZLayer.succeed(client)) } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/notification/WebhookPublisher.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/notification/WebhookPublisher.scala index d817326570..c3d79d94a6 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/notification/WebhookPublisher.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/notification/WebhookPublisher.scala @@ -13,7 +13,6 @@ import io.iohk.atala.shared.models.WalletAccessContext import io.iohk.atala.shared.models.WalletId import zio.* import zio.http.* -import zio.http.model.* import zio.json.* class WebhookPublisher( @@ -24,10 +23,10 @@ class WebhookPublisher( private val config = appConfig.agent.webhookPublisher - private val baseHeaders = Headers.contentType(HeaderValues.applicationJson) + private val baseHeaders = Headers(Header.ContentType(MediaType.application.json)) private val globalWebhookBaseHeaders = config.apiKey - .map(key => Headers.bearerAuthorizationHeader(key)) + .map(key => Headers(Header.Authorization.Bearer(key))) .getOrElse(Headers.empty) private val parallelism = config.parallelism.getOrElse(1).max(1).min(10) @@ -85,7 +84,7 @@ class WebhookPublisher( val walletWebhookTargets = webhooks .map(i => i.url -> i.customHeaders) .map { case (url, headers) => - url -> headers.foldLeft(Headers.empty) { case (acc, (k, v)) => acc ++ Header(k, v) } + url -> headers.foldLeft(Headers.empty) { case (acc, (k, v)) => acc.addHeader(Header.Custom(k, v)) } } (walletWebhookTargets ++ globalWebhookTarget) .map { case (url, headers) => notifyWebhook(event, url.toString, headers) } @@ -105,15 +104,21 @@ class WebhookPublisher( ) .timeoutFail(new RuntimeException("Client request timed out"))(5.seconds) .mapError(t => UnexpectedError(s"Webhook request error: $t")) - resp <- response match - case Response(status, _, _, _, _) if status.isSuccess => - ZIO.unit - case Response(status, _, _, _, maybeHttpError) => + + resp <- + if response.status.isSuccess then ZIO.unit + else { + val err = response match { + case Response.GetError(error) => Some(error) + case _ => None + } ZIO.fail( UnexpectedError( - s"Unsuccessful webhook response: [status: $status] [error: ${maybeHttpError.getOrElse("none")}]" + s"Unsuccessful webhook response: [status: ${response.status} [error: ${err.getOrElse("none")}]" ) ) + + } } yield resp } } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/DidCommHttpServer.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/DidCommHttpServer.scala index 5039bbe05f..8cf7a05c83 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/DidCommHttpServer.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/DidCommHttpServer.scala @@ -23,16 +23,14 @@ import io.iohk.atala.resolvers.DIDResolver import io.iohk.atala.shared.models.WalletAccessContext import zio.* import zio.http.* -import zio.http.model.* - import java.util.UUID object DidCommHttpServer { def run(didCommServicePort: Int) = { val server = { - val config = ServerConfig(address = new java.net.InetSocketAddress(didCommServicePort)) - ServerConfig.live(config)(using Trace.empty) >>> Server.live + val config = Server.Config.default.copy(address = new java.net.InetSocketAddress(didCommServicePort)) + ZLayer.succeed(config) >>> Server.live } for { _ <- ZIO.logInfo(s"Server Started on port $didCommServicePort") @@ -48,12 +46,8 @@ object DidCommHttpServer { DIDResolver & DIDNonSecretStorage & AppConfig, Nothing ] = Http.collectZIO[Request] { - case req @ Method.POST -> !! - if req.headersAsList - .exists(h => - h.key.toString.equalsIgnoreCase("content-type") && - h.value.toString.equalsIgnoreCase(MediaTypes.contentTypeEncrypted) - ) => + case req @ Method.POST -> Root + if req.rawHeader("content-type").fold(false) { _.equalsIgnoreCase(MediaTypes.contentTypeEncrypted) } => val result = for { data <- req.body.asString.mapError(e => RequestBodyParsingError(e.getMessage)) _ <- webServerProgram(data) diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/ZioHttpClient.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/ZioHttpClient.scala index 7ab73e991c..060bd131f4 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/ZioHttpClient.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/ZioHttpClient.scala @@ -1,8 +1,7 @@ package io.iohk.atala.agent.server.http import zio._ -import zio.http._ -import zio.http.model.{Header => _, _} +import zio.http.{Header => _, *} import io.iohk.atala.mercury._ object ZioHttpClient { @@ -22,7 +21,7 @@ class ZioHttpClient extends HttpClient { .map(body => HttpResponse( response.status.code, - response.headers.toSeq.map(h => Header(h.key.toString, h.value.toString)), + response.headers.map(h => Header(h.headerName, h.renderedValue)).toSeq, body ) ) @@ -46,7 +45,7 @@ class ZioHttpClient extends HttpClient { .map(body => HttpResponse( response.status.code, - response.headers.toSeq.map(h => Header(h.key.toString, h.value.toString)), + response.headers.map(h => Header(h.headerName, h.renderedValue)).toSeq, body ) )