diff --git a/build.sbt b/build.sbt index d5a0c52d..654e6266 100644 --- a/build.sbt +++ b/build.sbt @@ -2,13 +2,13 @@ import sbt.Keys.libraryDependencies val logger: Logger = ConsoleLogger() -crossScalaVersions := Seq("2.12.10") +crossScalaVersions := Seq("2.12.10", "2.13.1") lazy val Versions = new { val gpb3Version = "3.11.1" - val grpcVersion = "1.26.0" - val circeVersion = "0.11.2" - val http4sVersion = "0.20.15" + val grpcVersion = "1.27.0" + val circeVersion = "0.13.0" + val http4sVersion = "0.21.1" val akkaHttp = "10.1.5" // DO NOT upgrade to 10.1.[67] - will cause https://github.com/scala/community-builds/issues/825 } @@ -110,8 +110,8 @@ lazy val core = (project in file("core")).settings( "io.grpc" % "grpc-core" % Versions.grpcVersion, "io.grpc" % "grpc-protobuf" % Versions.grpcVersion, "io.grpc" % "grpc-stub" % Versions.grpcVersion, - "org.typelevel" %% "cats-core" % "1.6.0", - "org.typelevel" %% "cats-effect" % "1.3.0", + "org.typelevel" %% "cats-core" % "2.1.1", + "org.typelevel" %% "cats-effect" % "2.1.1", "com.kailuowang" %% "mainecoon-core" % "0.6.4", "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2", "org.slf4j" % "jul-to-slf4j" % "1.7.26", @@ -176,5 +176,5 @@ def grpcExeFileName: String = { } val grpcArtifactId = "protoc-gen-grpc-java" -val grpcExeUrl = url(s"http://repo1.maven.org/maven2/io/grpc/$grpcArtifactId/${Versions.grpcVersion}/$grpcExeFileName") +val grpcExeUrl = url(s"https://repo1.maven.org/maven2/io/grpc/$grpcArtifactId/${Versions.grpcVersion}/$grpcExeFileName") val grpcExePath = SettingKey[xsbti.api.Lazy[File]]("grpcExePath") diff --git a/core-scalapb/src/main/scala/com/avast/grpc/jsonbridge/scalapb/ScalaPBServiceHandlers.scala b/core-scalapb/src/main/scala/com/avast/grpc/jsonbridge/scalapb/ScalaPBServiceHandlers.scala index 2ad6f77e..e93000bc 100644 --- a/core-scalapb/src/main/scala/com/avast/grpc/jsonbridge/scalapb/ScalaPBServiceHandlers.scala +++ b/core-scalapb/src/main/scala/com/avast/grpc/jsonbridge/scalapb/ScalaPBServiceHandlers.scala @@ -7,7 +7,7 @@ import cats.implicits._ import com.avast.grpc.jsonbridge.GrpcJsonBridge.GrpcMethodName import com.avast.grpc.jsonbridge.ReflectionGrpcJsonBridge.{HandlerFunc, ServiceHandlers} import com.avast.grpc.jsonbridge.{BridgeError, JavaGenericHelper, ReflectionGrpcJsonBridge} -import com.fasterxml.jackson.core.{JsonParseException, JsonProcessingException} +import com.fasterxml.jackson.core.JsonProcessingException import com.typesafe.scalalogging.StrictLogging import io.grpc._ import io.grpc.protobuf.ProtoFileDescriptorSupplier @@ -22,7 +22,7 @@ import scala.util.control.NonFatal import scala.util.{Failure, Success} private[jsonbridge] object ScalaPBServiceHandlers extends ServiceHandlers with StrictLogging { - def createServiceHandlers[F[+ _]](ec: ExecutionContext)(inProcessChannel: ManagedChannel)(ssd: ServerServiceDefinition)( + def createServiceHandlers[F[_]](ec: ExecutionContext)(inProcessChannel: ManagedChannel)(ssd: ServerServiceDefinition)( implicit F: Async[F]): Map[GrpcMethodName, HandlerFunc[F]] = { if (ssd.getServiceDescriptor.getName == "grpc.reflection.v1alpha.ServerReflection") { logger.debug("Reflection endpoint service cannot be bridged because its implementation is not ScalaPB-based") @@ -86,7 +86,7 @@ private[jsonbridge] object ScalaPBServiceHandlers extends ServiceHandlers with S Seq(servicePackage + "." + fileNameWithoutExtension + "." + serviceName + "Grpc$", servicePackage + "." + serviceName + "Grpc$") } - private def createHandler[F[+ _]](ec: ExecutionContext)(futureStubCtor: () => AbstractStub[_])(method: ServerMethodDefinition[_, _])( + private def createHandler[F[_]](ec: ExecutionContext)(futureStubCtor: () => AbstractStub[_])(method: ServerMethodDefinition[_, _])( implicit F: Async[F]): (GrpcMethodName, HandlerFunc[F]) = { val requestCompanion = getRequestCompanion(method) val requestClass = Class.forName(requestCompanion.getClass.getName.stripSuffix("$")) @@ -144,7 +144,7 @@ private[jsonbridge] object ScalaPBServiceHandlers extends ServiceHandlers with S companionField.get(requestMarshaller).asInstanceOf[GeneratedMessageCompanion[_]] } - private def fromScalaFuture[F[+ _], A](ec: ExecutionContext)(fsf: F[Future[A]])(implicit F: Async[F]): F[A] = fsf.flatMap { sf => + private def fromScalaFuture[F[_], A](ec: ExecutionContext)(fsf: F[Future[A]])(implicit F: Async[F]): F[A] = fsf.flatMap { sf => F.async { cb => sf.onComplete { case Success(r) => cb(Right(r)) diff --git a/core/src/main/scala/com/avast/grpc/jsonbridge/JavaServiceHandlers.scala b/core/src/main/scala/com/avast/grpc/jsonbridge/JavaServiceHandlers.scala index abe1d7c8..cdf38441 100644 --- a/core/src/main/scala/com/avast/grpc/jsonbridge/JavaServiceHandlers.scala +++ b/core/src/main/scala/com/avast/grpc/jsonbridge/JavaServiceHandlers.scala @@ -25,7 +25,7 @@ private[jsonbridge] object JavaServiceHandlers extends ServiceHandlers with Stri JsonFormat.printer().includingDefaultValueFields().omittingInsignificantWhitespace() } - def createServiceHandlers[F[+ _]](ec: ExecutionContext)(inProcessChannel: ManagedChannel)(ssd: ServerServiceDefinition)( + def createServiceHandlers[F[_]](ec: ExecutionContext)(inProcessChannel: ManagedChannel)(ssd: ServerServiceDefinition)( implicit F: Async[F]): Map[GrpcMethodName, HandlerFunc[F]] = { val futureStubCtor = createFutureStubCtor(ssd.getServiceDescriptor, inProcessChannel) ssd.getMethods.asScala @@ -42,7 +42,7 @@ private[jsonbridge] object JavaServiceHandlers extends ServiceHandlers with Stri method.invoke(null, inProcessChannel).asInstanceOf[AbstractStub[_]] } - private def createHandler[F[+ _]](ec: ExecutionContext)(futureStubCtor: () => AbstractStub[_])(method: ServerMethodDefinition[_, _])( + private def createHandler[F[_]](ec: ExecutionContext)(futureStubCtor: () => AbstractStub[_])(method: ServerMethodDefinition[_, _])( implicit F: Async[F]): (GrpcMethodName, HandlerFunc[F]) = { val requestMessagePrototype = getRequestMessagePrototype(method) val javaMethod = futureStubCtor().getClass @@ -62,7 +62,7 @@ private[jsonbridge] object JavaServiceHandlers extends ServiceHandlers with Stri methodName.substring(0, 1).toLowerCase + methodName.substring(1) } - private def coreHandler[F[+ _]](requestMessagePrototype: Message, execute: (Message, Map[String, String]) => F[MessageOrBuilder])( + private def coreHandler[F[_]](requestMessagePrototype: Message, execute: (Message, Map[String, String]) => F[MessageOrBuilder])( implicit F: Async[F]): HandlerFunc[F] = { (json, headers) => { parseRequest(json, requestMessagePrototype) match { @@ -86,7 +86,7 @@ private[jsonbridge] object JavaServiceHandlers extends ServiceHandlers with Stri } } - private def executeRequest[F[+ _]](ec: ExecutionContext)(futureStubCtor: () => AbstractStub[_], javaMethod: Method)( + private def executeRequest[F[_]](ec: ExecutionContext)(futureStubCtor: () => AbstractStub[_], javaMethod: Method)( req: Message, headers: Map[String, String])(implicit F: Async[F]): F[MessageOrBuilder] = { val metaData = { @@ -107,7 +107,7 @@ private[jsonbridge] object JavaServiceHandlers extends ServiceHandlers with Stri requestBuilder.build() } - private def fromListenableFuture[F[+ _], A](ec: ExecutionContext)(flf: F[ListenableFuture[A]])(implicit F: Async[F]): F[A] = flf.flatMap { + private def fromListenableFuture[F[_], A](ec: ExecutionContext)(flf: F[ListenableFuture[A]])(implicit F: Async[F]): F[A] = flf.flatMap { lf => F.async { cb => Futures.addCallback(lf, new FutureCallback[A] { diff --git a/core/src/main/scala/com/avast/grpc/jsonbridge/ReflectionGrpcJsonBridge.scala b/core/src/main/scala/com/avast/grpc/jsonbridge/ReflectionGrpcJsonBridge.scala index 49e8818c..62130a0e 100644 --- a/core/src/main/scala/com/avast/grpc/jsonbridge/ReflectionGrpcJsonBridge.scala +++ b/core/src/main/scala/com/avast/grpc/jsonbridge/ReflectionGrpcJsonBridge.scala @@ -1,6 +1,7 @@ package com.avast.grpc.jsonbridge import cats.effect._ +import cats.syntax.all._ import com.avast.grpc.jsonbridge.GrpcJsonBridge.GrpcMethodName import com.avast.grpc.jsonbridge.ReflectionGrpcJsonBridge.{HandlerFunc, ServiceHandlers} import com.typesafe.scalalogging.StrictLogging @@ -10,14 +11,14 @@ import io.grpc.inprocess.{InProcessChannelBuilder, InProcessServerBuilder} import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext -import scala.language.{existentials, higherKinds} +import scala.language.higherKinds object ReflectionGrpcJsonBridge extends ReflectionGrpcJsonBridge(JavaServiceHandlers) { // JSON body and headers to a response (fail status or JSON response) - type HandlerFunc[F[+ _]] = (String, Map[String, String]) => F[Either[BridgeError.Narrow, String]] + type HandlerFunc[F[_]] = (String, Map[String, String]) => F[Either[BridgeError.Narrow, String]] trait ServiceHandlers { - def createServiceHandlers[F[+ _]](ec: ExecutionContext)(inProcessChannel: ManagedChannel)(ssd: ServerServiceDefinition)( + def createServiceHandlers[F[_]](ec: ExecutionContext)(inProcessChannel: ManagedChannel)(ssd: ServerServiceDefinition)( implicit F: Async[F]): Map[GrpcMethodName, HandlerFunc[F]] } @@ -26,11 +27,11 @@ object ReflectionGrpcJsonBridge extends ReflectionGrpcJsonBridge(JavaServiceHand private[jsonbridge] class ReflectionGrpcJsonBridge(serviceHandlers: ServiceHandlers) extends StrictLogging { - def createFromServer[F[+ _]](ec: ExecutionContext)(grpcServer: io.grpc.Server)(implicit F: Async[F]): Resource[F, GrpcJsonBridge[F]] = { + def createFromServer[F[_]](ec: ExecutionContext)(grpcServer: io.grpc.Server)(implicit F: Async[F]): Resource[F, GrpcJsonBridge[F]] = { createFromServices(ec)(grpcServer.getImmutableServices.asScala: _*) } - def createFromServices[F[+ _]](ec: ExecutionContext)(services: ServerServiceDefinition*)( + def createFromServices[F[_]](ec: ExecutionContext)(services: ServerServiceDefinition*)( implicit F: Async[F]): Resource[F, GrpcJsonBridge[F]] = { for { inProcessServiceName <- Resource.liftF(F.delay { s"ReflectionGrpcJsonBridge-${System.nanoTime()}" }) @@ -43,14 +44,14 @@ private[jsonbridge] class ReflectionGrpcJsonBridge(serviceHandlers: ServiceHandl } yield bridge } - def createFromHandlers[F[+ _]](handlersPerMethod: Map[GrpcMethodName, HandlerFunc[F]])(implicit F: Async[F]): GrpcJsonBridge[F] = { + def createFromHandlers[F[_]](handlersPerMethod: Map[GrpcMethodName, HandlerFunc[F]])(implicit F: Async[F]): GrpcJsonBridge[F] = { new GrpcJsonBridge[F] { override def invoke(methodName: GrpcJsonBridge.GrpcMethodName, body: String, headers: Map[String, String]): F[Either[BridgeError, String]] = handlersPerMethod.get(methodName) match { - case Some(handler) => handler(body, headers) + case Some(handler) => handler(body, headers).map(x => x: Either[BridgeError, String]) case None => F.pure(Left(BridgeError.GrpcMethodNotFound)) } @@ -62,7 +63,7 @@ private[jsonbridge] class ReflectionGrpcJsonBridge(serviceHandlers: ServiceHandl } } - private def createInProcessServer[F[+ _]](ec: ExecutionContext)(inProcessServiceName: String, services: Seq[ServerServiceDefinition])( + private def createInProcessServer[F[_]](ec: ExecutionContext)(inProcessServiceName: String, services: Seq[ServerServiceDefinition])( implicit F: Sync[F]): Resource[F, Server] = Resource { F.delay { @@ -73,12 +74,12 @@ private[jsonbridge] class ReflectionGrpcJsonBridge(serviceHandlers: ServiceHandl } } - private def createInProcessChannel[F[+ _]](ec: ExecutionContext)(inProcessServiceName: String)( + private def createInProcessChannel[F[_]](ec: ExecutionContext)(inProcessServiceName: String)( implicit F: Sync[F]): Resource[F, ManagedChannel] = Resource[F, ManagedChannel] { F.delay { val c = InProcessChannelBuilder.forName(inProcessServiceName).executor(ec.execute(_)).build() - (c, F.delay { c.shutdown() }) + (c, F.delay { val _ = c.shutdown() }) } } diff --git a/http4s/src/main/scala/com/avast/grpc/jsonbridge/http4s/Http4s.scala b/http4s/src/main/scala/com/avast/grpc/jsonbridge/http4s/Http4s.scala index f591f10a..b074c9d0 100644 --- a/http4s/src/main/scala/com/avast/grpc/jsonbridge/http4s/Http4s.scala +++ b/http4s/src/main/scala/com/avast/grpc/jsonbridge/http4s/Http4s.scala @@ -1,9 +1,9 @@ package com.avast.grpc.jsonbridge.http4s -import cats.Applicative import cats.data.NonEmptyList import cats.effect._ import cats.syntax.all._ +import cats._ import com.avast.grpc.jsonbridge.GrpcJsonBridge.GrpcMethodName import com.avast.grpc.jsonbridge.{BridgeError, BridgeErrorResponse, GrpcJsonBridge} import com.typesafe.scalalogging.LazyLogging @@ -15,7 +15,7 @@ import org.http4s.dsl.Http4sDsl import org.http4s.dsl.impl.EntityResponseGenerator import org.http4s.headers.{`Content-Type`, `WWW-Authenticate`} import org.http4s.server.middleware.{CORS, CORSConfig} -import org.http4s.{Challenge, EntityEncoder, Header, Headers, HttpRoutes, MediaType, Response, Status} +import org.http4s._ import scala.language.{higherKinds, implicitConversions} @@ -108,6 +108,10 @@ object Http4s extends LazyLogging { private def mapStatus[F[_]: Sync](s: GrpcStatus, configuration: Configuration)(implicit h: Http4sDsl[F]): F[Response[F]] = { import h._ + val ClientClosedRequest = Status(499, "Client Closed Request") + final case class ClientClosedRequestOps(status: ClientClosedRequest.type) extends EntityResponseGenerator[F, F] { + val liftG: F ~> F = h.liftG + } val description = BridgeErrorResponse.fromGrpcStatus(s) @@ -133,9 +137,6 @@ object Http4s extends LazyLogging { } } - val ClientClosedRequest = Status(499, "Client Closed Request") - final case class ClientClosedRequestOps[F[_], G[_]](status: ClientClosedRequest.type) extends AnyVal with EntityResponseGenerator[F, G] - private implicit def grpcStatusJsonEntityEncoder[F[_]: Applicative]: EntityEncoder[F, BridgeErrorResponse] = jsonEncoderOf[F, BridgeErrorResponse] } diff --git a/project/build.properties b/project/build.properties index c0bab049..a919a9b5 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.8 +sbt.version=1.3.8