diff --git a/build.sbt b/build.sbt index 8aea6a0..1748a30 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ val scalapbVersion = "0.10.2" lazy val codeGen = project .in(file("code-gen")) .settings( - name := "grpc-web-code-gen-with-metadata", + name := "grpc-web-code-gen", libraryDependencies ++= Seq( "com.thesamet.scalapb" %% "compilerplugin" % scalapbVersion ) @@ -25,7 +25,7 @@ lazy val root = project "com.thesamet.scalapb" %%% "protobuf-runtime-scala" % "0.8.5" ), npmDependencies in Compile += "grpc-web" -> "1.0.7" - ).dependsOn(codeGen).aggregate(codeGen) + ).aggregate(codeGen) inThisBuild( List( diff --git a/code-gen/src/main/scala-2.12/scalapb/grpc/web/compat.scala b/code-gen/src/main/scala-2.12/scalapb/grpc/web/compat.scala index 98173bb..fc9e47d 100644 --- a/code-gen/src/main/scala-2.12/scalapb/grpc/web/compat.scala +++ b/code-gen/src/main/scala-2.12/scalapb/grpc/web/compat.scala @@ -1,5 +1,5 @@ package scalapb.grpc_web object compat { - val JavaConverters = collection.JavaConverters -} \ No newline at end of file + val JavaConverters = collection.JavaConverters +} diff --git a/code-gen/src/main/scala/scalapb/grpc_web/GrpcServiceMetadataPrinter.scala b/code-gen/src/main/scala/scalapb/grpc_web/GrpcServiceMetadataPrinter.scala index 8a7afc1..98a6b5c 100644 --- a/code-gen/src/main/scala/scalapb/grpc_web/GrpcServiceMetadataPrinter.scala +++ b/code-gen/src/main/scala/scalapb/grpc_web/GrpcServiceMetadataPrinter.scala @@ -6,36 +6,36 @@ import scalapb.compiler.ProtobufGenerator.asScalaDocBlock import scalapb.compiler._ import scalapb.grpc_web.compat.JavaConverters._ +final class GrpcServiceMetadataPrinter( + service: ServiceDescriptor, + implicits: DescriptorImplicits +) { -final class GrpcServiceMetadataPrinter(service: ServiceDescriptor, implicits: DescriptorImplicits) { import implicits._ - private[this] def observer(typeParam: String): String = s"$streamObserver[$typeParam]" - private[this] def serviceMethodSignature(method: MethodDescriptor, overrideSig: Boolean) = { + private[this] def observer(typeParam: String): String = + s"$streamObserver[$typeParam]" + + private[this] def serviceMethodSignature( + method: MethodDescriptor, + overrideSig: Boolean + ) = { val overrideStr = if (overrideSig) "override " else "" - method.streamType match { + method.streamType match { case StreamType.Unary => s"${method.deprecatedAnnotation}${overrideStr}def ${method.name}" + s"(request: ${method.inputType.scalaType}, metadata: $metadata): scala.concurrent.Future[${method.outputType.scalaType}]" case StreamType.ServerStreaming => - s"${method.deprecatedAnnotation}${overrideStr}def ${method.name}" + s"(request: ${method.inputType.scalaType}, metadata: $metadata, responseObserver: ${observer(method.outputType.scalaType)}): Unit" + s"${method.deprecatedAnnotation}${overrideStr}def ${method.name}" + s"(request: ${method.inputType.scalaType}, metadata: $metadata, responseObserver: ${observer( + method.outputType.scalaType)}): Unit" case _ => "" } - -// s"${method.deprecatedAnnotation}${overrideStr}def ${method.name}" + (method.streamType match { -// case StreamType.Unary => -// s"(request: ${method.inputType.scalaType}, metadata: $metadata): scala.concurrent.Future[${method.outputType.scalaType}]" -// case StreamType.ClientStreaming => -// s"(responseObserver: ${observer(method.outputType.scalaType)}): ${observer(method.inputType.scalaType)}" -// case StreamType.ServerStreaming => -// s"(request: ${method.inputType.scalaType}, metadata: $metadata, responseObserver: ${observer(method.outputType.scalaType)}): Unit" -// case StreamType.Bidirectional => -// s"(responseObserver: ${observer(method.outputType.scalaType)}): ${observer(method.inputType.scalaType)}" -// }) - } - private[this] def blockingMethodSignature(method: MethodDescriptor, overrideSig: Boolean) = { + private[this] def blockingMethodSignature( + method: MethodDescriptor, + overrideSig: Boolean + ) = { val overrideStr = if (overrideSig) "override " else "" s"${method.deprecatedAnnotation}${overrideStr}def ${method.name}" + (method.streamType match { case StreamType.Unary => @@ -52,38 +52,54 @@ final class GrpcServiceMetadataPrinter(service: ServiceDescriptor, implicits: De .indent .print(service.methods) { case (p, method) => - p.call(generateScalaDoc(method)).add(serviceMethodSignature(method, overrideSig = false)) + p.call(generateScalaDoc(method)) + .add(serviceMethodSignature(method, overrideSig = false)) } .outdent .add("}") } - - private[this] def blockingClientTrait: PrinterEndo = { p => - p.call(generateScalaDoc(service)) - .add(s"trait ${service.blockingClient} {") - .indent - .print(service.methods.filter(_.canBeBlocking)) { - case (p, method) => - p.call(generateScalaDoc(method)).add(blockingMethodSignature(method, overrideSig = false)) - } - .outdent - .add("}") - } - - private[this] val channel = "_root_.io.grpc.Channel" + private[this] val channel = "_root_.io.grpc.Channel" private[this] val callOptions = "_root_.io.grpc.CallOptions" - private[this] val abstractStub = "_root_.io.grpc.stub.AbstractStub" + private[this] val abstractStub = "_root_.io.grpc.stub.AbstractStub" private[this] val streamObserver = "_root_.io.grpc.stub.StreamObserver" - private[this] val serverCalls = "_root_.io.grpc.stub.ServerCalls" private[this] val clientCalls = "_root_.scalapb.grpc.ClientCalls" - private[this] val serverServiceDef = "_root_.io.grpc.ServerServiceDefinition" - private[this] val executionContext = "executionContext" private[this] val metadata = "_root_.scalapb.grpc.grpcweb.Metadata.Metadata" + private[this] def methodDescriptor(method: MethodDescriptor) = PrinterEndo { + p => + def marshaller(t: MethodDescriptorPimp#MethodTypeWrapper) = + if (t.customScalaType.isDefined) + s"_root_.scalapb.grpc.Marshaller.forTypeMappedType[${t.baseScalaType}, ${t.scalaType}]" + else + s"_root_.scalapb.grpc.Marshaller.forMessage[${t.scalaType}]" + + val methodType = method.streamType match { + case StreamType.Unary => "UNARY" + case StreamType.ClientStreaming => "CLIENT_STREAMING" + case StreamType.ServerStreaming => "SERVER_STREAMING" + case StreamType.Bidirectional => "BIDI_STREAMING" + } + + val grpcMethodDescriptor = "_root_.io.grpc.MethodDescriptor" + + p.add( + s"""${method.deprecatedAnnotation}val ${method.grpcDescriptor.nameSymbol}: $grpcMethodDescriptor[${method.inputType.scalaType}, ${method.outputType.scalaType}] = + | $grpcMethodDescriptor.newBuilder() + | .setType($grpcMethodDescriptor.MethodType.$methodType) + | .setFullMethodName($grpcMethodDescriptor.generateFullMethodName("${service.getFullName}", "${method.getName}")) + | .setSampledToLocalTracing(true) + | .setRequestMarshaller(${marshaller(method.inputType)}) + | .setResponseMarshaller(${marshaller(method.outputType)}) + | .setSchemaDescriptor(_root_.scalapb.grpc.ConcreteProtoMethodDescriptorSupplier.fromMethodDescriptor(${method.javaDescriptorSource})) + | .build() + |""".stripMargin + ) + } + private[this] def clientMethodImpl(m: MethodDescriptor, blocking: Boolean) = { def printCall(p: FunctionalPrinter) = { val sig = @@ -99,10 +115,16 @@ final class GrpcServiceMetadataPrinter(service: ServiceDescriptor, implicits: De case StreamType.Bidirectional => "BidiStreamingCall" }) - val args = Seq("channel", m.grpcDescriptor.nameSymbol, "options", "metadata") ++ + val args = Seq( + "channel", + m.grpcDescriptor.nameSymbol, + "options", + "metadata" + ) ++ (if (m.isClientStreaming) Seq() else Seq("request")) ++ - (if ((m.isClientStreaming || m.isServerStreaming) && !blocking) Seq("responseObserver") - else Seq()) + (if ((m.isClientStreaming || m.isServerStreaming) && !blocking) + Seq("responseObserver") + else Seq()) val body = s"${clientCalls}.${methodName}(${args.mkString(", ")})" p.call(generateScalaDoc(m)).add(sig).addIndented(body).add("}").newline @@ -112,22 +134,22 @@ final class GrpcServiceMetadataPrinter(service: ServiceDescriptor, implicits: De m.streamType match { case StreamType.Unary => printCall(p) case StreamType.ServerStreaming => printCall(p) - case _ => p + case _ => p } } } private def stubImplementation( - className: String, - baseClass: String, - methods: Seq[PrinterEndo] - ): PrinterEndo = { p => + className: String, + baseClass: String, + methods: Seq[PrinterEndo] + ): PrinterEndo = { p => val build = s"override def build(channel: $channel, options: $callOptions): ${className} = new $className(channel, options)" p.add( - s"class $className(channel: $channel, options: $callOptions = $callOptions.DEFAULT) extends $abstractStub[$className](channel, options) with $baseClass {" - ) + s"class $className(channel: $channel, options: $callOptions = $callOptions.DEFAULT) extends $abstractStub[$className](channel, options) with $baseClass {" + ) .indent .call(methods: _*) .add(build) @@ -135,139 +157,30 @@ final class GrpcServiceMetadataPrinter(service: ServiceDescriptor, implicits: De .add("}") } - private[this] val stub: PrinterEndo = { - val methods = service.getMethods.asScala.map(clientMethodImpl(_, false)).toSeq + val methods = + service.getMethods.asScala.map(clientMethodImpl(_, false)).toSeq stubImplementation(service.stub, service.name, methods) } - private[this] def methodDescriptor(method: MethodDescriptor) = PrinterEndo { p => - def marshaller(t: MethodDescriptorPimp#MethodTypeWrapper) = - if (t.customScalaType.isDefined) - s"_root_.scalapb.grpc.Marshaller.forTypeMappedType[${t.baseScalaType}, ${t.scalaType}]" - else - s"_root_.scalapb.grpc.Marshaller.forMessage[${t.scalaType}]" - - val methodType = method.streamType match { - case StreamType.Unary => "UNARY" - case StreamType.ClientStreaming => "CLIENT_STREAMING" - case StreamType.ServerStreaming => "SERVER_STREAMING" - case StreamType.Bidirectional => "BIDI_STREAMING" - } - - val grpcMethodDescriptor = "_root_.io.grpc.MethodDescriptor" - - p.add( - s"""${method.deprecatedAnnotation}val ${method.grpcDescriptor.nameSymbol}: $grpcMethodDescriptor[${method.inputType.scalaType}, ${method.outputType.scalaType}] = - | $grpcMethodDescriptor.newBuilder() - | .setType($grpcMethodDescriptor.MethodType.$methodType) - | .setFullMethodName($grpcMethodDescriptor.generateFullMethodName("${service.getFullName}", "${method.getName}")) - | .setSampledToLocalTracing(true) - | .setRequestMarshaller(${marshaller(method.inputType)}) - | .setResponseMarshaller(${marshaller(method.outputType)}) - | .setSchemaDescriptor(_root_.scalapb.grpc.ConcreteProtoMethodDescriptorSupplier.fromMethodDescriptor(${method.javaDescriptorSource})) - | .build() - |""".stripMargin - ) - } - - private[this] def serviceDescriptor(service: ServiceDescriptor) = { - val grpcServiceDescriptor = "_root_.io.grpc.ServiceDescriptor" - - PrinterEndo( - _.add(s"val ${service.grpcDescriptor.nameSymbol}: $grpcServiceDescriptor =").indent - .add(s"""$grpcServiceDescriptor.newBuilder("${service.getFullName}")""") - .indent - .add( - s""".setSchemaDescriptor(new _root_.scalapb.grpc.ConcreteProtoFileDescriptorSupplier(${service.getFile.fileDescriptorObject.fullName}.javaDescriptor))""" - ) - .print(service.methods) { - case (p, method) => - p.add(s".addMethod(${method.grpcDescriptor.nameSymbol})") - } - .add(".build()") - .outdent - .outdent - .newline - ) - } - - private[this] def addMethodImplementation(method: MethodDescriptor): PrinterEndo = PrinterEndo { - _.add(".addMethod(") - .add(s" ${method.grpcDescriptor.nameSymbol},") - .indent - .call(PrinterEndo { p => - val call = method.streamType match { - case StreamType.Unary => s"$serverCalls.asyncUnaryCall" - case StreamType.ClientStreaming => s"$serverCalls.asyncClientStreamingCall" - case StreamType.ServerStreaming => s"$serverCalls.asyncServerStreamingCall" - case StreamType.Bidirectional => s"$serverCalls.asyncBidiStreamingCall" - } - - val serviceImpl = "serviceImpl" - - method.streamType match { - case StreamType.Unary => - val serverMethod = - s"$serverCalls.UnaryMethod[${method.inputType.scalaType}, ${method.outputType.scalaType}]" - p.add(s"""$call(new $serverMethod { - | override def invoke(request: ${method.inputType.scalaType}, observer: $streamObserver[${method.outputType.scalaType}]): Unit = - | $serviceImpl.${method.name}(request, _root_.scalapb.grpc.grpcweb.Metadata()).onComplete(scalapb.grpc.Grpc.completeObserver(observer))( - | $executionContext) - |}))""".stripMargin) - case StreamType.ServerStreaming => - val serverMethod = - s"$serverCalls.ServerStreamingMethod[${method.inputType.scalaType}, ${method.outputType.scalaType}]" - p.add(s"""$call(new $serverMethod { - | override def invoke(request: ${method.inputType.scalaType}, observer: $streamObserver[${method.outputType.scalaType}]): Unit = - | $serviceImpl.${method.name}(request, _root_.scalapb.grpc.grpcweb.Metadata(), observer) - |}))""".stripMargin) - case _ => - val serverMethod = if (method.streamType == StreamType.ClientStreaming) { - s"$serverCalls.ClientStreamingMethod[${method.inputType.scalaType}, ${method.outputType.scalaType}]" - } else { - s"$serverCalls.BidiStreamingMethod[${method.inputType.scalaType}, ${method.outputType.scalaType}]" - } - p.add(s"""$call(new $serverMethod { - | override def invoke(observer: $streamObserver[${method.outputType.scalaType}]): $streamObserver[${method.inputType.scalaType}] = - | $serviceImpl.${method.name}(observer) - |}))""".stripMargin) - } - }) - .outdent - } - - private[this] val bindService = { - val methods = service.methods.map(addMethodImplementation) - - PrinterEndo( - _.add( - s"""def bindService(serviceImpl: ${service.name}, $executionContext: scala.concurrent.ExecutionContext): $serverServiceDef =""" - ).indent - .add(s"""$serverServiceDef.builder(${service.grpcDescriptor.nameSymbol})""") - .call(methods: _*) - .add(".build()") - .outdent - ) - } - def printService(printer: FunctionalPrinter): FunctionalPrinter = { printer .add( "package " + service.getFile.scalaPackage.fullName, "", - s"${service.deprecatedAnnotation}object ${service.companionObject.nameSymbol}WithMetadata {" + s"${service.deprecatedAnnotation}object ${service.companionObject.nameSymbol}{" ) .indent .call(service.methods.map(methodDescriptor): _*) - .call(serviceDescriptor(service)) .call(serviceTrait) .newline .newline .call(stub) .newline .newline - .add(s"def stub(channel: $channel): ${service.stub} = new ${service.stub}(channel)") + .add( + s"def stub(channel: $channel): ${service.stub} = new ${service.stub}(channel)" + ) .newline .add( s"def javaDescriptor: _root_.com.google.protobuf.Descriptors.ServiceDescriptor = ${service.javaDescriptorSource}" @@ -278,12 +191,16 @@ final class GrpcServiceMetadataPrinter(service: ServiceDescriptor, implicits: De } def generateScalaDoc(service: ServiceDescriptor): PrinterEndo = { fp => - val lines = asScalaDocBlock(service.comment.map(_.split('\n').toSeq).getOrElse(Seq.empty)) + val lines = asScalaDocBlock( + service.comment.map(_.split('\n').toSeq).getOrElse(Seq.empty) + ) fp.add(lines: _*) } def generateScalaDoc(method: MethodDescriptor): PrinterEndo = { fp => - val lines = asScalaDocBlock(method.comment.map(_.split('\n').toSeq).getOrElse(Seq.empty)) + val lines = asScalaDocBlock( + method.comment.map(_.split('\n').toSeq).getOrElse(Seq.empty) + ) fp.add(lines: _*) } } diff --git a/code-gen/src/main/scala/scalapb/grpc_web/GrpcWebCodeGenerator.scala b/code-gen/src/main/scala/scalapb/grpc_web/GrpcWebCodeGenerator.scala new file mode 100644 index 0000000..01c1566 --- /dev/null +++ b/code-gen/src/main/scala/scalapb/grpc_web/GrpcWebCodeGenerator.scala @@ -0,0 +1,90 @@ +package scalapb.grpc_web + +import com.google.protobuf.Descriptors.FileDescriptor +import com.google.protobuf.ExtensionRegistry +import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse +import protocbridge.codegen.{CodeGenApp, CodeGenRequest, CodeGenResponse} +import scalapb.compiler.{ + DescriptorImplicits, + FunctionalPrinter, + GeneratorException, + GeneratorParams, + NameUtils, + ProtoValidation, + ProtobufGenerator +} +import scalapb.grpc_web.compat.JavaConverters._ +import scalapb.options.compiler.Scalapb + +case class GrpcWebCodeGenerator(metadata: Boolean = false) extends CodeGenApp { + override def registerExtensions(registry: ExtensionRegistry): Unit = + Scalapb.registerAllExtensions(registry) + + def process(request: CodeGenRequest): CodeGenResponse = { + ProtobufGenerator.parseParameters(request.parameter) match { + case Right(params) => + try { + val implicits = + new DescriptorImplicits(params, request.allProtos) + validate(request, implicits) + val generatedFiles = request.filesToGenerate.flatMap { file => + if (metadata) { + generateWithMetadata(params, file, implicits) + } else { + generate(params, file, implicits) + } + } + CodeGenResponse.succeed( + generatedFiles + ) + } catch { + case e: GeneratorException => + CodeGenResponse.fail(e.message) + } + case Left(error) => + CodeGenResponse.fail(error) + } + + } + + private def validate(request: CodeGenRequest, implicits: DescriptorImplicits) + : Map[FileDescriptor, Scalapb.ScalaPbOptions] = { + val validator = new ProtoValidation(implicits) + validator.validateFiles(request.allProtos) + } + + private def generate( + params: GeneratorParams, + file: FileDescriptor, + implicits: DescriptorImplicits): Seq[CodeGeneratorResponse.File] = { + val generator = new ProtobufGenerator(params.copy(grpc = true), implicits) + generator.generateMultipleScalaFilesForFileDescriptor(file) + } + + private def generateWithMetadata( + params: GeneratorParams, + file: FileDescriptor, + implicits: DescriptorImplicits): Seq[CodeGeneratorResponse.File] = { + val serviceFiles = generateServiceFiles(file, implicits) + val generator = new ProtobufGenerator(params, implicits) + val allOtherTypes = + generator.generateMultipleScalaFilesForFileDescriptor(file) + serviceFiles ++ allOtherTypes + } + + private def generateServiceFiles( + file: FileDescriptor, + implicits: DescriptorImplicits): Seq[CodeGeneratorResponse.File] = { + import implicits._ + file.getServices.asScala.map { service => + val p = new GrpcServiceMetadataPrinter(service, implicits) + val code = p.printService(FunctionalPrinter()).result() + val b = CodeGeneratorResponse.File.newBuilder() + b.setName( + file.scalaDirectory + "/" + service.companionObject.name + ".scala") + b.setContent(code) + b.build + }.toSeq + } + +} diff --git a/code-gen/src/main/scala/scalapb/grpc_web/GrpcWebWithMetadataCodeGenerator.scala b/code-gen/src/main/scala/scalapb/grpc_web/GrpcWebWithMetadataCodeGenerator.scala deleted file mode 100644 index 0298fa9..0000000 --- a/code-gen/src/main/scala/scalapb/grpc_web/GrpcWebWithMetadataCodeGenerator.scala +++ /dev/null @@ -1,59 +0,0 @@ -package scalapb.grpc_web - -import com.google.protobuf.Descriptors.FileDescriptor -import com.google.protobuf.ExtensionRegistry -import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse -import protocbridge.codegen.{CodeGenApp, CodeGenRequest, CodeGenResponse} -import scalapb.compiler.{DescriptorImplicits, FunctionalPrinter, NameUtils, ProtobufGenerator} -import scalapb.options.compiler.Scalapb -import scalapb.grpc_web.compat.JavaConverters._ - -object GrpcWebWithMetadataCodeGenerator extends CodeGenApp { - override def registerExtensions(registry: ExtensionRegistry): Unit = - Scalapb.registerAllExtensions(registry) - - def process(request: CodeGenRequest): CodeGenResponse = { - ProtobufGenerator.parseParameters(request.parameter) match { - case Right(params) => - val implicits = - new DescriptorImplicits(params, request.allProtos) - CodeGenResponse.succeed( - request.filesToGenerate - .collect { - case file if !file.getServices.isEmpty => - new MetadataFilePrinter(implicits, file).result() - } - ) - case Left(error) => - CodeGenResponse.fail(error) - } - } -} - -class MetadataFilePrinter( - implicits: DescriptorImplicits, - file: FileDescriptor -) { - import implicits._ - - private val OuterObject = - file.scalaPackage / s"${NameUtils.snakeCaseToCamelCase(baseName(file.getName), true)}GrpcWithMetaData" - - def scalaFileName: String = - OuterObject.fullName.replace('.', '/') + ".scala" - - def content: String = { - val fp = new FunctionalPrinter() - fp.print(file.getServices.asScala)((fp, s) => - new GrpcServiceMetadataPrinter(s,implicits).printService(fp) - ).result() - } - - def result(): CodeGeneratorResponse.File = { - val b = CodeGeneratorResponse.File.newBuilder() - b.setName(scalaFileName) - b.setContent(content) - b.build() - } - -} diff --git a/example2/build.sbt b/example2/build.sbt index 3ea9aed..dc99fe9 100644 --- a/example2/build.sbt +++ b/example2/build.sbt @@ -11,11 +11,10 @@ resolvers in ThisBuild ++= Seq( Resolver.sonatypeRepo("snapshots"), Resolver.sonatypeRepo("releases") ) -// This is a generator for metadata support -lazy val addSettings : Seq[Setting[_]] = Seq( +// js settings with attribute metadata true in GrpcWebCodeGenerator +lazy val jsSettings : Seq[Setting[_]] = Seq( PB.targets in Compile := Seq( - scalapb.gen() -> (sourceManaged in Compile).value, - scalapb.grpc_web.GrpcWebWithMetadataCodeGenerator -> (sourceManaged in Compile).value)) + scalapb.grpc_web.GrpcWebCodeGenerator(true) -> (sourceManaged in Compile).value)) lazy val protos = crossProject(JSPlatform, JVMPlatform) @@ -35,10 +34,10 @@ lazy val protos = ) .jsSettings( // publish locally and update the version for test - libraryDependencies += "com.thesamet.scalapb" %%% "scalapb-grpcweb" % "0.2.0+13-6851bb06+20200422-1144-SNAPSHOT" + libraryDependencies += "com.thesamet.scalapb" %%% "scalapb-grpcweb" % "0.2.0+15-1ed77e30+20200427-2143-SNAPSHOT" ) -lazy val protosJS = protos.js.settings(addSettings : _*) +lazy val protosJS = protos.js.settings(jsSettings : _*) lazy val protosJVM = protos.jvm lazy val client = diff --git a/example2/client/src/main/scala/scalapb/grpc/example/Client.scala b/example2/client/src/main/scala/scalapb/grpc/example/Client.scala index b0a0c57..06474e3 100644 --- a/example2/client/src/main/scala/scalapb/grpc/example/Client.scala +++ b/example2/client/src/main/scala/scalapb/grpc/example/Client.scala @@ -6,43 +6,48 @@ import scalapb.grpc.grpcweb.Metadata import scalapb.grpc.grpcweb.Metadata.Metadata import scalapb.web.myservice.TestServiceGrpc import scalapb.web.myservice.{Req, Res} - import scala.concurrent.ExecutionContext.Implicits.global -import scalapb.web.myservice.TestServiceGrpcWithMetadata -class GrpcError(code: String, message: String) extends RuntimeException(s"Grpc-web error ${code}: ${message}") + +class GrpcError(code: String, message: String) + extends RuntimeException(s"Grpc-web error ${code}: ${message}") object Client { def main(args: Array[String]): Unit = { println("Hello world!") - val stub = TestServiceGrpcWithMetadata.stub(Channels.grpcwebChannel("http://localhost:8080")) + val stub = + TestServiceGrpc.stub(Channels.grpcwebChannel("http://localhost:8080")) - val req = Req(payload="Hello!", vals=Seq(-4000, -1, 17, 39, 4175)) + val req = Req(payload = "Hello!", vals = Seq(-4000, -1, 17, 39, 4175)) // val req = Req(payload="error", vals=Seq(-4000, -1, 17, 39, 4175)) val header1 = Seq("custom-header-1" -> "unary-value") - val header2 = Seq("custom-header-2" -> "server-streaming-value") + val header2 = Seq("custom-header-1" -> "server-streaming-value") val metadata: Metadata = Metadata(header1) // Make an async unary call - stub.unary(req,metadata).onComplete { - f => println("Unary", f) + stub.unary(req, metadata).onComplete { f => + println("Unary", f) } val metadata2: Metadata = Metadata(header2) // Make an async server streaming call - stub.serverStreaming(req,metadata2, new StreamObserver[Res] { - override def onNext(value: Res): Unit = { - println("Next: " + value) - } - - override def onError(throwable: Throwable): Unit = { - println("Error! " + throwable) - } - - override def onCompleted(): Unit = { - println("Completed!") + stub.serverStreaming( + req, + metadata2, + new StreamObserver[Res] { + override def onNext(value: Res): Unit = { + println("Next: " + value) + } + + override def onError(throwable: Throwable): Unit = { + println("Error! " + throwable) + } + + override def onCompleted(): Unit = { + println("Completed!") + } } - }) + ) } } diff --git a/example2/project/plugins.sbt b/example2/project/plugins.sbt index 887230b..107af95 100644 --- a/example2/project/plugins.sbt +++ b/example2/project/plugins.sbt @@ -8,4 +8,4 @@ addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.17.0") libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.10.2" // publish locally and update the version for test -libraryDependencies += "com.thesamet.scalapb" %% "grpc-web-code-gen-with-metadata" % "0.2.0+13-6851bb06+20200422-1144-SNAPSHOT" +libraryDependencies += "com.thesamet.scalapb" %% "grpc-web-code-gen" % "0.2.0+15-1ed77e30+20200427-2143-SNAPSHOT" diff --git a/src/main/scala/scalapb/grpc/grpc.scala b/src/main/scala/scalapb/grpc/grpc.scala index b974c81..f2a3dc4 100644 --- a/src/main/scala/scalapb/grpc/grpc.scala +++ b/src/main/scala/scalapb/grpc/grpc.scala @@ -1,7 +1,13 @@ package scalapb.grpc import com.google.protobuf.Descriptors -import io.grpc.{CallOptions, Channel, MethodDescriptor, Status, StatusRuntimeException} +import io.grpc.{ + CallOptions, + Channel, + MethodDescriptor, + Status, + StatusRuntimeException +} import io.grpc.protobuf.ProtoFileDescriptorSupplier import io.grpc.protobuf.ProtoMethodDescriptorSupplier import io.grpc.stub.StreamObserver @@ -110,11 +116,11 @@ object ClientCalls { } def asyncUnaryCall[ReqT, RespT]( - channel: Channel, - method: MethodDescriptor[ReqT, RespT], - options: CallOptions, - request: ReqT - ): Future[RespT] = { + channel: Channel, + method: MethodDescriptor[ReqT, RespT], + options: CallOptions, + request: ReqT + ): Future[RespT] = { val metadata = Metadata.empty() val p = Promise[RespT] val handler: (grpcweb.ErrorInfo, RespT) => Unit = { @@ -135,24 +141,24 @@ object ClientCalls { } /** - * - * Overloaded method to support with Metadata - * @param channel - * @param method - * @param options - * @param metadata - * @param request - * @param responseObserver - * @tparam ReqT - * @tparam RespT - */ + * + * Overloaded method to support with Metadata + * @param channel + * @param method + * @param options + * @param metadata + * @param request + * @param responseObserver + * @tparam ReqT + * @tparam RespT + */ def asyncServerStreamingCall[ReqT, RespT]( channel: Channel, method: MethodDescriptor[ReqT, RespT], options: CallOptions, metadata: Metadata, request: ReqT, - responseObserver: StreamObserver[RespT], + responseObserver: StreamObserver[RespT] ): Unit = { channel.client .rpcCall( @@ -161,7 +167,9 @@ object ClientCalls { metadata, method.methodInfo ) - .on("data", { res: RespT => responseObserver.onNext(res) }) + .on("data", { res: RespT => + responseObserver.onNext(res) + }) .on( "status", { statusInfo: grpcweb.StatusInfo => if (statusInfo.code != 0) { @@ -178,16 +186,18 @@ object ClientCalls { responseObserver .onError(new StatusRuntimeException(Status.fromErrorInfo(errorInfo))) }) - .on("end", { _: Any => responseObserver.onCompleted() }) + .on("end", { _: Any => + responseObserver.onCompleted() + }) } def asyncServerStreamingCall[ReqT, RespT]( - channel: Channel, - method: MethodDescriptor[ReqT, RespT], - options: CallOptions, - request: ReqT, - responseObserver: StreamObserver[RespT], - ): Unit = { + channel: Channel, + method: MethodDescriptor[ReqT, RespT], + options: CallOptions, + request: ReqT, + responseObserver: StreamObserver[RespT] + ): Unit = { val metadata = Metadata.empty() channel.client .rpcCall(