io.grpc.Status Scala Examples
The following examples show how to use io.grpc.Status.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example.
Example 1
Source File: ApiLedgerIdentityService.scala From daml with Apache License 2.0 | 6 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.platform.apiserver.services import com.daml.dec.DirectExecutionContext import com.daml.ledger.api.domain.LedgerId import com.daml.ledger.api.v1.ledger_identity_service.LedgerIdentityServiceGrpc.{ LedgerIdentityService => GrpcLedgerIdentityService } import com.daml.ledger.api.v1.ledger_identity_service.{ GetLedgerIdentityRequest, GetLedgerIdentityResponse, LedgerIdentityServiceGrpc } import com.daml.logging.{ContextualizedLogger, LoggingContext} import com.daml.platform.api.grpc.GrpcApiService import com.daml.platform.server.api.ApiException import io.grpc.{BindableService, ServerServiceDefinition, Status} import scalaz.syntax.tag._ import scala.concurrent.Future final class ApiLedgerIdentityService private (getLedgerId: () => Future[LedgerId])( implicit logCtx: LoggingContext) extends GrpcLedgerIdentityService with GrpcApiService { @volatile var closed = false private val logger = ContextualizedLogger.get(this.getClass) override def getLedgerIdentity( request: GetLedgerIdentityRequest): Future[GetLedgerIdentityResponse] = if (closed) Future.failed( new ApiException( Status.UNAVAILABLE .withDescription("Ledger Identity Service closed."))) else { getLedgerId() .map(ledgerId => GetLedgerIdentityResponse(ledgerId.unwrap))(DirectExecutionContext) .andThen(logger.logErrorsOnCall[GetLedgerIdentityResponse])(DirectExecutionContext) } override def close(): Unit = closed = true override def bindService(): ServerServiceDefinition = LedgerIdentityServiceGrpc.bindService(this, DirectExecutionContext) } object ApiLedgerIdentityService { def create(getLedgerId: () => Future[LedgerId])( implicit logCtx: LoggingContext): ApiLedgerIdentityService with BindableService = { new ApiLedgerIdentityService(getLedgerId) } }
Example 2
Source File: AkkaDiscoveryNameResolver.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.internal import java.net.{ InetAddress, InetSocketAddress, UnknownHostException } import akka.discovery.ServiceDiscovery.ResolvedTarget import akka.discovery.{ Lookup, ServiceDiscovery } import akka.grpc.GrpcClientSettings import io.grpc.{ Attributes, EquivalentAddressGroup, NameResolver, Status } import io.grpc.NameResolver.Listener import scala.concurrent.duration.FiniteDuration import scala.concurrent.{ ExecutionContext, Promise } import scala.util.{ Failure, Success } class AkkaDiscoveryNameResolver( discovery: ServiceDiscovery, defaultPort: Int, serviceName: String, portName: Option[String], protocol: Option[String], resolveTimeout: FiniteDuration)(implicit val ec: ExecutionContext) extends NameResolver { override def getServiceAuthority: String = serviceName val listener: Promise[Listener] = Promise() override def start(l: Listener): Unit = { listener.trySuccess(l) lookup(l) } override def refresh(): Unit = listener.future.onComplete { case Success(l) => lookup(l) case Failure(_) => // We never fail this promise } def lookup(listener: Listener): Unit = { discovery.lookup(Lookup(serviceName, portName, protocol), resolveTimeout).onComplete { case Success(result) => try { listener.onAddresses(addresses(result.addresses), Attributes.EMPTY) } catch { case e: UnknownHostException => // TODO at least log listener.onError(Status.UNKNOWN.withDescription(e.getMessage)) } case Failure(e) => // TODO at least log listener.onError(Status.UNKNOWN.withDescription(e.getMessage)) } } @throws[UnknownHostException] private def addresses(addresses: Seq[ResolvedTarget]) = { import scala.collection.JavaConverters._ addresses .map(target => { val port = target.port.getOrElse(defaultPort) val address = target.address.getOrElse(InetAddress.getByName(target.host)) new EquivalentAddressGroup(new InetSocketAddress(address, port)) }) .asJava } override def shutdown(): Unit = () } object AkkaDiscoveryNameResolver { def apply(settings: GrpcClientSettings)(implicit ec: ExecutionContext): AkkaDiscoveryNameResolver = new AkkaDiscoveryNameResolver( settings.serviceDiscovery, settings.defaultPort, settings.serviceName, settings.servicePortName, settings.serviceProtocol, settings.resolveTimeout) }
Example 3
Source File: PlayScalaTestSpec.scala From play-grpc with Apache License 2.0 | 5 votes |
package play.grpc.scalatest import io.grpc.Status import org.scalatest.concurrent.IntegrationPatience import org.scalatest.concurrent.ScalaFutures import org.scalatestplus.play.PlaySpec import org.scalatestplus.play.guice.GuiceOneServerPerTest import play.api.Application import play.api.inject.bind import play.api.inject.guice.GuiceApplicationBuilder import play.api.libs.ws.WSClient import play.api.routing.Router import akka.grpc.internal.GrpcProtocolNative import example.myapp.helloworld.grpc.helloworld._ class PlayScalaTestSpec extends PlaySpec with GuiceOneServerPerTest with ServerGrpcClient with ScalaFutures with IntegrationPatience { override def fakeApplication(): Application = { GuiceApplicationBuilder() .overrides(bind[Router].to[GreeterServiceImpl]) .build() } implicit def ws: WSClient = app.injector.instanceOf(classOf[WSClient]) "A Play server bound to a gRPC router" must { "give a 404 when routing a non-gRPC request" in { val result = wsUrl("/").get.futureValue result.status must be(404) // Maybe should be a 426, see #396 } "give a 415 error when not using a gRPC content-type" in { val result = wsUrl(s"/${GreeterService.name}/FooBar").get.futureValue result.status must be(415) } "give a grpc 'unimplemented' error when routing a non-existent gRPC method" in { val result = wsUrl(s"/${GreeterService.name}/FooBar") .addHttpHeaders("Content-Type" -> GrpcProtocolNative.contentType.toString) .get .futureValue result.status must be(200) // Maybe should be a 426, see #396 result.header("grpc-status") mustEqual Some(Status.Code.UNIMPLEMENTED.value().toString) } "give a grpc 'invalid argument' error when routing an empty request to a gRPC method" in { val result = wsUrl(s"/${GreeterService.name}/SayHello") .addHttpHeaders("Content-Type" -> GrpcProtocolNative.contentType.toString) .get .futureValue result.status must be(200) result.header("grpc-status") mustEqual Some(Status.Code.INVALID_ARGUMENT.value().toString) } "work with a gRPC client" in withGrpcClient[GreeterServiceClient] { client: GreeterServiceClient => val reply = client.sayHello(HelloRequest("Alice")).futureValue reply.message must be("Hello, Alice!") } } }
Example 4
Source File: GrpcHandler.scala From haystack-traces with Apache License 2.0 | 5 votes |
package com.expedia.www.haystack.trace.reader.services import com.expedia.www.haystack.commons.metrics.MetricsSupport import com.google.protobuf.GeneratedMessageV3 import io.grpc.Status import io.grpc.stub.StreamObserver import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} import scala.util.{Failure, Success} object GrpcHandler { protected val LOGGER: Logger = LoggerFactory.getLogger(classOf[GrpcHandler]) } class GrpcHandler(operationName: String)(implicit val executor: ExecutionContextExecutor) extends MetricsSupport { private val metricFriendlyOperationName = operationName.replace('/', '.') private val timer = metricRegistry.timer(metricFriendlyOperationName) private val failureMeter = metricRegistry.meter(s"$metricFriendlyOperationName.failures") import GrpcHandler._ def handle[Rs](request: GeneratedMessageV3, responseObserver: StreamObserver[Rs])(op: => Future[Rs]): Unit = { val time = timer.time() op onComplete { case Success(response) => responseObserver.onNext(response) responseObserver.onCompleted() time.stop() LOGGER.debug(s"service invocation for operation=$operationName and request=${request.toString} completed successfully") case Failure(ex) => responseObserver.onError(Status.fromThrowable(ex).asRuntimeException()) failureMeter.mark() time.stop() LOGGER.error(s"service invocation for operation=$operationName and request=${request.toString} failed with error", ex) } } }
Example 5
Source File: GrpcHandler.scala From haystack-traces with Apache License 2.0 | 5 votes |
package com.expedia.www.haystack.trace.storage.backends.cassandra.services import com.expedia.www.haystack.commons.metrics.MetricsSupport import com.expedia.www.haystack.trace.storage.backends.cassandra.services.GrpcHandler._ import com.google.protobuf.GeneratedMessageV3 import io.grpc.Status import io.grpc.stub.StreamObserver import org.slf4j.{Logger, LoggerFactory} import scala.concurrent.{ExecutionContextExecutor, Future} import scala.util.{Failure, Success} object GrpcHandler { protected val LOGGER: Logger = LoggerFactory.getLogger(classOf[GrpcHandler]) } class GrpcHandler(operationName: String)(implicit val executor: ExecutionContextExecutor) extends MetricsSupport { private val metricFriendlyOperationName = operationName.replace('/', '.') private val timer = metricRegistry.timer(metricFriendlyOperationName) private val failureMeter = metricRegistry.meter(s"$metricFriendlyOperationName.failures") def handle[Rs](request: GeneratedMessageV3, responseObserver: StreamObserver[Rs])(op: => Future[Rs]): Unit = { val time = timer.time() op onComplete { case Success(response) => responseObserver.onNext(response) responseObserver.onCompleted() time.stop() LOGGER.debug(s"service invocation for operation=$operationName and request=${request.toString} completed successfully") case Failure(ex) => responseObserver.onError(Status.fromThrowable(ex).asRuntimeException()) failureMeter.mark() time.stop() LOGGER.debug(s"service invocation for operation=$operationName and request=${request.toString} failed with error", ex) } } }
Example 6
Source File: TestServiceImpl.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.interop import scala.concurrent.ExecutionContext import scala.concurrent.Future import scala.reflect.ClassTag import scala.collection.immutable import akka.grpc.scaladsl.{GrpcMarshalling} import akka.NotUsed import akka.actor.ActorSystem import akka.grpc._ import akka.stream.scaladsl.{Flow, Source} import akka.stream.{ Materializer, SystemMaterializer } import com.google.protobuf.ByteString import io.grpc.{ Status, StatusRuntimeException } // Generated by our plugin import io.grpc.testing.integration.test.TestService import io.grpc.testing.integration.messages._ import io.grpc.testing.integration.empty.Empty object TestServiceImpl { val parametersToResponseFlow: Flow[ResponseParameters, StreamingOutputCallResponse, NotUsed] = Flow[ResponseParameters] .map { parameters => StreamingOutputCallResponse( Some(Payload(body = ByteString.copyFrom(new Array[Byte](parameters.size))))) } } class TestServiceImpl(implicit sys: ActorSystem) extends TestService { import TestServiceImpl._ implicit val mat: Materializer = SystemMaterializer(sys).materializer implicit val ec: ExecutionContext = sys.dispatcher override def emptyCall(req: Empty) = Future.successful(Empty()) override def unaryCall(req: SimpleRequest): Future[SimpleResponse] = { req.responseStatus match { case None => Future.successful(SimpleResponse(Some(Payload(ByteString.copyFrom(new Array[Byte](req.responseSize)))))) case Some(requestStatus) => val responseStatus = Status.fromCodeValue(requestStatus.code).withDescription(requestStatus.message) // - Either one of the following works Future.failed(new GrpcServiceException(responseStatus)) // throw new GrpcServiceException(responseStatus) } } override def cacheableUnaryCall(in: SimpleRequest): Future[SimpleResponse] = ??? override def fullDuplexCall(in: Source[StreamingOutputCallRequest, NotUsed]): Source[StreamingOutputCallResponse, NotUsed] = in.map(req => { req.responseStatus.foreach(reqStatus => throw new GrpcServiceException( Status.fromCodeValue(reqStatus.code).withDescription(reqStatus.message))) req }).mapConcat( _.responseParameters.to[immutable.Seq]).via(parametersToResponseFlow) override def halfDuplexCall(in: Source[StreamingOutputCallRequest, NotUsed]): Source[StreamingOutputCallResponse, NotUsed] = ??? override def streamingInputCall(in: Source[StreamingInputCallRequest, NotUsed]): Future[StreamingInputCallResponse] = { in .map(_.payload.map(_.body.size).getOrElse(0)) .runFold(0)(_ + _) .map { sum => StreamingInputCallResponse(sum) } } override def streamingOutputCall(in: StreamingOutputCallRequest): Source[StreamingOutputCallResponse, NotUsed] = Source(in.responseParameters.to[immutable.Seq]).via(parametersToResponseFlow) override def unimplementedCall(in: Empty): Future[Empty] = ??? }
Example 7
Source File: ErrorReportingSpec.scala From akka-grpc with Apache License 2.0 | 5 votes |
package example.myapp.helloworld import akka.actor.{ ActorSystem, ClassicActorSystemProvider } import akka.grpc.internal.GrpcProtocolNative import akka.http.scaladsl.model.HttpEntity.{ Chunked, LastChunk } import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers.RawHeader import akka.http.scaladsl.{ Http, HttpConnectionContext } import akka.stream.ActorMaterializer import akka.stream.scaladsl.Sink import example.myapp.helloworld.grpc.{ GreeterService, GreeterServiceHandler } import io.grpc.Status import org.junit.runner.RunWith import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.ScalaFutures import org.scalatest.matchers.should.Matchers import org.scalatest.time.Span import org.scalatest.wordspec.AnyWordSpec import org.scalatestplus.junit.JUnitRunner import scala.concurrent.Await import scala.concurrent.duration._ @RunWith(classOf[JUnitRunner]) class ErrorReportingSpec extends AnyWordSpec with Matchers with ScalaFutures with BeforeAndAfterAll { override implicit val patienceConfig = PatienceConfig(5.seconds, Span(100, org.scalatest.time.Millis)) implicit val system: ActorSystem = ActorSystem() implicit val mat = ActorMaterializer() "A gRPC server" should { val binding = Http() .bindAndHandleAsync( GreeterServiceHandler(new GreeterServiceImpl())(system.asInstanceOf[ClassicActorSystemProvider]), interface = "127.0.0.1", port = 0, connectionContext = HttpConnectionContext()) .futureValue "respond with an 'unimplemented' gRPC error status when calling an unknown method" in { val request = HttpRequest( method = HttpMethods.POST, entity = HttpEntity.empty(GrpcProtocolNative.contentType), uri = s"http://localhost:${binding.localAddress.getPort}/${GreeterService.name}/UnknownMethod") val response = Http().singleRequest(request).futureValue response.status should be(StatusCodes.OK) allHeaders(response) should contain(RawHeader("grpc-status", Status.Code.UNIMPLEMENTED.value().toString)) } "respond with an 'invalid argument' gRPC error status when calling an method without a request body" in { val request = HttpRequest( method = HttpMethods.POST, entity = HttpEntity.empty(GrpcProtocolNative.contentType), uri = s"http://localhost:${binding.localAddress.getPort}/${GreeterService.name}/SayHello") val response = Http().singleRequest(request).futureValue response.status should be(StatusCodes.OK) allHeaders(response) should contain(RawHeader("grpc-status", Status.Code.INVALID_ARGUMENT.value().toString)) } def allHeaders(response: HttpResponse) = response.entity match { case Chunked(_, chunks) => chunks.runWith(Sink.last).futureValue match { case LastChunk(_, trailingHeaders) => response.headers ++ trailingHeaders case _ => response.headers } case _ => response.headers } } override def afterAll: Unit = Await.result(system.terminate(), 5.seconds) }
Example 8
Source File: ErrorReportingSpec.scala From akka-grpc with Apache License 2.0 | 5 votes |
package example.myapp.helloworld import akka.actor.ActorSystem import akka.grpc.internal.GrpcProtocolNative import akka.http.scaladsl.Http import akka.http.scaladsl.model._ import akka.http.scaladsl.model.HttpEntity.{ Chunked, LastChunk } import akka.http.scaladsl.model.headers.RawHeader import akka.stream.ActorMaterializer import akka.stream.scaladsl.Sink import example.myapp.helloworld.grpc.{ GreeterService, GreeterServiceHandlerFactory } import io.grpc.Status import org.scalatest.concurrent.ScalaFutures import org.scalatest.time.Span import org.scalatest.BeforeAndAfterAll import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import scala.concurrent.Await import scala.concurrent.duration._ class ErrorReportingSpec extends AnyWordSpec with Matchers with ScalaFutures with BeforeAndAfterAll { implicit val sys = ActorSystem() override implicit val patienceConfig = PatienceConfig(5.seconds, Span(100, org.scalatest.time.Millis)) "A gRPC server" should { implicit val mat = ActorMaterializer() val handler = GreeterServiceHandlerFactory.create(new GreeterServiceImpl(mat), sys) val binding = { import akka.http.javadsl.{ ConnectHttp, Http } Http(sys).bindAndHandleAsync(handler, ConnectHttp.toHost("127.0.0.1", 0), mat).toCompletableFuture.get } "respond with an 'unimplemented' gRPC error status when calling an unknown method" in { val request = HttpRequest( method = HttpMethods.POST, entity = HttpEntity.empty(GrpcProtocolNative.contentType), uri = s"http://localhost:${binding.localAddress.getPort}/${GreeterService.name}/UnknownMethod") val response = Http().singleRequest(request).futureValue response.status should be(StatusCodes.OK) allHeaders(response) should contain(RawHeader("grpc-status", Status.Code.UNIMPLEMENTED.value().toString)) } "respond with an 'invalid argument' gRPC error status when calling an method without a request body" in { val request = HttpRequest( method = HttpMethods.POST, entity = HttpEntity.empty(GrpcProtocolNative.contentType), uri = s"http://localhost:${binding.localAddress.getPort}/${GreeterService.name}/SayHello") val response = Http().singleRequest(request).futureValue response.status should be(StatusCodes.OK) allHeaders(response) should contain(RawHeader("grpc-status", Status.Code.INVALID_ARGUMENT.value().toString)) } def allHeaders(response: HttpResponse) = response.entity match { case Chunked(_, chunks) => chunks.runWith(Sink.last).futureValue match { case LastChunk(_, trailingHeaders) => response.headers ++ trailingHeaders case _ => response.headers } case _ => response.headers } } override def afterAll: Unit = Await.result(sys.terminate(), 5.seconds) }
Example 9
Source File: GrpcExceptionHandler.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.javadsl import java.util.concurrent.CompletionException import akka.actor.ActorSystem import akka.actor.ClassicActorSystemProvider import akka.annotation.ApiMayChange import akka.annotation.InternalApi import akka.grpc.{ GrpcServiceException, Trailers } import akka.grpc.GrpcProtocol.GrpcProtocolWriter import akka.grpc.internal.{ GrpcResponseHelpers, MissingParameterException } import akka.http.javadsl.model.HttpResponse import akka.japi.{ Function => jFunction } import io.grpc.Status import scala.concurrent.ExecutionException @ApiMayChange object GrpcExceptionHandler { private val INTERNAL = Trailers(Status.INTERNAL) private val INVALID_ARGUMENT = Trailers(Status.INVALID_ARGUMENT) private val UNIMPLEMENTED = Trailers(Status.UNIMPLEMENTED) def defaultMapper: jFunction[ActorSystem, jFunction[Throwable, Trailers]] = new jFunction[ActorSystem, jFunction[Throwable, Trailers]] { override def apply(system: ActorSystem): jFunction[Throwable, Trailers] = default(system) } @InternalApi private def default(system: ActorSystem): jFunction[Throwable, Trailers] = new jFunction[Throwable, Trailers] { override def apply(param: Throwable): Trailers = param match { case e: ExecutionException => if (e.getCause == null) INTERNAL else default(system)(e.getCause) case e: CompletionException => if (e.getCause == null) INTERNAL else default(system)(e.getCause) case grpcException: GrpcServiceException => Trailers(grpcException.status, grpcException.metadata) case _: MissingParameterException => INVALID_ARGUMENT case _: NotImplementedError => UNIMPLEMENTED case _: UnsupportedOperationException => UNIMPLEMENTED case other => system.log.error(other, "Unhandled error: [" + other.getMessage + "]") INTERNAL } } def standard(t: Throwable, writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpResponse = standard(t, default, writer, system) def standard( t: Throwable, mapper: jFunction[ActorSystem, jFunction[Throwable, Trailers]], writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpResponse = GrpcResponseHelpers.status(mapper(system.classicSystem)(t))(writer) }
Example 10
Source File: GrpcExceptionHandler.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.scaladsl import akka.actor.ActorSystem import akka.actor.ClassicActorSystemProvider import akka.annotation.{ ApiMayChange, InternalStableApi } import akka.grpc.{ GrpcServiceException, Trailers } import akka.grpc.GrpcProtocol.GrpcProtocolWriter import akka.grpc.internal.{ GrpcResponseHelpers, MissingParameterException } import akka.http.scaladsl.model.HttpResponse import io.grpc.Status import scala.concurrent.{ ExecutionException, Future } @ApiMayChange object GrpcExceptionHandler { private val INTERNAL = Trailers(Status.INTERNAL) private val INVALID_ARGUMENT = Trailers(Status.INVALID_ARGUMENT) private val UNIMPLEMENTED = Trailers(Status.UNIMPLEMENTED) def defaultMapper(system: ActorSystem): PartialFunction[Throwable, Trailers] = { case e: ExecutionException => if (e.getCause == null) INTERNAL else defaultMapper(system)(e.getCause) case grpcException: GrpcServiceException => Trailers(grpcException.status, grpcException.metadata) case _: NotImplementedError => UNIMPLEMENTED case _: UnsupportedOperationException => UNIMPLEMENTED case _: MissingParameterException => INVALID_ARGUMENT case other => system.log.error(other, s"Unhandled error: [${other.getMessage}].") INTERNAL } @InternalStableApi def default( implicit system: ClassicActorSystemProvider, writer: GrpcProtocolWriter): PartialFunction[Throwable, Future[HttpResponse]] = from(defaultMapper(system.classicSystem)) @InternalStableApi def from(mapper: PartialFunction[Throwable, Trailers])( implicit system: ClassicActorSystemProvider, writer: GrpcProtocolWriter): PartialFunction[Throwable, Future[HttpResponse]] = mapper.orElse(defaultMapper(system.classicSystem)).andThen(s => Future.successful(GrpcResponseHelpers.status(s))) }
Example 11
Source File: GrpcProtocolWeb.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.internal import akka.grpc.GrpcProtocol._ import akka.http.scaladsl.model._ import akka.http.scaladsl.model.HttpEntity.{ Chunk, ChunkStreamPart } import akka.stream.scaladsl.Flow import akka.util.ByteString import io.grpc.{ Status, StatusException } abstract class GrpcProtocolWebBase(subType: String) extends AbstractGrpcProtocol(subType) { protected def postEncode(frame: ByteString): ByteString protected def preDecode(frame: ByteString): ByteString override protected def writer(codec: Codec): GrpcProtocolWriter = AbstractGrpcProtocol.writer(this, codec, frame => encodeFrame(codec, frame)) override protected def reader(codec: Codec): GrpcProtocolReader = AbstractGrpcProtocol.reader(codec, decodeFrame, flow => Flow[ByteString].map(preDecode).via(flow)) @inline private def encodeFrame(codec: Codec, frame: Frame): ChunkStreamPart = { val dataFrameType = AbstractGrpcProtocol.fieldType(codec) val (frameType, data) = frame match { case DataFrame(data) => (dataFrameType, data) case TrailerFrame(trailer) => (ByteString(dataFrameType(0) | 0x80), encodeTrailer(trailer)) } val framed = AbstractGrpcProtocol.encodeFrameData(frameType, codec.compress(data)) Chunk(postEncode(framed)) } @inline private final def decodeFrame(frameHeader: Int, data: ByteString): Frame = { (frameHeader & 80) match { case 0 => DataFrame(data) case 1 => TrailerFrame(decodeTrailer(data)) case f => throw new StatusException(Status.INTERNAL.withDescription(s"Unknown frame type [$f]")) } } @inline private final def encodeTrailer(trailer: Seq[HttpHeader]): ByteString = ByteString(trailer.mkString("", "\r\n", "\r\n")) @inline private final def decodeTrailer(data: ByteString): List[HttpHeader] = ??? } object GrpcProtocolWebText extends GrpcProtocolWebBase("grpc-web-text") { override final def postEncode(framed: ByteString): ByteString = framed.encodeBase64 override final def preDecode(frame: ByteString): ByteString = frame.decodeBase64 }
Example 12
Source File: GrpcRequestHelpers.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.internal import akka.actor.ActorSystem import akka.actor.ClassicActorSystemProvider import akka.grpc.{ ProtobufSerializer, Trailers } import akka.grpc.GrpcProtocol.GrpcProtocolWriter import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart import akka.stream.scaladsl.Source import akka.NotUsed import akka.annotation.InternalApi import akka.grpc.scaladsl.{ headers, GrpcExceptionHandler } import akka.http.scaladsl.model.{ HttpEntity, HttpMethods, HttpRequest, Uri } import io.grpc.Status import scala.collection.immutable @InternalApi object GrpcRequestHelpers { def apply[T]( uri: Uri, e: Source[T, NotUsed], eHandler: ActorSystem => PartialFunction[Throwable, Trailers] = GrpcExceptionHandler.defaultMapper)( implicit m: ProtobufSerializer[T], writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpRequest = request(uri, GrpcEntityHelpers(e, Source.single(GrpcEntityHelpers.trailer(Status.OK)), eHandler)) private def request[T](uri: Uri, entity: Source[ChunkStreamPart, NotUsed])( implicit writer: GrpcProtocolWriter): HttpRequest = { HttpRequest( uri = uri, method = HttpMethods.POST, headers = immutable.Seq( headers.`Message-Encoding`(writer.messageEncoding.name), headers.`Message-Accept-Encoding`(Codecs.supportedCodecs.map(_.name).mkString(","))), entity = HttpEntity.Chunked(writer.contentType, entity)) } }
Example 13
Source File: GrpcEntityHelpers.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.internal import akka.NotUsed import akka.actor.{ ActorSystem, ClassicActorSystemProvider } import akka.annotation.InternalApi import akka.grpc.{ GrpcServiceException, ProtobufSerializer, Trailers } import akka.grpc.GrpcProtocol.{ DataFrame, Frame, GrpcProtocolWriter, TrailerFrame } import akka.grpc.scaladsl.{ headers, BytesEntry, Metadata, StringEntry } import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart import akka.http.scaladsl.model.HttpHeader import akka.http.scaladsl.model.headers.RawHeader import akka.stream.scaladsl.Source import io.grpc.Status @InternalApi object GrpcEntityHelpers { def apply[T]( e: Source[T, NotUsed], trail: Source[TrailerFrame, NotUsed], eHandler: ActorSystem => PartialFunction[Throwable, Trailers])( implicit m: ProtobufSerializer[T], writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): Source[ChunkStreamPart, NotUsed] = { chunks(e, trail).recover { case t => val e = eHandler(system.classicSystem).orElse[Throwable, Trailers] { case e: GrpcServiceException => Trailers(e.status, e.metadata) case e: Exception => Trailers(Status.UNKNOWN.withCause(e).withDescription("Stream failed")) }(t) writer.encodeFrame(trailer(e.status, e.metadata)) } } def apply[T](e: T)(implicit m: ProtobufSerializer[T], writer: GrpcProtocolWriter): Source[ChunkStreamPart, NotUsed] = chunks(Source.single(e), Source.empty) private def chunks[T](e: Source[T, NotUsed], trail: Source[Frame, NotUsed])( implicit m: ProtobufSerializer[T], writer: GrpcProtocolWriter): Source[ChunkStreamPart, NotUsed] = e.map { msg => DataFrame(m.serialize(msg)) }.concat(trail).via(writer.frameEncoder) def trailer(status: Status): TrailerFrame = TrailerFrame(trailers = statusHeaders(status)) def trailer(status: Status, metadata: Metadata): TrailerFrame = TrailerFrame(trailers = statusHeaders(status) ++ metadataHeaders(metadata)) def statusHeaders(status: Status): List[HttpHeader] = List(headers.`Status`(status.getCode.value.toString)) ++ Option(status.getDescription).map(d => headers.`Status-Message`(d)) def metadataHeaders(metadata: Metadata): List[HttpHeader] = metadata.asList.map { case (key, StringEntry(value)) => RawHeader(key, value) case (key, BytesEntry(value)) => RawHeader(key, MetadataImpl.encodeBinaryHeader(value)) } }
Example 14
Source File: package.scala From gatling-grpc with Apache License 2.0 | 5 votes |
package com.github.phisgr.gatling.grpc import java.lang.{StringBuilder => JStringBuilder} import com.google.common.base.Charsets.US_ASCII import io.gatling.commons.util.StringHelper.Eol import io.grpc.{InternalMetadata, Metadata, Status} package object util { implicit private[gatling] class GrpcStringBuilder(val buff: JStringBuilder) extends AnyVal { def appendWithEol(s: String): JStringBuilder = buff.append(s).append(Eol) def appendWithEol(o: Object): JStringBuilder = buff.append(o).append(Eol) def appendRequest(payload: Any, headers: Metadata): JStringBuilder = { val payloadString = payload match { case scalaPbObject: scalapb.GeneratedMessage => scalaPbObject.toProtoString case _ => payload.toString // for Java Proto messages, this is the proto string } appendHeaders(headers) appendWithEol("payload=") appendWithEol(payloadString) } def appendResponse(body: Any, status: Status, trailers: Metadata): JStringBuilder = { appendStatus(status) appendTrailers(trailers) val bodyString = body match { case _ if null == body || !status.isOk => null case scalaPbObject: scalapb.GeneratedMessage => scalaPbObject.toProtoString case _ => body.toString // for Java Proto messages, this is the proto string } if (bodyString ne null) { buff .appendWithEol("body=") .appendWithEol(bodyString) } buff } private def appendStatus(s: Status): JStringBuilder = { buff.append("status=").append(Eol) .append(s.getCode) val description = s.getDescription if (description ne null) { buff.append(", description: ").append(description) } buff.append(Eol) val cause = s.getCause if (cause ne null) { buff.append("cause: ").appendWithEol(cause.toString) } buff } private def appendHeaders(headers: Metadata): JStringBuilder = appendMetadata(headers, "headers") private def appendTrailers(trailers: Metadata): JStringBuilder = appendMetadata(trailers, "trailers") private def appendMetadata(metadata: Metadata, headersOrTrailers: String): JStringBuilder = { val size = InternalMetadata.headerCount(metadata) if (size != 0) { buff.append(headersOrTrailers).appendWithEol("=") var i = 0 while (i < size) { val headerName = new String(Reflections.name(metadata, i), US_ASCII) buff.append(headerName).append(": ") val valueBytes = Reflections.value(metadata, i) val valueString = if (headerName.endsWith(Metadata.BINARY_HEADER_SUFFIX)) { InternalMetadata.BASE64_ENCODING_OMIT_PADDING.encode(valueBytes) } else { new String(valueBytes, US_ASCII) } buff.appendWithEol(valueString) i += 1 } } buff } } }
Example 15
Source File: GrpcResponseHelpers.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.internal import akka.NotUsed import akka.actor.ActorSystem import akka.actor.ClassicActorSystemProvider import akka.annotation.InternalApi import akka.grpc.{ ProtobufSerializer, Trailers } import akka.grpc.GrpcProtocol.{ GrpcProtocolWriter, TrailerFrame } import akka.grpc.scaladsl.{ headers, GrpcExceptionHandler } import akka.http.scaladsl.model.{ HttpEntity, HttpResponse } import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart import akka.stream.Materializer import akka.stream.scaladsl.Source import io.grpc.Status import scala.collection.immutable import scala.concurrent.{ ExecutionContext, Future } @InternalApi // consumed from generated classes so cannot be private object GrpcResponseHelpers { def apply[T](e: Source[T, NotUsed])( implicit m: ProtobufSerializer[T], writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpResponse = GrpcResponseHelpers(e, Source.single(GrpcEntityHelpers.trailer(Status.OK))) def apply[T](e: Source[T, NotUsed], eHandler: ActorSystem => PartialFunction[Throwable, Trailers])( implicit m: ProtobufSerializer[T], writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpResponse = GrpcResponseHelpers(e, Source.single(GrpcEntityHelpers.trailer(Status.OK)), eHandler) def apply[T](e: Source[T, NotUsed], status: Future[Status])( implicit m: ProtobufSerializer[T], mat: Materializer, writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpResponse = GrpcResponseHelpers(e, status, GrpcExceptionHandler.defaultMapper _) def apply[T]( e: Source[T, NotUsed], status: Future[Status], eHandler: ActorSystem => PartialFunction[Throwable, Trailers])( implicit m: ProtobufSerializer[T], mat: Materializer, writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpResponse = { implicit val ec: ExecutionContext = mat.executionContext GrpcResponseHelpers( e, Source.lazilyAsync(() => status.map(GrpcEntityHelpers.trailer)).mapMaterializedValue(_ => NotUsed), eHandler) } def apply[T]( e: Source[T, NotUsed], trail: Source[TrailerFrame, NotUsed], eHandler: ActorSystem => PartialFunction[Throwable, Trailers] = GrpcExceptionHandler.defaultMapper)( implicit m: ProtobufSerializer[T], writer: GrpcProtocolWriter, system: ClassicActorSystemProvider): HttpResponse = { response(GrpcEntityHelpers(e, trail, eHandler)) } private def response[T](entity: Source[ChunkStreamPart, NotUsed])(implicit writer: GrpcProtocolWriter) = { HttpResponse( headers = immutable.Seq(headers.`Message-Encoding`(writer.messageEncoding.name)), entity = HttpEntity.Chunked(writer.contentType, entity)) } def status(trailer: Trailers)(implicit writer: GrpcProtocolWriter): HttpResponse = response(Source.single(writer.encodeFrame(GrpcEntityHelpers.trailer(trailer.status, trailer.metadata)))) }
Example 16
Source File: Codecs.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.internal import akka.http.javadsl.{ model => jm } import akka.grpc.GrpcServiceException import akka.grpc.scaladsl.headers.{ `Message-Accept-Encoding`, `Message-Encoding` } import io.grpc.Status import scala.collection.immutable import scala.util.{ Failure, Success, Try } object Codecs { // TODO should this list be made user-extensible? val supportedCodecs = immutable.Seq(Gzip, Identity) private val supported = supportedCodecs.map(_.name) private val byName = supportedCodecs.map(c => c.name -> c).toMap def detect(encoding: Option[String]): Try[Codec] = encoding .map { codec => byName .get(codec) .map(Success(_)) .getOrElse(Failure(new GrpcServiceException( Status.UNIMPLEMENTED.withDescription(s"Message Encoding $encoding is not supported")))) } .getOrElse(Success(Identity)) }
Example 17
Source File: Trailers.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc import akka.annotation.ApiMayChange import io.grpc.Status import akka.grpc.internal.JavaMetadataImpl import akka.grpc.scaladsl.{ Metadata, MetadataBuilder } import akka.grpc.javadsl.{ Metadata => jMetadata } @ApiMayChange class Trailers(val status: Status, val metadata: Metadata) { def this(status: Status) = { this(status, MetadataBuilder.empty) } def this(status: Status, metadata: jMetadata) = { this(status, metadata.asScala) } def getMetadata: jMetadata = new JavaMetadataImpl(metadata) } object Trailers { def apply(status: Status): Trailers = new Trailers(status) def apply(status: Status, metadata: Metadata): Trailers = new Trailers(status, metadata) }
Example 18
Source File: CodecsSpec.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc import akka.grpc.internal.{ Codecs, Gzip, Identity } import akka.grpc.scaladsl.headers import akka.http.scaladsl.model.HttpRequest import io.grpc.Status import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import org.scalatest.TryValues import scala.collection.immutable class CodecsSpec extends AnyWordSpec with Matchers with TryValues { private def accept(encodings: String*): HttpRequest = HttpRequest(headers = immutable.Seq(headers.`Message-Accept-Encoding`(encodings.mkString(",")))) private def enc(encodings: String*): HttpRequest = HttpRequest(headers = immutable.Seq(headers.`Message-Encoding`(encodings.mkString(",")))) "Negotiating message encoding with remote client" should { "default to Identity if no encoding provided" in { Codecs.negotiate(HttpRequest()) should be(Identity) } "accept explicit Identity" in { Codecs.negotiate(accept(Identity.name)) should be(Identity) } "accept explicit Gzip" in { Codecs.negotiate(accept(Gzip.name)) should be(Gzip) } "use client preference with multiple known encodings" in { Codecs.negotiate(accept(Gzip.name, Identity.name)) should be(Gzip) Codecs.negotiate(accept(Identity.name, Gzip.name)) should be(Identity) } "use first known encoding" in { Codecs.negotiate(accept("xxxxx", Gzip.name, Identity.name)) should be(Gzip) } "use default encoding if unknown encodings specified" in { Codecs.negotiate(accept("xxxxx")) should be(Identity) } } "Detecting message encoding from remote" should { "default to Identity if not specified" in { Codecs.detect(HttpRequest()).success.value should be(Identity) } "accept explicit Identity" in { Codecs.detect(enc(Identity.name)).success.value should be(Identity) } "accept explicit Gzip" in { Codecs.detect(enc(Gzip.name)).success.value should be(Gzip) } "fail with unknown encoding" in { val detected = Codecs.detect(enc("xxxxxxx")) detected.failure.exception shouldBe a[GrpcServiceException] detected.failure.exception.asInstanceOf[GrpcServiceException].status.getCode should be( Status.UNIMPLEMENTED.getCode) } } }
Example 19
Source File: GrpcExceptionHandlerSpec.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.scaladsl import akka.actor.ActorSystem import akka.grpc.GrpcServiceException import akka.grpc.internal.{ GrpcProtocolNative, GrpcResponseHelpers, Identity } import akka.grpc.scaladsl.GrpcExceptionHandler.defaultMapper import akka.http.scaladsl.model.HttpEntity._ import akka.http.scaladsl.model.HttpResponse import akka.stream.ActorMaterializer import io.grpc.Status import org.scalatest._ import org.scalatest.concurrent.ScalaFutures import org.scalatest.matchers.should.Matchers import org.scalatest.time.{ Millis, Seconds, Span } import org.scalatest.wordspec.AnyWordSpec import scala.concurrent.{ ExecutionException, Future } class GrpcExceptionHandlerSpec extends AnyWordSpec with Matchers with ScalaFutures with BeforeAndAfterAll { implicit val system = ActorSystem("Test") implicit val materializer = ActorMaterializer() implicit override val patienceConfig = PatienceConfig(timeout = scaled(Span(2, Seconds)), interval = scaled(Span(5, Millis))) implicit val writer = GrpcProtocolNative.newWriter(Identity) val expected: Function[Throwable, Status] = { case e: ExecutionException => if (e.getCause == null) Status.INTERNAL else expected(e.getCause) case grpcException: GrpcServiceException => grpcException.status case _: NotImplementedError => Status.UNIMPLEMENTED case _: UnsupportedOperationException => Status.UNIMPLEMENTED case _ => Status.INTERNAL } val otherTypes: Seq[Throwable] = Seq( new GrpcServiceException(status = Status.DEADLINE_EXCEEDED), new NotImplementedError, new UnsupportedOperationException, new NullPointerException, new RuntimeException) val executionExceptions: Seq[Throwable] = otherTypes.map(new ExecutionException(_)) :+ new ExecutionException("doh", null) "defaultMapper" should { (otherTypes ++ executionExceptions).foreach { e => val exp = expected(e) s"Map $e to $exp" in { defaultMapper(system)(e).status shouldBe exp } } } "default(defaultMapper)" should { (otherTypes ++ executionExceptions).foreach { e => s"Correctly map $e" in { val exp = GrpcResponseHelpers.status(defaultMapper(system)(e)) val expChunks = getChunks(exp) val act = GrpcExceptionHandler.from(defaultMapper(system))(system, writer)(e).futureValue val actChunks = getChunks(act) // Following is because aren't equal act.status shouldBe exp.status actChunks.toString shouldEqual expChunks.toString } } } def getChunks(resp: HttpResponse): Seq[ChunkStreamPart] = (resp.entity match { case Chunked(_, chunks) => chunks.runFold(Seq.empty[ChunkStreamPart]) { case (seq, chunk) => seq :+ chunk } case _ => Future.successful(Seq.empty[ChunkStreamPart]) }).futureValue override def afterAll(): Unit = { super.afterAll() system.terminate() } }
Example 20
Source File: AkkaDiscoveryNameResolverSpec.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.internal import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.grpc.{ GrpcClientSettings, GrpcServiceException } import akka.testkit.TestKit import io.grpc.Status import org.scalatest.concurrent.ScalaFutures import org.scalatest.matchers.should.Matchers import org.scalatest.time.{ Millis, Seconds, Span } import org.scalatest.wordspec.AnyWordSpecLike import scala.collection.JavaConverters._ class AkkaDiscoveryNameResolverSpec extends TestKit(ActorSystem()) with AnyWordSpecLike with Matchers with ScalaFutures { implicit val ex = system.dispatcher implicit override val patienceConfig = PatienceConfig(timeout = scaled(Span(2, Seconds)), interval = scaled(Span(5, Millis))) "The AkkaDiscovery-backed NameResolver" should { "correctly report an error for an unknown hostname" in { val host = "example.invalid" val resolver = AkkaDiscoveryNameResolver(GrpcClientSettings.connectToServiceAt(host, 80)) val probe = new NameResolverListenerProbe() resolver.start(probe) val exception = probe.future.failed.futureValue.asInstanceOf[GrpcServiceException] exception shouldBe an[GrpcServiceException] exception.status.getCode == Status.UNKNOWN.getCode // FIXME: This description is not portable - it arises from native function response, which differs by OS // exception.status.getDescription should equal(host + ": Name or service not known") } "support serving a static host/port" in { // Unfortunately it needs to be an actually resolvable address... val host = "akka.io" val port = 4040 val resolver = AkkaDiscoveryNameResolver(GrpcClientSettings.connectToServiceAt(host, port)) val probe = new NameResolverListenerProbe() resolver.start(probe) val addresses = probe.future.futureValue match { case Seq(addressGroup) => addressGroup.getAddresses case _ => fail("Expected a single address group") } addresses.asScala.toSeq match { case Seq(address: InetSocketAddress) => address.getPort should be(port) address.getAddress.getHostName should be(host) case other => fail(s"Expected a single InetSocketAddress, got $other") } } } }
Example 21
Source File: TestServiceImpl.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.interop import akka.NotUsed import akka.actor.ActorSystem import akka.grpc.GrpcServiceException import akka.stream.{ Materializer, SystemMaterializer } import akka.stream.scaladsl.{ Flow, Source } import com.google.protobuf.ByteString import io.grpc.Status import io.grpc.testing.integration.empty.Empty import scala.concurrent.{ ExecutionContext, Future } // Generated by our plugin import io.grpc.testing.integration.messages._ import io.grpc.testing.integration.test.TestService object TestServiceImpl { val parametersToResponseFlow: Flow[ResponseParameters, StreamingOutputCallResponse, NotUsed] = Flow[ResponseParameters].map { parameters => StreamingOutputCallResponse(Some(Payload(body = ByteString.copyFrom(new Array[Byte](parameters.size))))) } } class TestServiceImpl(implicit sys: ActorSystem) extends TestService { import TestServiceImpl._ implicit val mat: Materializer = SystemMaterializer(sys).materializer implicit val ec: ExecutionContext = sys.dispatcher override def emptyCall(req: Empty) = Future.successful(Empty()) override def unaryCall(req: SimpleRequest): Future[SimpleResponse] = req.responseStatus match { case None => Future.successful(SimpleResponse(Some(Payload(ByteString.copyFrom(new Array[Byte](req.responseSize)))))) case Some(requestStatus) => val responseStatus = Status.fromCodeValue(requestStatus.code).withDescription(requestStatus.message) // - Either one of the following works // Future.failed(new GrpcServiceException(responseStatus)) throw new GrpcServiceException(responseStatus) } override def cacheableUnaryCall(in: SimpleRequest): Future[SimpleResponse] = ??? override def fullDuplexCall( in: Source[StreamingOutputCallRequest, NotUsed]): Source[StreamingOutputCallResponse, NotUsed] = in.map(req => { req.responseStatus.foreach(reqStatus => throw new GrpcServiceException(Status.fromCodeValue(reqStatus.code).withDescription(reqStatus.message))) req }).mapConcat(_.responseParameters.toList) .via(parametersToResponseFlow) override def halfDuplexCall( in: Source[StreamingOutputCallRequest, NotUsed]): Source[StreamingOutputCallResponse, NotUsed] = ??? override def streamingInputCall(in: Source[StreamingInputCallRequest, NotUsed]): Future[StreamingInputCallResponse] = in.map(_.payload.map(_.body.size).getOrElse(0)).runFold(0)(_ + _).map { sum => StreamingInputCallResponse(sum) } override def streamingOutputCall(in: StreamingOutputCallRequest): Source[StreamingOutputCallResponse, NotUsed] = Source(in.responseParameters.toList).via(parametersToResponseFlow) override def unimplementedCall(in: Empty): Future[Empty] = ??? }
Example 22
Source File: GrpcMarshallingSpec.scala From akka-grpc with Apache License 2.0 | 5 votes |
package akka.grpc.scaladsl import akka.actor.ActorSystem import akka.grpc.internal.{ AbstractGrpcProtocol, GrpcProtocolNative, Gzip } import akka.grpc.scaladsl.headers.`Message-Encoding` import akka.http.scaladsl.model.{ HttpEntity, HttpRequest } import akka.stream.ActorMaterializer import akka.stream.scaladsl.Sink import io.grpc.{ Status, StatusException } import io.grpc.testing.integration.messages.{ BoolValue, SimpleRequest } import io.grpc.testing.integration.test.TestService import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import scala.collection.immutable import scala.concurrent.{ Await, Future } import scala.concurrent.duration._ class GrpcMarshallingSpec extends AnyWordSpec with Matchers { "The scaladsl GrpcMarshalling" should { val message = SimpleRequest(responseCompressed = Some(BoolValue(true))) implicit val serializer = TestService.Serializers.SimpleRequestSerializer implicit val system = ActorSystem() implicit val mat = ActorMaterializer() val awaitTimeout = 10.seconds val zippedBytes = AbstractGrpcProtocol.encodeFrameData( AbstractGrpcProtocol.fieldType(Gzip), Gzip.compress(serializer.serialize(message))) "correctly unmarshal a zipped object" in { val request = HttpRequest( headers = immutable.Seq(`Message-Encoding`("gzip")), entity = HttpEntity.Strict(GrpcProtocolNative.contentType, zippedBytes)) val marshalled = Await.result(GrpcMarshalling.unmarshal(request), 10.seconds) marshalled.responseCompressed should be(Some(BoolValue(true))) } "correctly unmarshal a zipped stream" in { val request = HttpRequest( headers = immutable.Seq(`Message-Encoding`("gzip")), entity = HttpEntity.Strict(GrpcProtocolNative.contentType, zippedBytes ++ zippedBytes)) val stream = Await.result(GrpcMarshalling.unmarshalStream(request), 10.seconds) val items = Await.result(stream.runWith(Sink.seq), 10.seconds) items(0).responseCompressed should be(Some(BoolValue(true))) items(1).responseCompressed should be(Some(BoolValue(true))) } // https://github.com/grpc/grpc/blob/master/doc/compression.md#compression-method-asymmetry-between-peers // test case 6 "fail with INTERNAL when the compressed bit is on but the encoding is identity" in { val request = HttpRequest( headers = immutable.Seq(`Message-Encoding`("identity")), entity = HttpEntity.Strict(GrpcProtocolNative.contentType, zippedBytes)) assertFailure(GrpcMarshalling.unmarshal(request), Status.Code.INTERNAL, "encoding") } // https://github.com/grpc/grpc/blob/master/doc/compression.md#compression-method-asymmetry-between-peers // test case 6 "fail with INTERNAL when the compressed bit is on but the encoding is missing" in { val request = HttpRequest(entity = HttpEntity.Strict(GrpcProtocolNative.contentType, zippedBytes)) assertFailure(GrpcMarshalling.unmarshal(request), Status.Code.INTERNAL, "encoding") } def assertFailure(failure: Future[_], expectedStatusCode: Status.Code, expectedMessageFragment: String): Unit = { val e = Await.result(failure.failed, awaitTimeout).asInstanceOf[StatusException] e.getStatus.getCode should be(expectedStatusCode) e.getStatus.getDescription should include(expectedMessageFragment) } } }
Example 23
Source File: GRPCErrors.scala From Waves with MIT License | 5 votes |
package com.wavesplatform.api.grpc import com.wavesplatform.api.http.ApiError import com.wavesplatform.api.http.ApiError._ import io.grpc.Metadata.AsciiMarshaller import io.grpc.{Metadata, Status, StatusException} object GRPCErrors { private[this] val IntMarshaller: AsciiMarshaller[Int] = new AsciiMarshaller[Int] { override def toAsciiString(value: Int): String = value.toString override def parseAsciiString(serialized: String): Int = serialized.toInt } val ErrorCodeKey = Metadata.Key.of("Error-Code", IntMarshaller) def toStatusException(api: ApiError): StatusException = { val code = api match { case WalletNotExist | WalletAddressDoesNotExist | TransactionDoesNotExist | AliasDoesNotExist(_) | BlockDoesNotExist | MissingSenderPrivateKey | DataKeyDoesNotExist => Status.NOT_FOUND case WalletAlreadyExists => Status.ALREADY_EXISTS case WalletLocked => Status.PERMISSION_DENIED case _ => Status.INVALID_ARGUMENT } val metadata = new Metadata() metadata.put(ErrorCodeKey, api.id) code.withDescription(api.message).asException(metadata) } def toStatusException(exc: Throwable): StatusException = { val status = exc match { case _: IllegalArgumentException => Status.INVALID_ARGUMENT case _: NoSuchElementException => Status.NOT_FOUND case _: IllegalStateException => Status.FAILED_PRECONDITION case _ => Status.fromThrowable(exc) } new StatusException(status.withCause(exc).withDescription(exc.getMessage)) } }
Example 24
Source File: GrpcSerializers.scala From scio with Apache License 2.0 | 5 votes |
package com.spotify.scio.coders.instances.kryo import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.io.{Input, Output} import com.twitter.chill.KSerializer import io.grpc.{Metadata, Status, StatusRuntimeException} private[coders] object GrpcSerializers { class StatusSerializer extends KSerializer[Status] { override def write(kryo: Kryo, output: Output, status: Status): Unit = { output.writeInt(status.getCode().value()) output.writeString(status.getDescription) kryo.writeClassAndObject(output, status.getCause) } override def read(kryo: Kryo, input: Input, `type`: Class[Status]): Status = { val code = input.readInt() val description = input.readString() val cause = kryo.readClassAndObject(input).asInstanceOf[Throwable] Status .fromCodeValue(code) .withDescription(description) .withCause(cause) } } class StatusRuntimeExceptionSerializer extends KSerializer[StatusRuntimeException] { lazy val statusSer = new StatusSerializer() override def write(kryo: Kryo, output: Output, e: StatusRuntimeException): Unit = { kryo.writeObject(output, e.getStatus, statusSer) kryo.writeObjectOrNull(output, e.getTrailers, classOf[Metadata]) } override def read( kryo: Kryo, input: Input, `type`: Class[StatusRuntimeException] ): StatusRuntimeException = { val status = kryo.readObject(input, classOf[Status], statusSer) val trailers = kryo.readObjectOrNull(input, classOf[Metadata]) new StatusRuntimeException(status, trailers) } } }
Example 25
Source File: GrpcSerializersTest.scala From scio with Apache License 2.0 | 5 votes |
package com.spotify.scio.coders.instances.kryo import com.spotify.scio.coders.{Coder, CoderMaterializer} import io.grpc.{Metadata, Status, StatusRuntimeException} import org.apache.beam.sdk.util.CoderUtils import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scala.jdk.CollectionConverters._ class GrpcSerializersTest extends AnyFlatSpec with Matchers { "StatusRuntimeException" should "roundtrip with nullable fields present" in { val metadata = new Metadata() metadata.put(Metadata.Key.of[String]("k", Metadata.ASCII_STRING_MARSHALLER), "v") roundtrip( new StatusRuntimeException( Status.OK.withCause(new RuntimeException("bar")).withDescription("bar"), metadata ) ) } it should "roundtrip with nullable fields absent" in { roundtrip(new StatusRuntimeException(Status.OK)) } private def roundtrip(t: StatusRuntimeException): Unit = { val kryoBCoder = CoderMaterializer.beamWithDefault(Coder[StatusRuntimeException]) val bytes = CoderUtils.encodeToByteArray(kryoBCoder, t) val copy = CoderUtils.decodeFromByteArray(kryoBCoder, bytes) checkStatusEq(t.getStatus, copy.getStatus) checkTrailersEq(t.getTrailers, copy.getTrailers) } private def checkTrailersEq(metadata1: Metadata, metadata2: Metadata): Unit = (Option(metadata1), Option(metadata2)) match { case (Some(m1), Some(m2)) => m1.keys.size shouldEqual m2.keys.size m1.keys.asScala.foreach { k => m1.get(Metadata.Key.of[String](k, Metadata.ASCII_STRING_MARSHALLER)) shouldEqual m2.get(Metadata.Key.of[String](k, Metadata.ASCII_STRING_MARSHALLER)) } case (None, None) => case _ => fail(s"Metadata were unequal: ($metadata1, $metadata2)") } private def checkStatusEq(s1: Status, s2: Status): Unit = { s1.getCode shouldEqual s2.getCode s1.getDescription shouldEqual s2.getDescription if (s1.getCause != null) { s1.getCause.getClass shouldEqual s2.getCause.getClass s1.getCause.getMessage shouldEqual s2.getCause.getMessage } else if (s2.getCause != null) { fail(s"Status $s1 is missing a cause") } } }
Example 26
Source File: LoggingServerInterceptor.scala From scala-server-toolkit with MIT License | 5 votes |
package com.avast.sst.grpc.server.interceptor import io.grpc.ForwardingServerCall.SimpleForwardingServerCall import io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener import io.grpc._ import org.slf4j.Logger class LoggingServerInterceptor(logger: Logger) extends ServerInterceptor { override def interceptCall[ReqT, RespT]( call: ServerCall[ReqT, RespT], headers: Metadata, next: ServerCallHandler[ReqT, RespT] ): ServerCall.Listener[ReqT] = { val methodName = call.getMethodDescriptor.getFullMethodName val finalCall = new CloseServerCall(methodName, call) new OnMessageServerCallListener(methodName, next.startCall(finalCall, headers)) } private class CloseServerCall[A, B](methodName: String, delegate: ServerCall[A, B]) extends SimpleForwardingServerCall[A, B](delegate) { override def close(status: Status, trailers: Metadata): Unit = { import io.grpc.Status if ((status.getCode eq Status.Code.UNKNOWN) || (status.getCode eq Status.Code.INTERNAL)) { logger.error( String.format( "Error response from method %s: %s %s", methodName, status.getCode, status.getDescription ), status.getCause ) } else if (!status.isOk) { logger.warn( String.format( "Error response from method %s: %s %s", methodName, status.getCode, status.getDescription ), status.getCause ) } else { logger.debug("Successful response from method {}: {}", Array(methodName, status): _*) } super.close(status, trailers) } } private class OnMessageServerCallListener[A](methodName: String, delegate: ServerCall.Listener[A]) extends SimpleForwardingServerCallListener[A](delegate) { override def onMessage(message: A): Unit = { logger.debug("Dispatching method {}", methodName) super.onMessage(message) } } }
Example 27
Source File: ContextualizedLogger.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.logging import akka.NotUsed import akka.stream.scaladsl.Flow import com.daml.grpc.GrpcException import io.grpc.Status import org.slf4j.{Logger, LoggerFactory} import scala.collection.concurrent.TrieMap import scala.util.{Failure, Try} import scala.util.control.NonFatal object ContextualizedLogger { // Caches loggers to prevent them from needlessly wasting memory // Replicates the behavior of the underlying Slf4j logger factory private[this] val cache = TrieMap.empty[String, ContextualizedLogger] // Allows to explicitly pass a logger, should be used for testing only private[logging] def createFor(withoutContext: Logger): ContextualizedLogger = new ContextualizedLogger(withoutContext) // Slf4j handles the caching of the underlying logger itself private[logging] def createFor(name: String): ContextualizedLogger = createFor(LoggerFactory.getLogger(name)) def get(clazz: Class[_]): ContextualizedLogger = { val name = clazz.getName.stripSuffix("$") cache.getOrElseUpdate(name, createFor(name)) } } final class ContextualizedLogger private (val withoutContext: Logger) { val trace = new LeveledLogger.Trace(withoutContext) val debug = new LeveledLogger.Debug(withoutContext) val info = new LeveledLogger.Info(withoutContext) val warn = new LeveledLogger.Warn(withoutContext) val error = new LeveledLogger.Error(withoutContext) private def internalOrUnknown(code: Status.Code): Boolean = code == Status.Code.INTERNAL || code == Status.Code.UNKNOWN private def logError(t: Throwable)(implicit logCtx: LoggingContext): Unit = error("Unhandled internal error", t) def logErrorsOnCall[Out](implicit logCtx: LoggingContext): PartialFunction[Try[Out], Unit] = { case Failure(e @ GrpcException(s, _)) => if (internalOrUnknown(s.getCode)) { logError(e) } case Failure(NonFatal(e)) => logError(e) } def logErrorsOnStream[Out](implicit logCtx: LoggingContext): Flow[Out, Out, NotUsed] = Flow[Out].mapError { case e @ GrpcException(s, _) => if (internalOrUnknown(s.getCode)) { logError(e) } e case NonFatal(e) => logError(e) e } }
Example 28
Source File: ApiPackageService.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.platform.apiserver.services import com.daml.ledger.participant.state.index.v2.IndexPackagesService import com.daml.lf.data.Ref import com.daml.daml_lf_dev.DamlLf.{Archive, HashFunction} import com.daml.dec.{DirectExecutionContext => DEC} import com.daml.ledger.api.domain.LedgerId import com.daml.ledger.api.v1.package_service.HashFunction.{ SHA256 => APISHA256, Unrecognized => APIUnrecognized } import com.daml.ledger.api.v1.package_service.PackageServiceGrpc.PackageService import com.daml.ledger.api.v1.package_service.{HashFunction => APIHashFunction, _} import com.daml.logging.{ContextualizedLogger, LoggingContext} import com.daml.platform.api.grpc.GrpcApiService import com.daml.platform.server.api.validation.PackageServiceValidation import io.grpc.{BindableService, ServerServiceDefinition, Status} import scala.concurrent.Future final class ApiPackageService private (backend: IndexPackagesService)( implicit logCtx: LoggingContext) extends PackageService with GrpcApiService { private val logger = ContextualizedLogger.get(this.getClass) override def bindService(): ServerServiceDefinition = PackageServiceGrpc.bindService(this, DEC) override def close(): Unit = () override def listPackages(request: ListPackagesRequest): Future[ListPackagesResponse] = backend .listLfPackages() .map(p => ListPackagesResponse(p.keys.toSeq))(DEC) .andThen(logger.logErrorsOnCall[ListPackagesResponse])(DEC) override def getPackage(request: GetPackageRequest): Future[GetPackageResponse] = withValidatedPackageId( request.packageId, pId => backend .getLfArchive(pId) .flatMap(_.fold(Future.failed[GetPackageResponse](Status.NOT_FOUND.asRuntimeException()))( archive => Future.successful(toGetPackageResponse(archive))))(DEC) .andThen(logger.logErrorsOnCall[GetPackageResponse])(DEC) ) override def getPackageStatus( request: GetPackageStatusRequest): Future[GetPackageStatusResponse] = withValidatedPackageId( request.packageId, pId => backend .listLfPackages() .map { packages => val result = if (packages.contains(pId)) { PackageStatus.REGISTERED } else { PackageStatus.UNKNOWN } GetPackageStatusResponse(result) }(DEC) .andThen(logger.logErrorsOnCall[GetPackageStatusResponse])(DEC) ) private def withValidatedPackageId[T](packageId: String, block: Ref.PackageId => Future[T]) = Ref.PackageId .fromString(packageId) .fold( error => Future.failed[T]( Status.INVALID_ARGUMENT .withDescription(error) .asRuntimeException()), pId => block(pId) ) private def toGetPackageResponse(archive: Archive): GetPackageResponse = { val hashF: APIHashFunction = archive.getHashFunction match { case HashFunction.SHA256 => APISHA256 case _ => APIUnrecognized(-1) } GetPackageResponse(hashF, archive.getPayload, archive.getHash) } } object ApiPackageService { def create(ledgerId: LedgerId, backend: IndexPackagesService)( implicit logCtx: LoggingContext): PackageService with GrpcApiService = new PackageServiceValidation(new ApiPackageService(backend), ledgerId) with BindableService { override def bindService(): ServerServiceDefinition = PackageServiceGrpc.bindService(this, DEC) } }
Example 29
Source File: TrackerImplTest.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.platform.apiserver.services.tracking import akka.NotUsed import akka.stream.OverflowStrategy import akka.stream.scaladsl.{Keep, Source, SourceQueueWithComplete} import akka.stream.testkit.TestSubscriber import akka.stream.testkit.scaladsl.TestSink import com.daml.ledger.api.testing.utils.{ AkkaBeforeAndAfterAll, IsStatusException, TestingException } import com.daml.ledger.api.v1.command_service.SubmitAndWaitRequest import com.daml.ledger.api.v1.commands.Commands import com.daml.ledger.api.v1.completion.Completion import com.daml.dec.DirectExecutionContext import com.google.rpc.status.{Status => RpcStatus} import io.grpc.Status import org.scalatest.concurrent.ScalaFutures import org.scalatest.{BeforeAndAfterEach, Matchers, Succeeded, WordSpec} import scala.concurrent.ExecutionContext.Implicits.global class TrackerImplTest extends WordSpec with Matchers with BeforeAndAfterEach with ScalaFutures with AkkaBeforeAndAfterAll { private var sut: Tracker = _ private var consumer: TestSubscriber.Probe[NotUsed] = _ private var queue: SourceQueueWithComplete[TrackerImpl.QueueInput] = _ private def input(cid: Int) = SubmitAndWaitRequest(Some(Commands(commandId = cid.toString))) override protected def beforeEach(): Unit = { val (q, sink) = Source .queue[TrackerImpl.QueueInput](1, OverflowStrategy.dropNew) .map { in => in.context.success(Completion(in.value.getCommands.commandId, Some(RpcStatus()))) NotUsed } .toMat(TestSink.probe[NotUsed])(Keep.both) .run() queue = q sut = new TrackerImpl(q) consumer = sink } override protected def afterEach(): Unit = { consumer.cancel() queue.complete() } "Tracker Implementation" when { "input is submitted, and the queue is available" should { "work successfully" in { val resultF1 = sut.track(input(1)) consumer.requestNext() val resultF = resultF1.flatMap(_ => sut.track(input(2)))(DirectExecutionContext) consumer.requestNext() whenReady(resultF)(_ => Succeeded) } } "input is submitted, and the queue is backpressuring" should { "return a RESOURCE_EXHAUSTED error" in { sut.track(input(1)) whenReady(sut.track(input(2)).failed)(IsStatusException(Status.RESOURCE_EXHAUSTED)) } } "input is submitted, and the queue has been completed" should { "return an ABORTED error" in { queue.complete() whenReady(sut.track(input(2)).failed)(IsStatusException(Status.ABORTED)) } } "input is submitted, and the queue has failed" should { "return an ABORTED error" in { queue.fail(TestingException("The queue fails with this error.")) whenReady(sut.track(input(2)).failed)(IsStatusException(Status.ABORTED)) } } } }
Example 30
Source File: ExpiringStreamServiceCallAuthTests.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.platform.sandbox.auth import java.time.Duration import com.daml.grpc.{GrpcException, GrpcStatus} import com.daml.platform.sandbox.services.SubmitAndWaitDummyCommand import com.daml.platform.testing.StreamConsumer import com.daml.timer.Delayed import io.grpc.Status import io.grpc.stub.StreamObserver import scala.concurrent.duration.DurationInt import scala.concurrent.{Future, Promise} import scala.util.control.NonFatal trait ExpiringStreamServiceCallAuthTests[T] extends ReadOnlyServiceCallAuthTests with SubmitAndWaitDummyCommand { protected def stream: Option[String] => StreamObserver[T] => Unit private def expectExpiration(token: String): Future[Unit] = { val promise = Promise[Unit]() stream(Option(token))(new StreamObserver[T] { @volatile private[this] var gotSomething = false def onNext(value: T): Unit = { gotSomething = true } def onError(t: Throwable): Unit = { t match { case GrpcException(GrpcStatus(Status.Code.PERMISSION_DENIED, _), _) if gotSomething => val _ = promise.trySuccess(()) case NonFatal(e) => val _ = promise.tryFailure(e) } } def onCompleted(): Unit = { val _ = promise.tryFailure(new RuntimeException("stream completed before token expiration")) } }) promise.future } private def canActAsMainActorExpiresInFiveSeconds = toHeader(expiringIn(Duration.ofSeconds(5), readWriteToken(mainActor))) private def canReadAsMainActorExpiresInFiveSeconds = toHeader(expiringIn(Duration.ofSeconds(5), readOnlyToken(mainActor))) it should "break a stream in flight upon read-only token expiration" in { val _ = Delayed.Future.by(10.seconds)(submitAndWait()) expectExpiration(canReadAsMainActorExpiresInFiveSeconds).map(_ => succeed) } it should "break a stream in flight upon read/write token expiration" in { val _ = Delayed.Future.by(10.seconds)(submitAndWait()) expectExpiration(canActAsMainActorExpiresInFiveSeconds).map(_ => succeed) } override def serviceCallWithToken(token: Option[String]): Future[Any] = submitAndWait().flatMap(_ => new StreamConsumer[T](stream(token)).first()) }
Example 31
Source File: GrpcHealthService.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.platform.server.api.services.grpc import akka.NotUsed import akka.stream.Materializer import akka.stream.scaladsl.Source import com.daml.grpc.adapter.ExecutionSequencerFactory import com.daml.dec.DirectExecutionContext import com.daml.ledger.api.health.HealthChecks import com.daml.platform.api.grpc.GrpcApiService import com.daml.platform.server.api.DropRepeated import com.daml.platform.server.api.services.grpc.GrpcHealthService._ import io.grpc.health.v1.health.{ HealthAkkaGrpc, HealthCheckRequest, HealthCheckResponse, HealthGrpc } import io.grpc.{ServerServiceDefinition, Status, StatusException} import scala.concurrent.duration.{DurationInt, FiniteDuration} import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success, Try} class GrpcHealthService( healthChecks: HealthChecks, maximumWatchFrequency: FiniteDuration = 1.second, )( implicit protected val esf: ExecutionSequencerFactory, protected val mat: Materializer, executionContext: ExecutionContext, ) extends HealthAkkaGrpc with GrpcApiService { override def bindService(): ServerServiceDefinition = HealthGrpc.bindService(this, DirectExecutionContext) override def check(request: HealthCheckRequest): Future[HealthCheckResponse] = Future.fromTry(matchResponse(serviceFrom(request))) override def watchSource(request: HealthCheckRequest): Source[HealthCheckResponse, NotUsed] = Source .fromIterator(() => Iterator.continually(matchResponse(serviceFrom(request)).get)) .throttle(1, per = maximumWatchFrequency) .via(DropRepeated()) private def matchResponse(componentName: Option[String]): Try[HealthCheckResponse] = if (!componentName.forall(healthChecks.hasComponent)) Failure(new StatusException(Status.NOT_FOUND)) else if (healthChecks.isHealthy(componentName)) Success(servingResponse) else Success(notServingResponse) } object GrpcHealthService { private[grpc] val servingResponse = HealthCheckResponse(HealthCheckResponse.ServingStatus.SERVING) private[grpc] val notServingResponse = HealthCheckResponse(HealthCheckResponse.ServingStatus.NOT_SERVING) private def serviceFrom(request: HealthCheckRequest): Option[String] = { Option(request.service).filter(_.nonEmpty) } }
Example 32
Source File: Assertions.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.ledger.api.testtool.infrastructure import ai.x.diff.DiffShow import com.daml.grpc.{GrpcException, GrpcStatus} import java.util.regex.Pattern import io.grpc.Status import scala.language.higherKinds import scala.util.control.NonFatal object Assertions extends DiffExtensions { def fail(message: String): Nothing = throw new AssertionError(message) def fail(message: String, cause: Throwable): Nothing = throw new AssertionError(message, cause) def assertLength[A, F[_] <: Seq[_]](context: String, length: Int, as: F[A]): F[A] = { assert(as.length == length, s"$context: expected $length item(s), got ${as.length}") as } def assertSingleton[A](context: String, as: Seq[A]): A = assertLength(context, 1, as).head def assertEquals[T: DiffShow](context: String, actual: T, expected: T): Unit = { val diff = DiffShow.diff(actual, expected) if (!diff.isIdentical) throw AssertionErrorWithPreformattedMessage( diff.string, s"$context: two objects are supposed to be equal but they are not", ) } def assertGrpcError(t: Throwable, expectedCode: Status.Code, pattern: String): Unit = { assertGrpcError( t, expectedCode, if (pattern.isEmpty) None else Some(Pattern.compile(Pattern.quote(pattern)))) } }
Example 33
Source File: LedgerConfigurationServiceIT.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.ledger.api.testtool.tests import com.daml.ledger.api.testtool.infrastructure.Allocation._ import com.daml.ledger.api.testtool.infrastructure.Assertions._ import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite import com.daml.ledger.test.model.Test.Dummy import io.grpc.Status class LedgerConfigurationServiceIT extends LedgerTestSuite { test("ConfigSucceeds", "Return a valid configuration for a valid request", allocate(NoParties))( implicit ec => { case Participants(Participant(ledger)) => for { config <- ledger.configuration() } yield { assert( config.maxDeduplicationTime.isDefined, "The maxDeduplicationTime field of the configuration is empty") } }) test("ConfigLedgerId", "Return NOT_FOUND to invalid ledger identifier", allocate(NoParties))( implicit ec => { case Participants(Participant(ledger)) => val invalidLedgerId = "THIS_IS_AN_INVALID_LEDGER_ID" for { failure <- ledger.configuration(overrideLedgerId = Some(invalidLedgerId)).failed } yield { assertGrpcError( failure, Status.Code.NOT_FOUND, s"Ledger ID '$invalidLedgerId' not found.") } }) test( "CSLSuccessIfMaxDedplicationTimeRight", "Submission returns OK if deduplication time is within the accepted interval", allocate(SingleParty), )(implicit ec => { case Participants(Participant(ledger, party)) => // Submission using the maximum allowed deduplication time val request = ledger.submitRequest(party, Dummy(party).create.command) for { config <- ledger.configuration() maxDedupTime = config.maxDeduplicationTime.get _ <- ledger.submit(request.update(_.commands.deduplicationTime := maxDedupTime)) } yield { // No assertions to make, since the command went through as expected } }) test( "CSLSuccessIfMaxDeduplicationTimeExceeded", "Submission returns OK if deduplication time is too high", allocate(SingleParty), )(implicit ec => { case Participants(Participant(ledger, party)) => val request = ledger.submitRequest(party, Dummy(party).create.command) for { config <- ledger.configuration() maxDedupTime = config.maxDeduplicationTime.get failure <- ledger .submit( request.update(_.commands.deduplicationTime := maxDedupTime.update( _.seconds := maxDedupTime.seconds + 1))) .failed } yield { assertGrpcError(failure, Status.Code.INVALID_ARGUMENT, "") } }) }
Example 34
Source File: PackageManagementServiceIT.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.ledger.api.testtool.tests import com.daml.ledger.api.testtool.infrastructure.Allocation._ import com.daml.ledger.api.testtool.infrastructure.Assertions._ import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite import com.daml.ledger.packagemanagementtest.PackageManagementTest.PackageManagementTestTemplate import com.daml.ledger.packagemanagementtest.PackageManagementTest.PackageManagementTestTemplate._ import com.google.protobuf.ByteString import io.grpc.Status import scala.concurrent.{ExecutionContext, Future} final class PackageManagementServiceIT extends LedgerTestSuite { private[this] val testPackageResourcePath = "/ledger/ledger-api-test-tool/PackageManagementTest.dar" private def loadTestPackage()(implicit ec: ExecutionContext): Future[ByteString] = { val testPackage = Future { val in = getClass.getResourceAsStream(testPackageResourcePath) assert(in != null, s"Unable to load test package resource at '$testPackageResourcePath'") in } val bytes = testPackage.map(ByteString.readFrom) bytes.onComplete(_ => testPackage.map(_.close())) bytes } test( "PackageManagementEmptyUpload", "An attempt at uploading an empty payload should fail", allocate(NoParties), )(implicit ec => { case Participants(Participant(ledger)) => for { failure <- ledger.uploadDarFile(ByteString.EMPTY).failed } yield { assertGrpcError( failure, Status.Code.INVALID_ARGUMENT, "Invalid argument: Invalid DAR: package-upload", ) } }) test( "PackageManagementLoad", "Concurrent uploads of the same package should be idempotent and result in the package being available for use", allocate(SingleParty), )(implicit ec => { case Participants(Participant(ledger, party)) => for { testPackage <- loadTestPackage() _ <- Future.sequence(Vector.fill(8)(ledger.uploadDarFile(testPackage))) knownPackages <- ledger.listKnownPackages() contract <- ledger.create(party, new PackageManagementTestTemplate(party)) acsBefore <- ledger.activeContracts(party) _ <- ledger.exercise(party, contract.exerciseTestChoice) acsAfter <- ledger.activeContracts(party) } yield { val duplicatePackageIds = knownPackages.groupBy(_.packageId).mapValues(_.size).filter(_._2 > 1) assert( duplicatePackageIds.isEmpty, s"There are duplicate package identifiers: ${duplicatePackageIds map { case (name, count) => s"$name ($count)" } mkString (", ")}", ) assert( acsBefore.size == 1, "After the contract has been created there should be one active contract but there's none", ) assert( acsAfter.isEmpty, s"There should be no active package after the contract has been consumed: ${acsAfter.map(_.contractId).mkString(", ")}", ) } }) }
Example 35
Source File: PackageServiceIT.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.ledger.api.testtool.tests import com.daml.ledger.api.testtool.infrastructure.Allocation._ import com.daml.ledger.api.testtool.infrastructure.Assertions._ import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite import io.grpc.Status final class PackageServiceIT extends LedgerTestSuite { private[this] val unknownPackageId = " " test("PackagesList", "Listing packages should return a result", allocate(NoParties))(implicit ec => { case Participants(Participant(ledger)) => for { knownPackages <- ledger.listPackages() } yield assert( knownPackages.size >= 3, s"List of packages was expected to contain at least 3 packages, got ${knownPackages.size} instead.", ) }) test("PackagesGet", "Getting package content should return a valid result", allocate(NoParties))( implicit ec => { case Participants(Participant(ledger)) => for { somePackageId <- ledger .listPackages() .map(_.headOption.getOrElse(fail("No package found"))) somePackage <- ledger.getPackage(somePackageId) } yield { assert(somePackage.hash.length > 0, s"Package $somePackageId has an empty hash.") assert( somePackage.hash == somePackageId, s"Package $somePackageId has hash ${somePackage.hash}, expected hash to be equal to the package ID.", ) assert(somePackage.archivePayload.size() >= 0, s"Package $somePackageId has zero size.") } }) test( "PackagesGetUnknown", "Getting package content for an unknown package should fail", allocate(NoParties), )(implicit ec => { case Participants(Participant(ledger)) => for { failure <- ledger.getPackage(unknownPackageId).failed } yield { assertGrpcError(failure, Status.Code.NOT_FOUND, "") } }) test( "PackagesStatus", "Getting package status should return a valid result", allocate(NoParties))(implicit ec => { case Participants(Participant(ledger)) => for { somePackageId <- ledger.listPackages().map(_.headOption.getOrElse(fail("No package found"))) status <- ledger.getPackageStatus(somePackageId) } yield { assert(status.isRegistered, s"Package $somePackageId is not registered.") } }) test( "PackagesStatusUnknown", "Getting package status for an unknown package should fail", allocate(NoParties), )(implicit ec => { case Participants(Participant(ledger)) => for { status <- ledger.getPackageStatus(unknownPackageId) } yield { assert(status.isUnknown, s"Package $unknownPackageId is not unknown.") } }) }
Example 36
Source File: ClosedWorldIT.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.ledger.api.testtool.tests import com.daml.ledger.api.testtool.infrastructure.Allocation.{ Participant, Participants, SingleParty, allocate } import com.daml.ledger.api.testtool.infrastructure.Assertions.assertGrpcError import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite import com.daml.ledger.client.binding import com.daml.ledger.test.semantic.SemanticTests.{Amount, Iou} import io.grpc.Status class ClosedWorldIT extends LedgerTestSuite { private[this] val onePound = Amount(BigDecimal(1), "GBP") test( "ClosedWorldObserver", "Cannot execute a transaction that references unallocated observer parties", allocate(SingleParty), )(implicit ec => { case Participants(Participant(alpha, payer)) => for { failure <- alpha .create(payer, Iou(payer, binding.Primitive.Party("unallocated"), onePound)) .failed } yield { assertGrpcError(failure, Status.Code.INVALID_ARGUMENT, "Party not known on ledger") } }) }
Example 37
Source File: IsStatusException.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.ledger.api.testing.utils import com.daml.grpc.{GrpcException, GrpcStatus} import io.grpc.Status import org.scalatest.{Assertion, Matchers} import scala.util.control.NonFatal object IsStatusException extends Matchers { def apply(expectedStatusCode: Status.Code)(throwable: Throwable): Assertion = { throwable match { case GrpcException(GrpcStatus(code, _), _) => code shouldEqual expectedStatusCode case NonFatal(other) => fail(s"$other is not a gRPC Status exception.") } } def apply(expectedStatus: Status): Throwable => Assertion = { apply(expectedStatus.getCode) } }
Example 38
Source File: ReferenceImplementation.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.grpc.sampleservice.implementations import com.daml.grpc.sampleservice.Responding import com.daml.platform.hello.HelloServiceGrpc.HelloService import com.daml.platform.hello.{HelloRequest, HelloResponse, HelloServiceGrpc} import io.grpc.stub.StreamObserver import io.grpc.{BindableService, ServerServiceDefinition, Status} import scala.concurrent.ExecutionContext class ReferenceImplementation extends HelloService with Responding with BindableService with AutoCloseable { override def close(): Unit = () override def bindService(): ServerServiceDefinition = HelloServiceGrpc.bindService(this, ExecutionContext.global) override def serverStreaming( request: HelloRequest, responseObserver: StreamObserver[HelloResponse], ): Unit = { validateRequest(request) for (i <- 1.to(request.reqInt)) responseObserver.onNext(HelloResponse(i)) responseObserver.onCompleted() } private def validateRequest(request: HelloRequest): Unit = if (request.reqInt < 0) throw Status.INVALID_ARGUMENT .withDescription("request cannot be negative") .asRuntimeException() }
Example 39
Source File: ResultAssertions.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.grpc.adapter.client import com.daml.platform.hello.HelloResponse import com.google.protobuf.ByteString import io.grpc.{Status, StatusRuntimeException} import org.scalatest.{Assertion, Matchers} import scala.util.Random trait ResultAssertions { self: Matchers => protected def elemCount: Int = 1024 protected lazy val elemRange: Range = 1.to(elemCount) protected lazy val halfCount: Int = elemCount / 2 protected lazy val halfRange: Range = elemRange.take(halfCount) protected def isCancelledException(err: Throwable): Assertion = { err shouldBe a[StatusRuntimeException] err.asInstanceOf[StatusRuntimeException].getStatus.getCode shouldEqual Status.CANCELLED.getCode } protected def assertElementsAreInOrder(expectedCount: Long)( results: Seq[HelloResponse] ): Assertion = { results should have length expectedCount results.map(_.respInt) shouldEqual (1 to expectedCount.toInt) } protected def elementsAreSummed(results: Seq[HelloResponse]): Assertion = { results should have length 1 results.foldLeft(0)(_ + _.respInt) shouldEqual elemRange.sum } protected def everyElementIsDoubled(results: Seq[HelloResponse]): Assertion = { results should have length elemCount.toLong //the order does matter results.map(_.respInt) shouldEqual elemRange.map(_ * 2) } protected def genPayload(): ByteString = { val bytes = new Array[Byte](1024) Random.nextBytes(bytes) ByteString.copyFrom(bytes) } }
Example 40
Source File: PlaySpecs2Spec.scala From play-grpc with Apache License 2.0 | 5 votes |
package play.grpc.specs2 import org.junit.runner.RunWith import org.specs2.runner.JUnitRunner import play.api.inject.bind import play.api.inject.guice.GuiceApplicationBuilder import play.api.libs.ws.WSClient import play.api.libs.ws.WSRequest import play.api.routing.Router import play.api.test._ import akka.grpc.internal.GrpcProtocolNative import example.myapp.helloworld.grpc.helloworld._ import io.grpc.Status @RunWith(classOf[JUnitRunner]) class PlaySpecs2Spec extends ForServer with ServerGrpcClient with PlaySpecification with ApplicationFactories { protected def applicationFactory: ApplicationFactory = withGuiceApp(GuiceApplicationBuilder().overrides(bind[Router].to[GreeterServiceImpl])) // RICH: Still need to work out how to make WSClient work properly with endpoints def wsUrl(path: String)(implicit running: RunningServer): WSRequest = { val ws = running.app.injector.instanceOf[WSClient] val url = running.endpoints.httpEndpoint.get.pathUrl(path) ws.url(url) } "A Play server bound to a gRPC router" should { "give a 404 when routing a non-gRPC request" >> { implicit rs: RunningServer => val result = await(wsUrl("/").get) result.status must ===(404) // Maybe should be a 426, see #396 } "give a 415 error when not using a gRPC content-type" >> { implicit rs: RunningServer => val result = await(wsUrl(s"/${GreeterService.name}/FooBar").get) result.status must ===(415) // Maybe should be a 426, see #396 } "give a grpc UNIMPLEMENTED when routing a non-existent gRPC method" >> { implicit rs: RunningServer => val result = await( wsUrl(s"/${GreeterService.name}/FooBar") .addHttpHeaders("Content-Type" -> GrpcProtocolNative.contentType.toString) .get, ) result.status must ===(200) // Maybe should be a 426, see #396 result.header("grpc-status") must beSome(Status.Code.UNIMPLEMENTED.value().toString) } "give a grpc INVALID_ARGUMENT error when routing an empty request to a gRPC method" >> { implicit rs: RunningServer => val result = await( wsUrl(s"/${GreeterService.name}/SayHello") .addHttpHeaders("Content-Type" -> GrpcProtocolNative.contentType.toString) .get, ) result.status must ===(200) // Maybe should be a 426, see #396 // grpc-status 3 means INVALID_ARGUMENT error. See https://developers.google.com/maps-booking/reference/grpc-api/status_codes result.header("grpc-status") must beSome(Status.Code.INVALID_ARGUMENT.value().toString) } "work with a gRPC client" >> { implicit rs: RunningServer => withGrpcClient[GreeterServiceClient] { client: GreeterServiceClient => val reply = await(client.sayHello(HelloRequest("Alice"))) reply.message must ===("Hello, Alice!") } } } }
Example 41
Source File: GrpcStatus.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.grpc import com.google.rpc.status.{Status => ProtobufStatus} import io.grpc.Status import io.grpc.Status.Code object GrpcStatus { type Description = Option[String] def unapply(status: Status): Some[(Code, Description)] = Some((status.getCode, Option(status.getDescription))) def toProto(code: Code, description: Description): ProtobufStatus = ProtobufStatus(code.value, description.getOrElse("")) def toProto(status: Status): ProtobufStatus = toProto(status.getCode, Option(status.getDescription)) private[grpc] final class SpecificGrpcStatus(code: Code) { def unapply(status: Status): Boolean = status.getCode == code } val OK = new SpecificGrpcStatus(Code.OK) val CANCELLED = new SpecificGrpcStatus(Code.CANCELLED) val UNKNOWN = new SpecificGrpcStatus(Code.UNKNOWN) val INVALID_ARGUMENT = new SpecificGrpcStatus(Code.INVALID_ARGUMENT) val DEADLINE_EXCEEDED = new SpecificGrpcStatus(Code.DEADLINE_EXCEEDED) val NOT_FOUND = new SpecificGrpcStatus(Code.NOT_FOUND) val ALREADY_EXISTS = new SpecificGrpcStatus(Code.ALREADY_EXISTS) val PERMISSION_DENIED = new SpecificGrpcStatus(Code.PERMISSION_DENIED) val RESOURCE_EXHAUSTED = new SpecificGrpcStatus(Code.RESOURCE_EXHAUSTED) val FAILED_PRECONDITION = new SpecificGrpcStatus(Code.FAILED_PRECONDITION) val ABORTED = new SpecificGrpcStatus(Code.ABORTED) val OUT_OF_RANGE = new SpecificGrpcStatus(Code.OUT_OF_RANGE) val UNIMPLEMENTED = new SpecificGrpcStatus(Code.UNIMPLEMENTED) val INTERNAL = new SpecificGrpcStatus(Code.INTERNAL) val UNAVAILABLE = new SpecificGrpcStatus(Code.UNAVAILABLE) val DATA_LOSS = new SpecificGrpcStatus(Code.DATA_LOSS) val UNAUTHENTICATED = new SpecificGrpcStatus(Code.UNAUTHENTICATED) }
Example 42
Source File: GrpcException.scala From daml with Apache License 2.0 | 5 votes |
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package com.daml.grpc import com.daml.grpc.GrpcStatus.SpecificGrpcStatus import io.grpc.{Metadata, Status, StatusException, StatusRuntimeException} object GrpcException { def unapply(exception: Exception): Option[(Status, Metadata)] = exception match { case e: StatusRuntimeException => Some((e.getStatus, e.getTrailers)) case e: StatusException => Some((e.getStatus, e.getTrailers)) case _ => None } private[grpc] final class SpecificGrpcException(status: SpecificGrpcStatus) { def unapply(exception: Exception): Boolean = exception match { case e: StatusRuntimeException => status.unapply(e.getStatus) case e: StatusException => status.unapply(e.getStatus) case _ => false } } val OK = new SpecificGrpcException(GrpcStatus.OK) val CANCELLED = new SpecificGrpcException(GrpcStatus.CANCELLED) val UNKNOWN = new SpecificGrpcException(GrpcStatus.UNKNOWN) val INVALID_ARGUMENT = new SpecificGrpcException(GrpcStatus.INVALID_ARGUMENT) val DEADLINE_EXCEEDED = new SpecificGrpcException(GrpcStatus.DEADLINE_EXCEEDED) val NOT_FOUND = new SpecificGrpcException(GrpcStatus.NOT_FOUND) val ALREADY_EXISTS = new SpecificGrpcException(GrpcStatus.ALREADY_EXISTS) val PERMISSION_DENIED = new SpecificGrpcException(GrpcStatus.PERMISSION_DENIED) val RESOURCE_EXHAUSTED = new SpecificGrpcException(GrpcStatus.RESOURCE_EXHAUSTED) val FAILED_PRECONDITION = new SpecificGrpcException(GrpcStatus.FAILED_PRECONDITION) val ABORTED = new SpecificGrpcException(GrpcStatus.ABORTED) val OUT_OF_RANGE = new SpecificGrpcException(GrpcStatus.OUT_OF_RANGE) val UNIMPLEMENTED = new SpecificGrpcException(GrpcStatus.UNIMPLEMENTED) val INTERNAL = new SpecificGrpcException(GrpcStatus.INTERNAL) val UNAVAILABLE = new SpecificGrpcException(GrpcStatus.UNAVAILABLE) val DATA_LOSS = new SpecificGrpcException(GrpcStatus.DATA_LOSS) val UNAUTHENTICATED = new SpecificGrpcException(GrpcStatus.UNAUTHENTICATED) }
Example 43
Source File: GRPCErrors.scala From matcher with MIT License | 5 votes |
package com.wavesplatform.dex.grpc.integration.protobuf import com.wavesplatform.api.http.ApiError import com.wavesplatform.api.http.ApiError._ import io.grpc.Metadata.AsciiMarshaller import io.grpc.{Metadata, Status, StatusException} object GRPCErrors { private[this] val IntMarshaller: AsciiMarshaller[Int] = new AsciiMarshaller[Int] { override def toAsciiString(value: Int): String = value.toString override def parseAsciiString(serialized: String): Int = serialized.toInt } val ErrorCodeKey = Metadata.Key.of("Error-Code", IntMarshaller) def toStatusException(api: ApiError): StatusException = { val code = api match { case WalletNotExist | WalletAddressDoesNotExist | TransactionDoesNotExist | AliasDoesNotExist(_) | BlockDoesNotExist | MissingSenderPrivateKey | DataKeyDoesNotExist => Status.NOT_FOUND case WalletAlreadyExists => Status.ALREADY_EXISTS case WalletLocked => Status.PERMISSION_DENIED case _ => Status.INVALID_ARGUMENT } val metadata = new Metadata() metadata.put(ErrorCodeKey, api.id) code.withDescription(api.message).asException(metadata) } }
Example 44
Source File: GrpcAkkaStreamsClientCalls.scala From grpcakkastream with MIT License | 5 votes |
package grpc.akkastreams import java.util.concurrent.atomic.{AtomicBoolean, AtomicReference} import akka.NotUsed import akka.stream.scaladsl.{Flow, Source} import com.trueaccord.scalapb.grpc.Grpc import io.grpc.{ClientCall, Metadata, Status} import io.grpc.stub._ object GrpcAkkaStreamsClientCalls { def unaryFlow[I, O](call: ClientCall[I, O]): Flow[I, O, NotUsed] = Flow[I].flatMapConcat(request => Source.fromFuture( Grpc.guavaFuture2ScalaFuture( ClientCalls.futureUnaryCall(call, request) ) ) ) def serverStreamingFlow[I, O](call: ClientCall[I, O]): Flow[I, O, NotUsed] = Flow.fromGraph( new GrpcGraphStage[I, O](outputObserver => { val out = outputObserver.asInstanceOf[ClientResponseObserver[I, O]] val in = new ClientCallStreamObserver[I] { val halfClosed = new AtomicBoolean(false) val onReadyHandler = new AtomicReference[Option[Runnable]](None) val listener = new ClientCall.Listener[O] { override def onClose(status: Status, trailers: Metadata): Unit = status.getCode match { case Status.Code.OK => out.onCompleted() case _ => out.onError(status.asException(trailers)) } override def onMessage(message: O): Unit = out.onNext(message) override def onReady(): Unit = onReadyHandler.get().foreach(_.run()) } call.start(listener, new Metadata()) override def cancel(message: String, cause: Throwable): Unit = call.cancel(message, cause) override def setOnReadyHandler(onReadyHandler: Runnable): Unit = this.onReadyHandler.set(Some(onReadyHandler)) override def request(count: Int): Unit = call.request(count) override def disableAutoInboundFlowControl(): Unit = () override def isReady: Boolean = !halfClosed.get() || call.isReady override def setMessageCompression(enable: Boolean): Unit = call.setMessageCompression(enable) override def onError(t: Throwable): Unit = call.cancel("Cancelled by client with StreamObserver.onError()", t) override def onCompleted(): Unit = () override def onNext(request: I): Unit = { call.sendMessage(request) halfClosed.set(true) call.halfClose() } } out.beforeStart(in) in }) ) def clientStreamingFlow[I, O](call: ClientCall[I, O]): Flow[I, O, NotUsed] = Flow.fromGraph(new GrpcGraphStage[I, O](ClientCalls.asyncClientStreamingCall(call, _))) def bidiStreamingFlow[I, O](call: ClientCall[I, O]): Flow[I, O, NotUsed] = Flow.fromGraph(new GrpcGraphStage[I, O](ClientCalls.asyncBidiStreamingCall(call, _))) }
Example 45
Source File: Fs2StreamClientCallListener.scala From fs2-grpc with MIT License | 5 votes |
package org.lyranthe.fs2_grpc package java_runtime package client import cats.effect.{Effect, ConcurrentEffect} import cats.implicits._ import fs2.{Pull, Stream} import fs2.concurrent.Queue import io.grpc.{ClientCall, Metadata, Status} class Fs2StreamClientCallListener[F[_]: Effect, Response]( request: Int => Unit, queue: Queue[F, Either[GrpcStatus, Response]] ) extends ClientCall.Listener[Response] { override def onMessage(message: Response): Unit = { request(1) queue.enqueue1(message.asRight).unsafeRun() } override def onClose(status: Status, trailers: Metadata): Unit = queue.enqueue1(GrpcStatus(status, trailers).asLeft).unsafeRun() def stream: Stream[F, Response] = { def go(q: Stream[F, Either[GrpcStatus, Response]]): Pull[F, Response, Unit] = { q.pull.uncons1.flatMap { case Some((Right(v), tl)) => Pull.output1(v) >> go(tl) case Some((Left(GrpcStatus(status, trailers)), _)) => if (!status.isOk) Pull.raiseError[F](status.asRuntimeException(trailers)) else Pull.done case None => Pull.done } } go(queue.dequeue).stream } } object Fs2StreamClientCallListener { def apply[F[_]: ConcurrentEffect, Response](request: Int => Unit): F[Fs2StreamClientCallListener[F, Response]] = Queue.unbounded[F, Either[GrpcStatus, Response]].map(new Fs2StreamClientCallListener[F, Response](request, _)) }
Example 46
Source File: Fs2ServerCallListener.scala From fs2-grpc with MIT License | 5 votes |
package org.lyranthe.fs2_grpc package java_runtime package server import cats.effect._ import cats.effect.concurrent.Deferred import cats.implicits._ import fs2.Stream import io.grpc.{Metadata, Status, StatusException, StatusRuntimeException} private[server] trait Fs2ServerCallListener[F[_], G[_], Request, Response] { def source: G[Request] def isCancelled: Deferred[F, Unit] def call: Fs2ServerCall[F, Request, Response] private def reportError(t: Throwable)(implicit F: Sync[F]): F[Unit] = { t match { case ex: StatusException => call.closeStream(ex.getStatus, Option(ex.getTrailers).getOrElse(new Metadata())) case ex: StatusRuntimeException => call.closeStream(ex.getStatus, Option(ex.getTrailers).getOrElse(new Metadata())) case ex => // TODO: Customize failure trailers? call.closeStream(Status.INTERNAL.withDescription(ex.getMessage).withCause(ex), new Metadata()) } } private def handleUnaryResponse(headers: Metadata, response: F[Response])(implicit F: Sync[F]): F[Unit] = call.sendHeaders(headers) *> call.request(1) *> response >>= call.sendMessage private def handleStreamResponse(headers: Metadata, response: Stream[F, Response])(implicit F: Sync[F]): F[Unit] = call.sendHeaders(headers) *> call.request(1) *> response.evalMap(call.sendMessage).compile.drain private def unsafeRun(f: F[Unit])(implicit F: ConcurrentEffect[F]): Unit = { val bracketed = F.guaranteeCase(f) { case ExitCase.Completed => call.closeStream(Status.OK, new Metadata()) case ExitCase.Canceled => call.closeStream(Status.CANCELLED, new Metadata()) case ExitCase.Error(t) => reportError(t) } // Exceptions are reported by closing the call F.runAsync(F.race(bracketed, isCancelled.get))(_ => IO.unit).unsafeRunSync() } def unsafeUnaryResponse(headers: Metadata, implementation: G[Request] => F[Response])(implicit F: ConcurrentEffect[F] ): Unit = unsafeRun(handleUnaryResponse(headers, implementation(source))) def unsafeStreamResponse(headers: Metadata, implementation: G[Request] => Stream[F, Response])(implicit F: ConcurrentEffect[F] ): Unit = unsafeRun(handleStreamResponse(headers, implementation(source))) }
Example 47
Source File: DummyServerCall.scala From fs2-grpc with MIT License | 5 votes |
package org.lyranthe.fs2_grpc.java_runtime.server import io.grpc.{Metadata, MethodDescriptor, ServerCall, Status} import scala.collection.mutable.ArrayBuffer class DummyServerCall extends ServerCall[String, Int] { val messages: ArrayBuffer[Int] = ArrayBuffer[Int]() var currentStatus: Option[Status] = None override def request(numMessages: Int): Unit = () override def sendMessage(message: Int): Unit = { messages += message () } override def sendHeaders(headers: Metadata): Unit = { () } override def getMethodDescriptor: MethodDescriptor[String, Int] = ??? override def close(status: Status, trailers: Metadata): Unit = { currentStatus = Some(status) } override def isCancelled: Boolean = false }
Example 48
Source File: RetryPolicyDefaults.scala From akka-cloudpubsub with Apache License 2.0 | 5 votes |
package com.qubit.pubsub.client.retry import java.util.concurrent.Executors import com.gilt.gfc.concurrent.ThreadFactoryBuilder import com.typesafe.scalalogging.LazyLogging import io.grpc.{Status, StatusRuntimeException} import scala.concurrent.ExecutionContext import scala.util.Failure object RetryPolicyDefaults extends LazyLogging { import atmos.dsl._ import Slf4jSupport._ import scala.concurrent.duration._ private val unrecoverableErrorCodes = Set(Status.Code.PERMISSION_DENIED, Status.Code.UNAUTHENTICATED, Status.Code.INVALID_ARGUMENT) private val rateLimitingErrorCodes = Set(Status.Code.RESOURCE_EXHAUSTED, Status.Code.UNAVAILABLE) val retryPolicy = retryFor { 10.attempts } using selectedBackoff { case Failure(sre: StatusRuntimeException) if rateLimitingErrorCodes.contains(sre.getStatus.getCode) => linearBackoff { 50.seconds } case _ => exponentialBackoff { 30.seconds } randomized 10.second -> 100.seconds } monitorWith { logger.underlying } onError { case sre: StatusRuntimeException if unrecoverableErrorCodes.contains(sre.getStatus.getCode) => stopRetrying } val retryExecCtx = ExecutionContext.fromExecutor( Executors.newFixedThreadPool( 10, ThreadFactoryBuilder("retry-pool", "retry-worker").build() )) }
Example 49
Source File: StatusExtract.scala From gatling-grpc with Apache License 2.0 | 5 votes |
package com.github.phisgr.gatling.grpc.check import io.gatling.commons.validation.SuccessWrapper import io.gatling.core.Predef.value2Expression import io.gatling.core.check._ import io.grpc.Status private[gatling] object StatusExtract { val StatusDescription: ValidatorCheckBuilder[StatusExtract, Status, String] = ValidatorCheckBuilder( extractor = new FindExtractor[Status, String]( name = "grpcStatusDescription", extractor = status => Option(status.getDescription).success ), displayActualValue = true ) val StatusCode: ValidatorCheckBuilder[StatusExtract, Status, Status.Code] = ValidatorCheckBuilder( extractor = new FindExtractor[Status, Status.Code]( name = "grpcStatusCode", extractor = status => Some(status.getCode).success ), displayActualValue = true ) object Materializer extends CheckMaterializer[StatusExtract, GrpcCheck[Any], GrpcResponse[Any], Status]( specializer = GrpcCheck(_, GrpcCheck.Status) ) { override protected def preparer: Preparer[GrpcResponse[Any], Status] = _.status.success } val DefaultCheck: GrpcCheck[Any] = StatusCode.is(value2Expression(Status.Code.OK)).build(Materializer) } // phantom type for implicit materializer resolution trait StatusExtract
Example 50
Source File: GrpcCheckSupport.scala From gatling-grpc with Apache License 2.0 | 5 votes |
package com.github.phisgr.gatling.grpc.check import io.gatling.core.check.{CheckBuilder, CheckMaterializer, DefaultMultipleFindCheckBuilder, FindCheckBuilder, ValidatorCheckBuilder} import io.grpc.{Metadata, Status} trait GrpcCheckSupport { val statusCode = StatusExtract.StatusCode val statusDescription = StatusExtract.StatusDescription def extract[T, X](f: T => Option[X]): ValidatorCheckBuilder[ResponseExtract, T, X] = ResponseExtract.extract(f) def extractMultiple[T, X](f: T => Option[Seq[X]]): DefaultMultipleFindCheckBuilder[ResponseExtract, T, X] = ResponseExtract.extractMultiple(f) def trailer[T](key: Metadata.Key[T]): DefaultMultipleFindCheckBuilder[TrailersExtract, Metadata, T] = TrailersExtract.trailer(key) implicit def resMat[Res]: CheckMaterializer[ResponseExtract, GrpcCheck[Res], GrpcResponse[Res], Res] = ResponseExtract.materializer[Res] implicit val statusMat: CheckMaterializer[StatusExtract, GrpcCheck[Any], GrpcResponse[Any], Status] = StatusExtract.Materializer implicit val trailersMat: CheckMaterializer[TrailersExtract, GrpcCheck[Any], GrpcResponse[Any], Metadata] = TrailersExtract.Materializer // The contravarianceHelper is needed because without it, the implicit conversion does not turn // CheckBuilder[StatusExtract, GrpcResponse[Any], X] into a GrpcCheck[Res] // Despite GrpcCheck[Any] is a subtype of GrpcCheck[Res]. implicit def checkBuilder2GrpcCheck[A, P, X, ResOrAny, Res](checkBuilder: CheckBuilder[A, P, X])( implicit materializer: CheckMaterializer[A, GrpcCheck[ResOrAny], GrpcResponse[ResOrAny], P], contravarianceHelper: GrpcCheck[ResOrAny] => GrpcCheck[Res] ): GrpcCheck[Res] = contravarianceHelper(checkBuilder.build(materializer)) implicit def validatorCheckBuilder2GrpcCheck[A, P, X, ResOrAny, Res](vCheckBuilder: ValidatorCheckBuilder[A, P, X])( implicit materializer: CheckMaterializer[A, GrpcCheck[ResOrAny], GrpcResponse[ResOrAny], P], contravarianceHelper: GrpcCheck[ResOrAny] => GrpcCheck[Res] ): GrpcCheck[Res] = vCheckBuilder.exists implicit def findCheckBuilder2GrpcCheck[A, P, X, ResOrAny, Res](findCheckBuilder: FindCheckBuilder[A, P, X])( implicit materializer: CheckMaterializer[A, GrpcCheck[ResOrAny], GrpcResponse[ResOrAny], P], contravarianceHelper: GrpcCheck[ResOrAny] => GrpcCheck[Res] ): GrpcCheck[Res] = findCheckBuilder.find.exists implicit def someWrapper[T](value: T): SomeWrapper[T] = new SomeWrapper(value) }
Example 51
Source File: util.scala From gatling-grpc with Apache License 2.0 | 5 votes |
package com.github.phisgr.gatling.grpc.check import io.gatling.commons.validation.{Failure, Success, Validation} import io.grpc.{Metadata, Status} import scala.annotation.unchecked.uncheckedVariance case class GrpcResponse[+T]( private val res: T, // can be null if status is not OK status: Status, trailers: Metadata ) { private var _validation: Validation[T@uncheckedVariance] = _ // Hand-rolling lazy val because lazy is thread-safe def validation: Validation[T] = { if (_validation eq null) { _validation = if (status.isOk) { Success(res) } else { val description = status.getDescription Failure(if (description eq null) status.getCode.toString else s"${status.getCode}: $description") } } _validation } } class SomeWrapper[T](val value: T) extends AnyVal { def some: Some[T] = Some(value) }