├── vertx-grpc-it ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── MANIFEST.MF │ │ └── java │ │ │ └── io │ │ │ └── vertx │ │ │ └── grpc │ │ │ └── it │ │ │ └── Noop.java │ └── test │ │ ├── proto │ │ ├── streaming.proto │ │ ├── optionals.proto │ │ ├── hello_streaming.proto │ │ ├── empty.proto │ │ ├── helloworld.proto │ │ ├── test.proto │ │ └── messages.proto │ │ └── java │ │ └── io │ │ └── vertx │ │ └── grpc │ │ └── it │ │ ├── ProxyTestBase.java │ │ └── ProxyTest.java └── pom.xml ├── vertx-grpc-client ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── MANIFEST.MF │ │ ├── java │ │ │ ├── examples │ │ │ │ ├── EmptyOrBuilder.java │ │ │ │ ├── ItemOrBuilder.java │ │ │ │ ├── HelloRequestOrBuilder.java │ │ │ │ ├── HelloReplyOrBuilder.java │ │ │ │ ├── HelloWorldProto.java │ │ │ │ └── StreamingProto.java │ │ │ └── io │ │ │ │ └── vertx │ │ │ │ └── grpc │ │ │ │ └── client │ │ │ │ ├── package-info.java │ │ │ │ ├── GrpcClientChannel.java │ │ │ │ ├── GrpcClientResponse.java │ │ │ │ ├── impl │ │ │ │ ├── GrpcClientImpl.java │ │ │ │ └── GrpcClientResponseImpl.java │ │ │ │ ├── GrpcClientRequest.java │ │ │ │ ├── GrpcClient.java │ │ │ │ └── VertxClientCall.java │ │ ├── proto │ │ │ ├── streaming.proto │ │ │ └── helloworld.proto │ │ └── asciidoc │ │ │ └── client.adoc │ └── test │ │ ├── proto │ │ ├── streaming.proto │ │ ├── optionals.proto │ │ ├── hello_streaming.proto │ │ ├── empty.proto │ │ ├── helloworld.proto │ │ └── test.proto │ │ └── java │ │ └── io │ │ └── vertx │ │ └── grpc │ │ └── client │ │ └── ClientTestBase.java └── pom.xml ├── vertx-grpc-common ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── MANIFEST.MF │ │ ├── java │ │ │ └── io │ │ │ │ └── vertx │ │ │ │ └── grpc │ │ │ │ └── common │ │ │ │ ├── package-info.java │ │ │ │ ├── CodecException.java │ │ │ │ ├── GrpcMessage.java │ │ │ │ ├── impl │ │ │ │ ├── GrpcMethodCall.java │ │ │ │ ├── Utils.java │ │ │ │ ├── BridgeMessageDecoder.java │ │ │ │ ├── ReadStreamAdapter.java │ │ │ │ ├── GrpcMessageImpl.java │ │ │ │ ├── WriteStreamAdapter.java │ │ │ │ ├── ServiceNameImpl.java │ │ │ │ └── BridgeMessageEncoder.java │ │ │ │ ├── GrpcWriteStream.java │ │ │ │ ├── GrpcStatus.java │ │ │ │ ├── ServiceName.java │ │ │ │ ├── GrpcReadStream.java │ │ │ │ ├── GrpcError.java │ │ │ │ ├── GrpcMessageEncoder.java │ │ │ │ └── GrpcMessageDecoder.java │ │ └── asciidoc │ │ │ └── index.adoc │ └── test │ │ └── java │ │ └── io │ │ └── vertx │ │ └── grpc │ │ └── common │ │ ├── ServiceNameTest.java │ │ ├── UtilsTest.java │ │ └── GrpcTestBase.java └── pom.xml ├── vertx-grpc-server ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── MANIFEST.MF │ │ ├── java │ │ │ ├── examples │ │ │ │ ├── EmptyOrBuilder.java │ │ │ │ ├── ItemOrBuilder.java │ │ │ │ ├── HelloRequestOrBuilder.java │ │ │ │ ├── HelloReplyOrBuilder.java │ │ │ │ ├── HelloWorldProto.java │ │ │ │ └── StreamingProto.java │ │ │ └── io │ │ │ │ └── vertx │ │ │ │ └── grpc │ │ │ │ └── server │ │ │ │ ├── package-info.java │ │ │ │ ├── GrpcServiceBridge.java │ │ │ │ ├── GrpcServerResponse.java │ │ │ │ ├── GrpcServerRequest.java │ │ │ │ ├── GrpcServer.java │ │ │ │ └── impl │ │ │ │ ├── GrpcServerRequestImpl.java │ │ │ │ └── GrpcServerImpl.java │ │ ├── proto │ │ │ ├── streaming.proto │ │ │ └── helloworld.proto │ │ └── asciidoc │ │ │ └── server.adoc │ └── test │ │ ├── proto │ │ ├── streaming.proto │ │ ├── optionals.proto │ │ ├── hello_streaming.proto │ │ ├── empty.proto │ │ ├── helloworld.proto │ │ └── test.proto │ │ └── java │ │ └── io │ │ └── vertx │ │ └── grpc │ │ └── server │ │ └── ServerTestBase.java └── pom.xml ├── vertx-grpc-context-storage ├── src │ ├── main │ │ ├── java │ │ │ ├── io │ │ │ │ ├── vertx │ │ │ │ │ └── grpc │ │ │ │ │ │ └── contextstorage │ │ │ │ │ │ └── DumbClass.java │ │ │ │ └── grpc │ │ │ │ │ └── override │ │ │ │ │ └── ContextStorageOverride.java │ │ │ └── examples │ │ │ │ └── GrpcContextStorageExamples.java │ │ └── asciidoc │ │ │ └── storage.adoc │ └── test │ │ ├── proto │ │ └── helloworld.proto │ │ └── java │ │ └── io │ │ └── vertx │ │ └── grpc │ │ └── context │ │ └── storage │ │ └── ContextStorageTest.java └── pom.xml ├── .editorconfig ├── .gitignore ├── README.md ├── .github ├── workflows │ ├── ci-4.x.yml │ ├── ci.yml │ ├── ci-5.x.yml │ └── deploy.yml ├── maven-ci-settings.xml └── maven-cd-settings.xml └── pom.xml /vertx-grpc-it/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Automatic-Module-Name: io.vertx.grpc.client 2 | 3 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Automatic-Module-Name: io.vertx.grpc.common 2 | 3 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Automatic-Module-Name: io.vertx.grpc.server 2 | 3 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/main/java/io/vertx/grpc/it/Noop.java: -------------------------------------------------------------------------------- 1 | package io.vertx.grpc.it; 2 | 3 | public class Noop { 4 | private Noop() { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /vertx-grpc-context-storage/src/main/java/io/vertx/grpc/contextstorage/DumbClass.java: -------------------------------------------------------------------------------- 1 | package io.vertx.grpc.contextstorage; 2 | 3 | /** 4 | * Seems necessary to generate javadoc jar 5 | */ 6 | public class DumbClass { 7 | } 8 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/examples/EmptyOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: streaming.proto 3 | 4 | package examples; 5 | 6 | public interface EmptyOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:streaming.Empty) 8 | com.google.protobuf.MessageOrBuilder { 9 | } 10 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/examples/EmptyOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: streaming.proto 3 | 4 | package examples; 5 | 6 | public interface EmptyOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:streaming.Empty) 8 | com.google.protobuf.MessageOrBuilder { 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | [Makefile] 12 | indent_style = tab 13 | 14 | [**/examples/**.java] 15 | # 84 looks like a odd number, however 16 | # it accounts for 4 spaces (class and example method indentation) 17 | max_line_length = 84 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vertx 2 | .DS_Store 3 | .gradle 4 | .idea 5 | .classpath 6 | .project 7 | .settings 8 | .yardoc 9 | .yardopts 10 | build 11 | target 12 | out 13 | *.iml 14 | *.ipr 15 | *.iws 16 | test-output 17 | Scratch.java 18 | ScratchTest.java 19 | test-results 20 | test-tmp 21 | *.class 22 | ScratchPad.java 23 | src/main/resources/ext-js/*.js 24 | src/main/java/io/vertx/java/**/*.java 25 | *.swp 26 | .vscode 27 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/proto/streaming.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "examples"; 5 | option java_outer_classname = "StreamingProto"; 6 | option objc_class_prefix = "RTG"; 7 | 8 | package streaming; 9 | 10 | // Interface exported by the server. 11 | service Streaming { 12 | rpc Source(Empty) returns (stream Item) {} 13 | rpc Sink(stream Item) returns (Empty) {} 14 | rpc Pipe(stream Item) returns (stream Item) {} 15 | } 16 | 17 | message Item { 18 | string value = 1; 19 | } 20 | 21 | message Empty { 22 | } 23 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/proto/streaming.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "examples"; 5 | option java_outer_classname = "StreamingProto"; 6 | option objc_class_prefix = "RTG"; 7 | 8 | package streaming; 9 | 10 | // Interface exported by the server. 11 | service Streaming { 12 | rpc Source(Empty) returns (stream Item) {} 13 | rpc Sink(stream Item) returns (Empty) {} 14 | rpc Pipe(stream Item) returns (stream Item) {} 15 | } 16 | 17 | message Item { 18 | string value = 1; 19 | } 20 | 21 | message Empty { 22 | } 23 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/proto/streaming.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.grpc.examples.streaming"; 5 | option java_outer_classname = "StreamingProto"; 6 | option objc_class_prefix = "RTG"; 7 | 8 | package streaming; 9 | 10 | // Interface exported by the server. 11 | service Streaming { 12 | rpc Source(Empty) returns (stream Item) {} 13 | rpc Sink(stream Item) returns (Empty) {} 14 | rpc Pipe(stream Item) returns (stream Item) {} 15 | } 16 | 17 | message Item { 18 | string value = 1; 19 | } 20 | 21 | message Empty { 22 | } -------------------------------------------------------------------------------- /vertx-grpc-client/src/test/proto/streaming.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.grpc.examples.streaming"; 5 | option java_outer_classname = "StreamingProto"; 6 | option objc_class_prefix = "RTG"; 7 | 8 | package streaming; 9 | 10 | // Interface exported by the server. 11 | service Streaming { 12 | rpc Source(Empty) returns (stream Item) {} 13 | rpc Sink(stream Item) returns (Empty) {} 14 | rpc Pipe(stream Item) returns (stream Item) {} 15 | } 16 | 17 | message Item { 18 | string value = 1; 19 | } 20 | 21 | message Empty { 22 | } -------------------------------------------------------------------------------- /vertx-grpc-server/src/test/proto/streaming.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.grpc.examples.streaming"; 5 | option java_outer_classname = "StreamingProto"; 6 | option objc_class_prefix = "RTG"; 7 | 8 | package streaming; 9 | 10 | // Interface exported by the server. 11 | service Streaming { 12 | rpc Source(Empty) returns (stream Item) {} 13 | rpc Sink(stream Item) returns (Empty) {} 14 | rpc Pipe(stream Item) returns (stream Item) {} 15 | } 16 | 17 | message Item { 18 | string value = 1; 19 | } 20 | 21 | message Empty { 22 | } -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/examples/ItemOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: streaming.proto 3 | 4 | package examples; 5 | 6 | public interface ItemOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:streaming.Item) 8 | com.google.protobuf.MessageOrBuilder { 9 | 10 | /** 11 | * string value = 1; 12 | * @return The value. 13 | */ 14 | java.lang.String getValue(); 15 | /** 16 | * string value = 1; 17 | * @return The bytes for value. 18 | */ 19 | com.google.protobuf.ByteString 20 | getValueBytes(); 21 | } 22 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/examples/ItemOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: streaming.proto 3 | 4 | package examples; 5 | 6 | public interface ItemOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:streaming.Item) 8 | com.google.protobuf.MessageOrBuilder { 9 | 10 | /** 11 | * string value = 1; 12 | * @return The value. 13 | */ 14 | java.lang.String getValue(); 15 | /** 16 | * string value = 1; 17 | * @return The bytes for value. 18 | */ 19 | com.google.protobuf.ByteString 20 | getValueBytes(); 21 | } 22 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/examples/HelloRequestOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: helloworld.proto 3 | 4 | package examples; 5 | 6 | public interface HelloRequestOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:helloworld.HelloRequest) 8 | com.google.protobuf.MessageOrBuilder { 9 | 10 | /** 11 | * string name = 1; 12 | * @return The name. 13 | */ 14 | java.lang.String getName(); 15 | /** 16 | * string name = 1; 17 | * @return The bytes for name. 18 | */ 19 | com.google.protobuf.ByteString 20 | getNameBytes(); 21 | } 22 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/examples/HelloRequestOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: helloworld.proto 3 | 4 | package examples; 5 | 6 | public interface HelloRequestOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:helloworld.HelloRequest) 8 | com.google.protobuf.MessageOrBuilder { 9 | 10 | /** 11 | * string name = 1; 12 | * @return The name. 13 | */ 14 | java.lang.String getName(); 15 | /** 16 | * string name = 1; 17 | * @return The bytes for name. 18 | */ 19 | com.google.protobuf.ByteString 20 | getNameBytes(); 21 | } 22 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/proto/optionals.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.grpc.examples.optionals"; 5 | option java_outer_classname = "OptionalsProto"; 6 | 7 | package optionals; 8 | 9 | // The greeting service definition. 10 | service Greeter { 11 | // Sends a greeting 12 | rpc SayHello (HelloRequest) returns (HelloReply) {} 13 | } 14 | 15 | // The request message containing the user's name. 16 | message HelloRequest { 17 | string name = 1; 18 | optional int32 age = 2; 19 | } 20 | 21 | // The response message containing the greetings 22 | message HelloReply { 23 | string message = 1; 24 | } 25 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/examples/HelloReplyOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: helloworld.proto 3 | 4 | package examples; 5 | 6 | public interface HelloReplyOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:helloworld.HelloReply) 8 | com.google.protobuf.MessageOrBuilder { 9 | 10 | /** 11 | * string message = 1; 12 | * @return The message. 13 | */ 14 | java.lang.String getMessage(); 15 | /** 16 | * string message = 1; 17 | * @return The bytes for message. 18 | */ 19 | com.google.protobuf.ByteString 20 | getMessageBytes(); 21 | } 22 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/test/proto/optionals.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.grpc.examples.optionals"; 5 | option java_outer_classname = "OptionalsProto"; 6 | 7 | package optionals; 8 | 9 | // The greeting service definition. 10 | service Greeter { 11 | // Sends a greeting 12 | rpc SayHello (HelloRequest) returns (HelloReply) {} 13 | } 14 | 15 | // The request message containing the user's name. 16 | message HelloRequest { 17 | string name = 1; 18 | optional int32 age = 2; 19 | } 20 | 21 | // The response message containing the greetings 22 | message HelloReply { 23 | string message = 1; 24 | } 25 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/examples/HelloReplyOrBuilder.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: helloworld.proto 3 | 4 | package examples; 5 | 6 | public interface HelloReplyOrBuilder extends 7 | // @@protoc_insertion_point(interface_extends:helloworld.HelloReply) 8 | com.google.protobuf.MessageOrBuilder { 9 | 10 | /** 11 | * string message = 1; 12 | * @return The message. 13 | */ 14 | java.lang.String getMessage(); 15 | /** 16 | * string message = 1; 17 | * @return The bytes for message. 18 | */ 19 | com.google.protobuf.ByteString 20 | getMessageBytes(); 21 | } 22 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/test/proto/optionals.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.grpc.examples.optionals"; 5 | option java_outer_classname = "OptionalsProto"; 6 | 7 | package optionals; 8 | 9 | // The greeting service definition. 10 | service Greeter { 11 | // Sends a greeting 12 | rpc SayHello (HelloRequest) returns (HelloReply) {} 13 | } 14 | 15 | // The request message containing the user's name. 16 | message HelloRequest { 17 | string name = 1; 18 | optional int32 age = 2; 19 | } 20 | 21 | // The response message containing the greetings 22 | message HelloReply { 23 | string message = 1; 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status (5.x)](https://github.com/eclipse-vertx/vertx-grpc/actions/workflows/ci-5.x.yml/badge.svg)](https://github.com/eclipse-vertx/vertx-grpc/actions/workflows/ci-5.x.yml) 2 | [![Build Status (4.x)](https://github.com/eclipse-vertx/vertx-grpc/actions/workflows/ci-4.x.yml/badge.svg)](https://github.com/eclipse-vertx/vertx-grpc/actions/workflows/ci-4.x.yml) 3 | 4 | # Vert.x gRPC 5 | 6 | Vert.x gRPC is a gRPC implementation based on Vert.x, it aims to implement an application level API as well as a request/response oriented API 7 | to write gRPC middlewares like reverse proxies. 8 | 9 | # License 10 | 11 | Eclipse Public License - Version 1.0 / Apache License - Version 2.0 12 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/io/vertx/grpc/client/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | @ModuleGen(name = "vertx-grpc-client", groupPackage = "io.vertx", useFutures = true) 12 | package io.vertx.grpc.client; 13 | 14 | import io.vertx.codegen.annotations.ModuleGen; 15 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | @ModuleGen(name = "vertx-grpc-common", groupPackage = "io.vertx", useFutures = true) 12 | package io.vertx.grpc.common; 13 | 14 | import io.vertx.codegen.annotations.ModuleGen; 15 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/io/vertx/grpc/server/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | @ModuleGen(name = "vertx-grpc-server", groupPackage = "io.vertx", useFutures = true) 12 | package io.vertx.grpc.server; 13 | 14 | import io.vertx.codegen.annotations.ModuleGen; 15 | -------------------------------------------------------------------------------- /.github/workflows/ci-4.x.yml: -------------------------------------------------------------------------------- 1 | name: vertx-grpc (4.x) 2 | on: 3 | schedule: 4 | - cron: '0 4 * * *' 5 | jobs: 6 | CI: 7 | strategy: 8 | matrix: 9 | include: 10 | - os: ubuntu-latest 11 | jdk: 8 12 | - os: ubuntu-latest 13 | jdk: 17 14 | uses: ./.github/workflows/ci.yml 15 | with: 16 | branch: 4.x 17 | jdk: ${{ matrix.jdk }} 18 | os: ${{ matrix.os }} 19 | secrets: inherit 20 | Deploy: 21 | if: ${{ github.repository_owner == 'eclipse-vertx' && (github.event_name == 'push' || github.event_name == 'schedule') }} 22 | needs: CI 23 | uses: ./.github/workflows/deploy.yml 24 | with: 25 | branch: 4.x 26 | jdk: 8 27 | secrets: inherit 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | workflow_call: 4 | inputs: 5 | branch: 6 | required: true 7 | type: string 8 | jdk: 9 | default: 8 10 | type: string 11 | os: 12 | default: ubuntu-latest 13 | type: string 14 | jobs: 15 | Test: 16 | name: Run tests 17 | runs-on: ${{ inputs.os }} 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 21 | with: 22 | ref: ${{ inputs.branch }} 23 | - name: Install JDK 24 | uses: actions/setup-java@v2 25 | with: 26 | java-version: ${{ inputs.jdk }} 27 | distribution: temurin 28 | - name: Run tests 29 | run: mvn -s .github/maven-ci-settings.xml -q clean verify -B 30 | -------------------------------------------------------------------------------- /vertx-grpc-context-storage/src/main/java/examples/GrpcContextStorageExamples.java: -------------------------------------------------------------------------------- 1 | package examples; 2 | 3 | import io.grpc.Context; 4 | import io.vertx.core.Vertx; 5 | import io.vertx.docgen.Source; 6 | 7 | @Source 8 | @SuppressWarnings("unused") 9 | public class GrpcContextStorageExamples { 10 | 11 | public void example(Vertx vertx) { 12 | Context grpcCtx1 = Context.current(); 13 | 14 | vertx.executeBlocking(prom -> { 15 | 16 | // Same as grpcCtx1 17 | Context grpcCtx2 = Context.current(); 18 | 19 | String result = doSomething(); 20 | prom.complete(result); 21 | 22 | }).onComplete(ar -> { 23 | 24 | // Same as grpcCtx1 and grpcCtx2 25 | Context grpcCtx3 = Context.current(); 26 | 27 | }); 28 | } 29 | 30 | private String doSomething() { 31 | return null; 32 | } 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/java/io/vertx/grpc/it/ProxyTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.it; 12 | 13 | import io.vertx.ext.unit.junit.VertxUnitRunner; 14 | import io.vertx.grpc.common.GrpcTestBase; 15 | import org.junit.runner.RunWith; 16 | 17 | /** 18 | * @author Julien Viet 19 | */ 20 | @RunWith(VertxUnitRunner.class) 21 | public abstract class ProxyTestBase extends GrpcTestBase { 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/ci-5.x.yml: -------------------------------------------------------------------------------- 1 | name: vertx-grpc (5.x) 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | schedule: 10 | - cron: '0 5 * * *' 11 | jobs: 12 | CI: 13 | strategy: 14 | matrix: 15 | include: 16 | - os: ubuntu-latest 17 | jdk: 8 18 | - os: ubuntu-latest 19 | jdk: 17 20 | uses: ./.github/workflows/ci.yml 21 | with: 22 | branch: ${{ github.event.pull_request.head.sha || github.ref_name }} 23 | jdk: ${{ matrix.jdk }} 24 | os: ${{ matrix.os }} 25 | secrets: inherit 26 | Deploy: 27 | if: ${{ github.repository_owner == 'eclipse-vertx' && (github.event_name == 'push' || github.event_name == 'schedule') }} 28 | needs: CI 29 | uses: ./.github/workflows/deploy.yml 30 | with: 31 | branch: ${{ github.event.pull_request.head.sha || github.ref_name }} 32 | jdk: 8 33 | secrets: inherit 34 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/test/java/io/vertx/grpc/common/ServiceNameTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import org.junit.Test; 14 | 15 | import java.util.Arrays; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | 19 | public class ServiceNameTest { 20 | 21 | @Test 22 | public void testServiceName() { 23 | for (ServiceName sn : Arrays.asList(ServiceName.create("com.examples.MyService"), ServiceName.create("com.examples", "MyService"))) { 24 | assertEquals("com.examples", sn.packageName()); 25 | assertEquals("MyService", sn.name()); 26 | assertEquals("com.examples.MyService", sn.fullyQualifiedName()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | on: 3 | workflow_call: 4 | inputs: 5 | branch: 6 | required: true 7 | type: string 8 | jdk: 9 | default: 8 10 | type: string 11 | jobs: 12 | Deploy: 13 | name: Deploy to OSSRH 14 | runs-on: ubuntu-latest 15 | env: 16 | VERTX_NEXUS_USERNAME: ${{ secrets.VERTX_NEXUS_USERNAME }} 17 | VERTX_NEXUS_PASSWORD: ${{ secrets.VERTX_NEXUS_PASSWORD }} 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 21 | with: 22 | ref: ${{ inputs.branch }} 23 | - name: Install JDK 24 | uses: actions/setup-java@v2 25 | with: 26 | java-version: ${{ inputs.jdk }} 27 | distribution: temurin 28 | - name: Get project version 29 | run: echo "PROJECT_VERSION=$(mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version -B | grep -v '\[')" >> $GITHUB_ENV 30 | - name: Maven deploy 31 | if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }} 32 | run: mvn deploy -s .github/maven-cd-settings.xml -DskipTests -B 33 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/CodecException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | /** 14 | * An encoding/decoding exception. 15 | */ 16 | public class CodecException extends RuntimeException { 17 | 18 | public CodecException() { 19 | } 20 | 21 | public CodecException(String message) { 22 | super(message); 23 | } 24 | 25 | public CodecException(String message, Throwable cause) { 26 | super(message, cause); 27 | } 28 | 29 | public CodecException(Throwable cause) { 30 | super(cause); 31 | } 32 | 33 | public CodecException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 34 | super(message, cause, enableSuppression, writableStackTrace); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/GrpcMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import io.vertx.codegen.annotations.VertxGen; 14 | import io.vertx.core.buffer.Buffer; 15 | import io.vertx.grpc.common.impl.GrpcMessageImpl; 16 | 17 | /** 18 | * A generic gRPC message 19 | * 20 | * @author Julien Viet 21 | */ 22 | @VertxGen 23 | public interface GrpcMessage { 24 | 25 | /** 26 | * @return a new message 27 | */ 28 | static GrpcMessage message(String encoding, Buffer payload) { 29 | return new GrpcMessageImpl(encoding, payload); 30 | } 31 | 32 | /** 33 | * @return the message encoding 34 | */ 35 | String encoding(); 36 | 37 | /** 38 | * @return the message payload, usually in Protobuf format encoded in the {@link #encoding()} format 39 | */ 40 | Buffer payload(); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/test/proto/hello_streaming.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | syntax = "proto3"; 15 | 16 | option java_multiple_files = true; 17 | option java_package = "io.grpc.examples.manualflowcontrol"; 18 | option java_outer_classname = "HelloStreamingProto"; 19 | option objc_class_prefix = "HLWS"; 20 | 21 | package manualflowcontrol; 22 | 23 | // The greeting service definition. 24 | service StreamingGreeter { 25 | // Streams a many greetings 26 | rpc SayHelloStreaming (stream HelloRequest) returns (stream HelloReply) {} 27 | } 28 | 29 | // The request message containing the user's name. 30 | message HelloRequest { 31 | string name = 1; 32 | } 33 | 34 | // The response message containing the greetings 35 | message HelloReply { 36 | string message = 1; 37 | } 38 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/proto/hello_streaming.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | syntax = "proto3"; 15 | 16 | option java_multiple_files = true; 17 | option java_package = "io.grpc.examples.manualflowcontrol"; 18 | option java_outer_classname = "HelloStreamingProto"; 19 | option objc_class_prefix = "HLWS"; 20 | 21 | package manualflowcontrol; 22 | 23 | // The greeting service definition. 24 | service StreamingGreeter { 25 | // Streams a many greetings 26 | rpc SayHelloStreaming (stream HelloRequest) returns (stream HelloReply) {} 27 | } 28 | 29 | // The request message containing the user's name. 30 | message HelloRequest { 31 | string name = 1; 32 | } 33 | 34 | // The response message containing the greetings 35 | message HelloReply { 36 | string message = 1; 37 | } 38 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/test/proto/hello_streaming.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | syntax = "proto3"; 15 | 16 | option java_multiple_files = true; 17 | option java_package = "io.grpc.examples.manualflowcontrol"; 18 | option java_outer_classname = "HelloStreamingProto"; 19 | option objc_class_prefix = "HLWS"; 20 | 21 | package manualflowcontrol; 22 | 23 | // The greeting service definition. 24 | service StreamingGreeter { 25 | // Streams a many greetings 26 | rpc SayHelloStreaming (stream HelloRequest) returns (stream HelloReply) {} 27 | } 28 | 29 | // The request message containing the user's name. 30 | message HelloRequest { 31 | string name = 1; 32 | } 33 | 34 | // The response message containing the greetings 35 | message HelloReply { 36 | string message = 1; 37 | } 38 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/asciidoc/index.adoc: -------------------------------------------------------------------------------- 1 | = Vert.x gRPC 2 | 3 | The best description of gRPC can be seen at wikipedia. 4 | 5 | [quote, wikipedia, wikipedia] 6 | ____ 7 | gRPC is an open source remote procedure call (RPC) system initially developed at Google. It uses HTTP/2 for 8 | transport, Protocol Buffers as the interface description language, and provides features such as authentication, 9 | bidirectional streaming and flow control, blocking or nonblocking bindings, and cancellation and timeouts. It 10 | generates cross-platform client and server bindings for many languages. 11 | ____ 12 | 13 | Vert.x gRPC is a module that will align the programming style of Google gRPC with Vert.x style. As a user of this 14 | module you will be more familiar with the code style using Vert.x Streams and Futures while benefiting from all the 15 | benefits of gRPC. 16 | 17 | For more information related to gRPC please consult the official documentation site http://www.grpc.io/. 18 | 19 | WARNING: Since Vert.x 4.3, this module is the new support for gRPC in the Vert.x stack, the previous implementation based 20 | on gRPC Netty is still available and has been renamed Vert.x gRPC Netty, it can be found at https://vertx.io/docs/vertx-grpc-netty/java/ . 21 | This module has _Tech Preview_ status, this means the API can change between versions. 22 | 23 | Vert.x gRPC is split into three parts: 24 | 25 | - Vert.x gRPC Server 26 | - Vert.x gRPC Client 27 | - Vert.x gRPC Context Storage 28 | 29 | include::server.adoc[] 30 | 31 | include::client.adoc[] 32 | 33 | include::storage.adoc[] 34 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/GrpcMethodCall.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.vertx.grpc.common.ServiceName; 14 | 15 | public class GrpcMethodCall { 16 | 17 | private String path; 18 | private String fullMethodName; 19 | private ServiceName serviceName; 20 | private String methodName; 21 | 22 | public GrpcMethodCall(String path) { 23 | this.path = path; 24 | } 25 | 26 | public String fullMethodName() { 27 | if (fullMethodName == null) { 28 | fullMethodName = path.substring(1); 29 | } 30 | return fullMethodName; 31 | } 32 | 33 | public ServiceName serviceName() { 34 | if (serviceName == null) { 35 | int idx1 = path.lastIndexOf('.'); 36 | int idx2 = path.lastIndexOf('/'); 37 | serviceName = ServiceName.create(path.substring(1, idx1), path.substring(idx1 + 1, idx2)); 38 | } 39 | return serviceName; 40 | } 41 | 42 | public String methodName() { 43 | if (methodName == null) { 44 | int idx = path.lastIndexOf('/'); 45 | methodName = path.substring(idx); 46 | } 47 | return methodName; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2023 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.grpc.InternalMetadata; 14 | import io.grpc.Metadata; 15 | import io.netty.util.AsciiString; 16 | import io.vertx.core.MultiMap; 17 | 18 | import java.nio.charset.StandardCharsets; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | public class Utils { 23 | 24 | public static void writeMetadata(Metadata metadata, MultiMap mmap) { 25 | byte[][] t = InternalMetadata.serialize(metadata); 26 | for (int i = 0; i < t.length; i += 2) { 27 | mmap.add(new AsciiString(t[i], false), new AsciiString(t[i + 1], false)); 28 | } 29 | } 30 | 31 | public static Metadata readMetadata(MultiMap headers) { 32 | List> entries = headers.entries(); 33 | byte[][] abc = new byte[entries.size() * 2][]; 34 | int idx = 0; 35 | for (Map.Entry entry : entries) { 36 | abc[idx++] = entry.getKey().getBytes(StandardCharsets.UTF_8); 37 | abc[idx++] = entry.getValue().getBytes(StandardCharsets.UTF_8); 38 | } 39 | return InternalMetadata.newMetadata(abc); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vertx-grpc-context-storage/src/main/asciidoc/storage.adoc: -------------------------------------------------------------------------------- 1 | == Vert.x gRPC Context Storage 2 | 3 | Vert.x gRPC Context Storage overrides the default `io.grpc.Context.Storage` implementation. 4 | 5 | The default implementation always stores the gRPC context in a _thread-local_ variable. 6 | This implementation stores the gRPC context the same way as Vert.x core stores request tracing data. 7 | 8 | This means, for example, that when you implement a service method, the gRPC context is propagated across Vert.x async API calls: 9 | 10 | [source,java] 11 | ---- 12 | {@link examples.GrpcContextStorageExamples#example} 13 | ---- 14 | 15 | [CAUTION] 16 | ==== 17 | The gRPC context is propagated across Vert.x async API calls only when the current Vert.x {@link io.vertx.core.Context} is bound to a Vert.x HTTP server request. 18 | 19 | It is not propagated if, for example, you invoke a stub on a non-Vert.x thread or from a verticle {@link io.vertx.core.Verticle#start} method. 20 | ==== 21 | 22 | === Using Vert.x gRPC Context Storage 23 | 24 | To use Vert.x gRPC Context Storage, add the following dependency to the _dependencies_ section of your build descriptor: 25 | 26 | * Maven (in your `pom.xml`): 27 | 28 | [source,xml,subs="+attributes"] 29 | ---- 30 | 31 | io.vertx 32 | vertx-grpc-context-storage 33 | ${maven.version} 34 | 35 | ---- 36 | 37 | * Gradle (in your `build.gradle` file): 38 | 39 | [source,groovy,subs="+attributes"] 40 | ---- 41 | dependencies { 42 | compile 'io.vertx:vertx-grpc-context-storage:${maven.version}' 43 | } 44 | ---- 45 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/BridgeMessageDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.grpc.Decompressor; 14 | import io.grpc.MethodDescriptor; 15 | import io.vertx.grpc.common.GrpcMessage; 16 | import io.vertx.grpc.common.GrpcMessageDecoder; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.IOException; 20 | 21 | public class BridgeMessageDecoder implements GrpcMessageDecoder { 22 | 23 | private MethodDescriptor.Marshaller marshaller; 24 | private Decompressor decompressor; 25 | 26 | public BridgeMessageDecoder(MethodDescriptor.Marshaller marshaller, Decompressor decompressor) { 27 | this.marshaller = marshaller; 28 | this.decompressor = decompressor; 29 | } 30 | 31 | @Override 32 | public T decode(GrpcMessage msg) { 33 | if (msg.encoding().equals("identity")) { 34 | return marshaller.parse(new ByteArrayInputStream(msg.payload().getBytes())); 35 | } else { 36 | try { 37 | return marshaller.parse(decompressor.decompress(new ByteArrayInputStream(msg.payload().getBytes()))); 38 | } catch (IOException e) { 39 | throw new RuntimeException(e); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/io/vertx/grpc/server/GrpcServiceBridge.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.server; 12 | 13 | import io.grpc.BindableService; 14 | import io.grpc.ServerServiceDefinition; 15 | import io.vertx.grpc.server.impl.GrpcServiceBridgeImpl; 16 | 17 | /** 18 | * Bridge a gRPC service with a {@link GrpcServer}. 19 | */ 20 | public interface GrpcServiceBridge { 21 | 22 | /** 23 | * Create a stub for a given {@code service}. 24 | * 25 | * @param service the service 26 | * @return the stub 27 | */ 28 | static GrpcServiceBridge bridge(ServerServiceDefinition service) { 29 | return new GrpcServiceBridgeImpl(service); 30 | } 31 | 32 | /** 33 | * Create a stub for a given {@code service}. 34 | * 35 | * @param service the service 36 | * @return the stub 37 | */ 38 | static GrpcServiceBridge bridge(BindableService service) { 39 | return bridge(service.bindService()); 40 | } 41 | 42 | /** 43 | * Bind all service methods to the @{code server}. 44 | * 45 | * @param server the server to bind to 46 | */ 47 | void bind(GrpcServer server); 48 | 49 | /** 50 | * Unbind all service methods from the @{code server}. 51 | * 52 | * @param server the server to unbind from 53 | */ 54 | void unbind(GrpcServer server); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/GrpcWriteStream.java: -------------------------------------------------------------------------------- 1 | package io.vertx.grpc.common; 2 | 3 | import io.vertx.codegen.annotations.Fluent; 4 | import io.vertx.codegen.annotations.Nullable; 5 | import io.vertx.codegen.annotations.VertxGen; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.Handler; 8 | import io.vertx.core.MultiMap; 9 | import io.vertx.core.streams.WriteStream; 10 | 11 | @VertxGen 12 | public interface GrpcWriteStream extends WriteStream { 13 | 14 | /** 15 | * @return the {@link MultiMap} to reader metadata headers 16 | */ 17 | MultiMap headers(); 18 | 19 | /** 20 | * Set the stream encoding, e.g {@code identity} or {@code gzip}. 21 | * 22 | * It must be called before sending any message, otherwise {@code identity will be used. 23 | * 24 | * @param encoding the target message encoding 25 | * @return a reference to this, so the API can be used fluently 26 | */ 27 | @Fluent 28 | GrpcWriteStream encoding(String encoding); 29 | 30 | @Override 31 | GrpcWriteStream exceptionHandler(@Nullable Handler handler); 32 | 33 | @Override 34 | GrpcWriteStream setWriteQueueMaxSize(int i); 35 | 36 | @Override 37 | GrpcWriteStream drainHandler(@Nullable Handler handler); 38 | 39 | /** 40 | * Write an encoded gRPC message. 41 | * 42 | * @param message the message 43 | * @return a future completed with the result 44 | */ 45 | Future writeMessage(GrpcMessage message); 46 | 47 | /** 48 | * End the stream with an encoded gRPC message. 49 | * 50 | * @param message the message 51 | * @return a future completed with the result 52 | */ 53 | Future endMessage(GrpcMessage message); 54 | 55 | /** 56 | * Cancel the stream. 57 | */ 58 | void cancel(); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/ReadStreamAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.vertx.grpc.common.GrpcReadStream; 14 | 15 | import java.util.LinkedList; 16 | 17 | /** 18 | * An adapter between gRPC and Vert.x back-pressure. 19 | */ 20 | public class ReadStreamAdapter { 21 | 22 | private GrpcReadStream stream; 23 | private int request = 0; 24 | 25 | /** 26 | * Init the adapter with the stream. 27 | */ 28 | public final void init(GrpcReadStream stream, BridgeMessageDecoder decoder) { 29 | stream.messageHandler(msg -> { 30 | handleMessage(decoder.decode(msg)); 31 | }); 32 | stream.endHandler(v -> { 33 | handleClose(); 34 | }); 35 | this.stream = stream; 36 | stream.pause(); 37 | if (request > 0) { 38 | stream.fetch(request); 39 | } 40 | } 41 | 42 | /** 43 | * Override this to handle close event 44 | */ 45 | protected void handleClose() { 46 | 47 | } 48 | 49 | /** 50 | * Override this to handle message event 51 | */ 52 | protected void handleMessage(T msg) { 53 | 54 | } 55 | 56 | /** 57 | * Request {@code num} messages 58 | */ 59 | public final void request(int num) { 60 | if (stream != null) { 61 | stream.fetch(num); 62 | } else { 63 | request += num; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/GrpcMessageImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.netty.buffer.ByteBuf; 14 | import io.netty.buffer.CompositeByteBuf; 15 | import io.netty.buffer.Unpooled; 16 | import io.vertx.core.buffer.Buffer; 17 | import io.vertx.grpc.common.GrpcMessage; 18 | 19 | public class GrpcMessageImpl implements GrpcMessage { 20 | 21 | private final String encoding; 22 | private final Buffer payload; 23 | 24 | public GrpcMessageImpl(String encoding, Buffer payload) { 25 | this.encoding = encoding; 26 | this.payload = payload; 27 | } 28 | 29 | @Override 30 | public String encoding() { 31 | return encoding; 32 | } 33 | 34 | @Override 35 | public Buffer payload() { 36 | return payload; 37 | } 38 | 39 | public static Buffer encode(GrpcMessage message) { 40 | ByteBuf bbuf = message.payload().getByteBuf(); 41 | int len = bbuf.readableBytes(); 42 | boolean compressed = !message.encoding().equals("identity"); 43 | ByteBuf prefix = Unpooled.buffer(5, 5); 44 | prefix.writeByte(compressed ? 1 : 0); // Compression flag 45 | prefix.writeInt(len); // Length 46 | CompositeByteBuf composite = Unpooled.compositeBuffer(); 47 | composite.addComponent(true, prefix); 48 | composite.addComponent(true, bbuf); 49 | return Buffer.buffer(composite); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/WriteStreamAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.vertx.grpc.common.GrpcWriteStream; 14 | import io.vertx.grpc.common.GrpcMessageEncoder; 15 | 16 | /** 17 | * An adapter between gRPC and Vert.x back-pressure. 18 | */ 19 | public class WriteStreamAdapter { 20 | 21 | private GrpcWriteStream stream; 22 | private boolean ready; 23 | private GrpcMessageEncoder encoder; 24 | 25 | /** 26 | * Override this method to call gRPC {@code onReady} 27 | */ 28 | protected void handleReady() { 29 | } 30 | 31 | public final void init(GrpcWriteStream stream, GrpcMessageEncoder encoder) { 32 | synchronized (this) { 33 | this.stream = stream; 34 | this.encoder = encoder; 35 | } 36 | stream.drainHandler(v -> { 37 | checkReady(); 38 | }); 39 | checkReady(); 40 | } 41 | 42 | public final synchronized boolean isReady() { 43 | return ready; 44 | } 45 | 46 | public final void write(T msg) { 47 | stream.writeMessage(encoder.encode(msg)); 48 | synchronized (this) { 49 | ready = !stream.writeQueueFull(); 50 | } 51 | } 52 | 53 | private void checkReady() { 54 | synchronized (this) { 55 | if (ready || stream.writeQueueFull()) { 56 | return; 57 | } 58 | ready = true; 59 | } 60 | handleReady(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/io/vertx/grpc/client/GrpcClientChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.client; 12 | 13 | import io.grpc.CallOptions; 14 | import io.grpc.ClientCall; 15 | import io.grpc.Compressor; 16 | import io.grpc.CompressorRegistry; 17 | import io.grpc.MethodDescriptor; 18 | import io.vertx.core.net.SocketAddress; 19 | 20 | import java.util.concurrent.Executor; 21 | 22 | /** 23 | * Bridge a gRPC service with a {@link io.vertx.grpc.client.GrpcClient}. 24 | */ 25 | public class GrpcClientChannel extends io.grpc.Channel { 26 | 27 | private GrpcClient client; 28 | private SocketAddress server; 29 | 30 | public GrpcClientChannel(GrpcClient client, SocketAddress server) { 31 | this.client = client; 32 | this.server = server; 33 | } 34 | 35 | @Override 36 | public ClientCall newCall(MethodDescriptor methodDescriptor, CallOptions callOptions) { 37 | 38 | String encoding = callOptions.getCompressor(); 39 | 40 | Compressor compressor; 41 | if (encoding != null) { 42 | compressor = CompressorRegistry.getDefaultInstance().lookupCompressor(encoding); 43 | } else { 44 | compressor = null; 45 | } 46 | 47 | 48 | Executor exec = callOptions.getExecutor(); 49 | 50 | return new VertxClientCall<>(client, server, exec, methodDescriptor, encoding, compressor); 51 | } 52 | 53 | @Override 54 | public String authority() { 55 | return null; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /.github/maven-ci-settings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | false 20 | 21 | 22 | 23 | google-mirror 24 | 25 | true 26 | 27 | 28 | 29 | google-maven-central 30 | GCS Maven Central mirror EU 31 | https://maven-central.storage-download.googleapis.com/maven2/ 32 | 33 | true 34 | 35 | 36 | false 37 | 38 | 39 | 40 | 41 | 42 | google-maven-central 43 | GCS Maven Central mirror 44 | https://maven-central.storage-download.googleapis.com/maven2/ 45 | 46 | true 47 | 48 | 49 | false 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/GrpcStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import io.netty.util.collection.IntObjectHashMap; 14 | import io.netty.util.collection.IntObjectMap; 15 | import io.vertx.codegen.annotations.VertxGen; 16 | 17 | /** 18 | * gRPC statuses. 19 | * 20 | * @author Julien Viet 21 | */ 22 | @VertxGen 23 | public enum GrpcStatus { 24 | 25 | OK(0), 26 | 27 | CANCELLED(1), 28 | 29 | UNKNOWN(2), 30 | 31 | INVALID_ARGUMENT(3), 32 | 33 | DEADLINE_EXCEEDED(4), 34 | 35 | NOT_FOUND(5), 36 | 37 | ALREADY_EXISTS(6), 38 | 39 | PERMISSION_DENIED(7), 40 | 41 | RESOURCE_EXHAUSTED(8), 42 | 43 | FAILED_PRECONDITION(9), 44 | 45 | ABORTED(10), 46 | 47 | OUT_OF_RANGE(11), 48 | 49 | UNIMPLEMENTED(12), 50 | 51 | INTERNAL(13), 52 | 53 | UNAVAILABLE(14), 54 | 55 | DATA_LOSS(15), 56 | 57 | UNAUTHENTICATED(16); 58 | 59 | private static final IntObjectMap codeMap = new IntObjectHashMap<>(); 60 | 61 | public static GrpcStatus valueOf(int code) { 62 | return codeMap.get(code); 63 | } 64 | 65 | static { 66 | for (GrpcStatus status : values()) { 67 | codeMap.put(status.code, status); 68 | } 69 | } 70 | 71 | public final int code; 72 | private final String string; 73 | 74 | GrpcStatus(int code) { 75 | this.code = code; 76 | this.string = Integer.toString(code); 77 | } 78 | 79 | 80 | @Override 81 | public String toString() { 82 | return string; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/io/vertx/grpc/server/GrpcServerResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.server; 12 | 13 | import io.vertx.codegen.annotations.Fluent; 14 | import io.vertx.codegen.annotations.Nullable; 15 | import io.vertx.codegen.annotations.VertxGen; 16 | import io.vertx.core.Future; 17 | import io.vertx.core.Handler; 18 | import io.vertx.core.MultiMap; 19 | import io.vertx.core.streams.ReadStream; 20 | import io.vertx.grpc.common.GrpcStatus; 21 | import io.vertx.grpc.common.GrpcWriteStream; 22 | 23 | @VertxGen 24 | public interface GrpcServerResponse extends GrpcWriteStream { 25 | 26 | /** 27 | * Set the grpc status response 28 | * 29 | * @param status the status 30 | * @return a reference to this, so the API can be used fluently 31 | */ 32 | @Fluent 33 | GrpcServerResponse status(GrpcStatus status); 34 | 35 | @Fluent 36 | GrpcServerResponse encoding(String encoding); 37 | 38 | /** 39 | * @return the {@link MultiMap} to write metadata trailers 40 | */ 41 | MultiMap trailers(); 42 | 43 | @Override 44 | GrpcServerResponse exceptionHandler(@Nullable Handler handler); 45 | 46 | @Override 47 | GrpcServerResponse setWriteQueueMaxSize(int maxSize); 48 | 49 | @Override 50 | GrpcServerResponse drainHandler(@Nullable Handler handler); 51 | 52 | default Future send(Resp item) { 53 | return end(item); 54 | } 55 | 56 | default Future send(ReadStream body) { 57 | return body.pipeTo(this); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/ServiceName.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import io.vertx.codegen.annotations.CacheReturn; 14 | import io.vertx.codegen.annotations.VertxGen; 15 | import io.vertx.grpc.common.impl.ServiceNameImpl; 16 | 17 | /** 18 | * A gRPC service name. 19 | */ 20 | @VertxGen 21 | public interface ServiceName { 22 | 23 | /** 24 | * Create a service name from its fully qualified name, e.g {@code com.examples.MyService} 25 | * 26 | * @param fqn the fully qualified service name 27 | * @return the service name 28 | */ 29 | static ServiceName create(String fqn) { 30 | return new ServiceNameImpl(fqn); 31 | } 32 | 33 | /** 34 | * Create a service name from its package name and name 35 | * 36 | * @param packageName the package name 37 | * @param name the name 38 | * @return the service name 39 | */ 40 | static ServiceName create(String packageName, String name) { 41 | return new ServiceNameImpl(packageName, name); 42 | } 43 | 44 | /** 45 | * @return the name 46 | */ 47 | @CacheReturn 48 | String name(); 49 | 50 | /** 51 | * @return the package name 52 | */ 53 | @CacheReturn 54 | String packageName(); 55 | 56 | /** 57 | * @return the fully qualified name 58 | */ 59 | @CacheReturn 60 | String fullyQualifiedName(); 61 | 62 | /** 63 | * Create the path of a given {@code method} to call. 64 | * @param method the method 65 | * @return the path, e.g {@code /com.examples.MyService/MyMethod} 66 | */ 67 | String pathOf(String method); 68 | 69 | } 70 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/test/java/io/vertx/grpc/common/UtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2023 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import io.grpc.Metadata; 14 | import io.vertx.core.MultiMap; 15 | import io.vertx.grpc.common.impl.Utils; 16 | import org.junit.Test; 17 | 18 | import java.util.Arrays; 19 | import java.util.List; 20 | import java.util.Set; 21 | import java.util.stream.Collectors; 22 | import java.util.stream.StreamSupport; 23 | 24 | import static org.junit.Assert.assertEquals; 25 | import static org.junit.Assert.assertTrue; 26 | 27 | public class UtilsTest { 28 | 29 | /** 30 | * Reproduce #35 31 | */ 32 | @Test 33 | public void testReadMetadata() { 34 | MultiMap headers = MultiMap.caseInsensitiveMultiMap(); 35 | 36 | headers.add("key0", "value0"); 37 | headers.add("key1", "value1"); 38 | headers.add("key0", "value2"); 39 | 40 | Metadata metadata = Utils.readMetadata(headers); 41 | assertEquals(metadata.keys().size(), 2); 42 | 43 | List l = StreamSupport.stream(metadata.getAll(Metadata.Key.of("key0", Metadata.ASCII_STRING_MARSHALLER)).spliterator(), false) 44 | .collect(Collectors.toList()); 45 | assertEquals(l.size(), 2); 46 | assertTrue(l.contains("value0")); 47 | assertTrue(l.contains("value2")); 48 | 49 | l = StreamSupport.stream(metadata.getAll(Metadata.Key.of("key1", Metadata.ASCII_STRING_MARSHALLER)).spliterator(), false) 50 | .collect(Collectors.toList()); 51 | assertEquals(l.size(), 1); 52 | assertTrue(l.contains("value1")); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/ServiceNameImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.vertx.grpc.common.ServiceName; 14 | 15 | public class ServiceNameImpl implements ServiceName { 16 | 17 | private String name; 18 | private String packageName; 19 | private String fullyQualifiedName; 20 | 21 | public ServiceNameImpl(String packageName, String name) { 22 | this.name = name; 23 | this.packageName = packageName; 24 | } 25 | 26 | public ServiceNameImpl(String fullyQualifiedName) { 27 | this.fullyQualifiedName = fullyQualifiedName; 28 | } 29 | 30 | @Override 31 | public String name() { 32 | if (name == null) { 33 | int idx = fullyQualifiedName.lastIndexOf('.'); 34 | name = fullyQualifiedName.substring(idx + 1); 35 | } 36 | return name; 37 | } 38 | 39 | @Override 40 | public String packageName() { 41 | if (packageName == null) { 42 | int idx = fullyQualifiedName.lastIndexOf('.'); 43 | packageName = fullyQualifiedName.substring(0, idx); 44 | } 45 | return packageName; 46 | } 47 | 48 | @Override 49 | public String fullyQualifiedName() { 50 | if (fullyQualifiedName == null) { 51 | fullyQualifiedName = packageName + '.' + name; 52 | } 53 | return fullyQualifiedName; 54 | } 55 | 56 | @Override 57 | public String pathOf(String method) { 58 | if (fullyQualifiedName != null) { 59 | return '/' + fullyQualifiedName + '/' + method; 60 | } else { 61 | return '/' + packageName + '.' + name + '/' + method; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.github/maven-cd-settings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | false 20 | 21 | 22 | 23 | vertx-snapshots-repository 24 | ${env.VERTX_NEXUS_USERNAME} 25 | ${env.VERTX_NEXUS_PASSWORD} 26 | 27 | 28 | 29 | 30 | 31 | google-mirror 32 | 33 | true 34 | 35 | 36 | 37 | google-maven-central 38 | GCS Maven Central mirror EU 39 | https://maven-central.storage-download.googleapis.com/maven2/ 40 | 41 | true 42 | 43 | 44 | false 45 | 46 | 47 | 48 | 49 | 50 | google-maven-central 51 | GCS Maven Central mirror 52 | https://maven-central.storage-download.googleapis.com/maven2/ 53 | 54 | true 55 | 56 | 57 | false 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/test/proto/empty.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto2"; 31 | 32 | package grpc.testing; 33 | 34 | option java_package = "com.google.protobuf"; 35 | option java_outer_classname = "EmptyProtos"; 36 | 37 | // An empty message that you can re-use to avoid defining duplicated empty 38 | // messages in your project. A typical example is to use it as argument or the 39 | // return value of a service API. For instance: 40 | // 41 | // service Foo { 42 | // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; 43 | // }; 44 | // 45 | message Empty {} 46 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/proto/empty.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto2"; 31 | 32 | package grpc.testing; 33 | 34 | option java_package = "com.google.protobuf"; 35 | option java_outer_classname = "EmptyProtos"; 36 | 37 | // An empty message that you can re-use to avoid defining duplicated empty 38 | // messages in your project. A typical example is to use it as argument or the 39 | // return value of a service API. For instance: 40 | // 41 | // service Foo { 42 | // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; 43 | // }; 44 | // 45 | message Empty {} 46 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/test/proto/empty.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto2"; 31 | 32 | package grpc.testing; 33 | 34 | option java_package = "com.google.protobuf"; 35 | option java_outer_classname = "EmptyProtos"; 36 | 37 | // An empty message that you can re-use to avoid defining duplicated empty 38 | // messages in your project. A typical example is to use it as argument or the 39 | // return value of a service API. For instance: 40 | // 41 | // service Foo { 42 | // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; 43 | // }; 44 | // 45 | message Empty {} 46 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | io.vertx 6 | vertx-ext-parent 7 | 38 8 | 9 | 10 | 4.0.0 11 | pom 12 | 13 | vertx-grpc-aggregator 14 | 5.0.0-SNAPSHOT 15 | 16 | 17 | 5.0.0-SNAPSHOT 18 | 1.50.2 19 | 3.21.12 20 | true 21 | 22 | 23 | 24 | 25 | 26 | io.vertx 27 | vertx-dependencies 28 | ${stack.version} 29 | pom 30 | import 31 | 32 | 33 | 34 | 35 | 36 | 37 | io.vertx 38 | vertx-codegen 39 | provided 40 | true 41 | 42 | 43 | io.vertx 44 | vertx-docgen 45 | provided 46 | 47 | 48 | 49 | junit 50 | junit 51 | 4.13.1 52 | test 53 | 54 | 55 | io.vertx 56 | vertx-core 57 | test-jar 58 | test 59 | 60 | 61 | 62 | 63 | vertx-grpc-common 64 | vertx-grpc-server 65 | vertx-grpc-client 66 | vertx-grpc-context-storage 67 | vertx-grpc-it 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/test/java/io/vertx/grpc/client/ClientTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.client; 12 | 13 | import io.grpc.BindableService; 14 | import io.grpc.Server; 15 | import io.grpc.ServerBuilder; 16 | import io.grpc.ServerServiceDefinition; 17 | import io.vertx.core.Vertx; 18 | import io.vertx.ext.unit.TestContext; 19 | import io.vertx.ext.unit.junit.VertxUnitRunner; 20 | import io.vertx.grpc.common.GrpcTestBase; 21 | import org.junit.After; 22 | import org.junit.runner.RunWith; 23 | 24 | import java.io.IOException; 25 | 26 | /** 27 | * @author Julien Viet 28 | */ 29 | @RunWith(VertxUnitRunner.class) 30 | public abstract class ClientTestBase extends GrpcTestBase { 31 | 32 | /* The port on which the server should run */ 33 | protected Server server; 34 | 35 | @After 36 | public void tearDown(TestContext should) { 37 | stopServer(false); 38 | super.tearDown(should); 39 | } 40 | 41 | void startServer(BindableService service) throws IOException { 42 | startServer(service, ServerBuilder.forPort(port)); 43 | } 44 | 45 | void stopServer(boolean now) { 46 | Server s = server; 47 | if (s != null) { 48 | server = null; 49 | s.shutdownNow(); 50 | } 51 | } 52 | 53 | void startServer(BindableService service, ServerBuilder builder) throws IOException { 54 | server = builder 55 | .addService(service) 56 | .build() 57 | .start(); 58 | } 59 | 60 | 61 | void startServer(ServerServiceDefinition service) throws IOException { 62 | startServer(service, ServerBuilder.forPort(port)); 63 | } 64 | 65 | void startServer(ServerServiceDefinition service, ServerBuilder builder) throws IOException { 66 | server = builder 67 | .addService(service) 68 | .build() 69 | .start(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "examples"; 34 | option java_outer_classname = "HelloWorldProto"; 35 | option objc_class_prefix = "HLW"; 36 | 37 | package helloworld; 38 | 39 | // The greeting service definition. 40 | service Greeter { 41 | // Sends a greeting 42 | rpc SayHello (HelloRequest) returns (HelloReply) {} 43 | } 44 | 45 | // The request message containing the user's name. 46 | message HelloRequest { 47 | string name = 1; 48 | } 49 | 50 | // The response message containing the greetings 51 | message HelloReply { 52 | string message = 1; 53 | } 54 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "examples"; 34 | option java_outer_classname = "HelloWorldProto"; 35 | option objc_class_prefix = "HLW"; 36 | 37 | package helloworld; 38 | 39 | // The greeting service definition. 40 | service Greeter { 41 | // Sends a greeting 42 | rpc SayHello (HelloRequest) returns (HelloReply) {} 43 | } 44 | 45 | // The request message containing the user's name. 46 | message HelloRequest { 47 | string name = 1; 48 | } 49 | 50 | // The response message containing the greetings 51 | message HelloReply { 52 | string message = 1; 53 | } 54 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/test/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "io.grpc.examples.helloworld"; 34 | option java_outer_classname = "HelloWorldProto"; 35 | option objc_class_prefix = "HLW"; 36 | 37 | package helloworld; 38 | 39 | // The greeting service definition. 40 | service Greeter { 41 | // Sends a greeting 42 | rpc SayHello (HelloRequest) returns (HelloReply) {} 43 | } 44 | 45 | // The request message containing the user's name. 46 | message HelloRequest { 47 | string name = 1; 48 | } 49 | 50 | // The response message containing the greetings 51 | message HelloReply { 52 | string message = 1; 53 | } 54 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "io.grpc.examples.helloworld"; 34 | option java_outer_classname = "HelloWorldProto"; 35 | option objc_class_prefix = "HLW"; 36 | 37 | package helloworld; 38 | 39 | // The greeting service definition. 40 | service Greeter { 41 | // Sends a greeting 42 | rpc SayHello (HelloRequest) returns (HelloReply) {} 43 | } 44 | 45 | // The request message containing the user's name. 46 | message HelloRequest { 47 | string name = 1; 48 | } 49 | 50 | // The response message containing the greetings 51 | message HelloReply { 52 | string message = 1; 53 | } 54 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/test/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "io.grpc.examples.helloworld"; 34 | option java_outer_classname = "HelloWorldProto"; 35 | option objc_class_prefix = "HLW"; 36 | 37 | package helloworld; 38 | 39 | // The greeting service definition. 40 | service Greeter { 41 | // Sends a greeting 42 | rpc SayHello (HelloRequest) returns (HelloReply) {} 43 | } 44 | 45 | // The request message containing the user's name. 46 | message HelloRequest { 47 | string name = 1; 48 | } 49 | 50 | // The response message containing the greetings 51 | message HelloReply { 52 | string message = 1; 53 | } 54 | -------------------------------------------------------------------------------- /vertx-grpc-context-storage/src/test/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "io.grpc.examples.helloworld"; 34 | option java_outer_classname = "HelloWorldProto"; 35 | option objc_class_prefix = "HLW"; 36 | 37 | package helloworld; 38 | 39 | // The greeting service definition. 40 | service Greeter { 41 | // Sends a greeting 42 | rpc SayHello (HelloRequest) returns (HelloReply) {} 43 | } 44 | 45 | // The request message containing the user's name. 46 | message HelloRequest { 47 | string name = 1; 48 | } 49 | 50 | // The response message containing the greetings 51 | message HelloReply { 52 | string message = 1; 53 | } 54 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/GrpcReadStream.java: -------------------------------------------------------------------------------- 1 | package io.vertx.grpc.common; 2 | 3 | import io.vertx.codegen.annotations.Fluent; 4 | import io.vertx.codegen.annotations.GenIgnore; 5 | import io.vertx.codegen.annotations.Nullable; 6 | import io.vertx.codegen.annotations.VertxGen; 7 | import io.vertx.core.Future; 8 | import io.vertx.core.Handler; 9 | import io.vertx.core.MultiMap; 10 | import io.vertx.core.streams.ReadStream; 11 | 12 | @VertxGen 13 | public interface GrpcReadStream extends ReadStream { 14 | 15 | /** 16 | * @return the {@link MultiMap} to read metadata headers 17 | */ 18 | MultiMap headers(); 19 | 20 | /** 21 | * @return the stream encoding, e.g {@code identity} or {@code gzip} 22 | */ 23 | String encoding(); 24 | 25 | /** 26 | * Set a handler to be notified with incoming encoded messages. The {@code handler} is 27 | * responsible for fully decoding incoming messages, including compression. 28 | * 29 | * @param handler the message handler 30 | * @return a reference to this, so the API can be used fluently 31 | */ 32 | @Fluent 33 | GrpcReadStream messageHandler(@Nullable Handler handler); 34 | 35 | /** 36 | * Set a handler to be notified with gRPC errors. 37 | * 38 | * @param handler the error handler 39 | * @return a reference to this, so the API can be used fluently 40 | */ 41 | @Fluent 42 | GrpcReadStream errorHandler(@Nullable Handler handler); 43 | 44 | @Override 45 | GrpcReadStream exceptionHandler(@Nullable Handler handler); 46 | 47 | @Override 48 | GrpcReadStream handler(@Nullable Handler handler); 49 | 50 | @Override 51 | GrpcReadStream pause(); 52 | 53 | @Override 54 | GrpcReadStream resume(); 55 | 56 | @Override 57 | GrpcReadStream fetch(long l); 58 | 59 | @Override 60 | GrpcReadStream endHandler(@Nullable Handler handler); 61 | 62 | /** 63 | * @return the last element of the stream 64 | */ 65 | Future last(); 66 | 67 | /** 68 | * @return a future signaling when the response has been fully received successfully or failed 69 | */ 70 | Future end(); 71 | 72 | /** 73 | * @return the result of applying a collector on the stream 74 | */ 75 | @GenIgnore(GenIgnore.PERMITTED_TYPE) 76 | Future collecting(java.util.stream.Collector collector); 77 | 78 | } 79 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/io/vertx/grpc/client/GrpcClientResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.client; 12 | 13 | import io.vertx.codegen.annotations.CacheReturn; 14 | import io.vertx.codegen.annotations.Fluent; 15 | import io.vertx.codegen.annotations.Nullable; 16 | import io.vertx.codegen.annotations.VertxGen; 17 | import io.vertx.core.Handler; 18 | import io.vertx.core.MultiMap; 19 | import io.vertx.grpc.common.GrpcError; 20 | import io.vertx.grpc.common.GrpcMessage; 21 | import io.vertx.grpc.common.GrpcReadStream; 22 | import io.vertx.grpc.common.GrpcStatus; 23 | 24 | /** 25 | * A response from a gRPC server. 26 | * 27 | * You can set a {@link #messageHandler(Handler)} to receive {@link GrpcMessage} and a {@link #endHandler(Handler)} to be notified 28 | * of the end of the response. 29 | * 30 | */ 31 | @VertxGen 32 | public interface GrpcClientResponse extends GrpcReadStream { 33 | 34 | /** 35 | * @return the gRPC status or {@code null} when the status has not yet been received 36 | */ 37 | @CacheReturn 38 | GrpcStatus status(); 39 | 40 | /** 41 | * @return the {@link MultiMap} to write metadata trailers 42 | */ 43 | MultiMap trailers(); 44 | 45 | @Override 46 | @Fluent 47 | GrpcClientResponse messageHandler(@Nullable Handler handler); 48 | 49 | @Override 50 | @Fluent 51 | GrpcClientResponse errorHandler(@Nullable Handler handler); 52 | 53 | @Override 54 | GrpcClientResponse exceptionHandler(@Nullable Handler handler); 55 | 56 | @Override 57 | GrpcClientResponse handler(@Nullable Handler handler); 58 | 59 | @Override 60 | GrpcClientResponse endHandler(@Nullable Handler handler); 61 | 62 | @Override 63 | GrpcClientResponse pause(); 64 | 65 | @Override 66 | GrpcClientResponse resume(); 67 | 68 | @Override 69 | GrpcClientResponse fetch(long amount); 70 | } 71 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/test/java/io/vertx/grpc/common/GrpcTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import io.vertx.core.Vertx; 14 | import io.vertx.core.buffer.Buffer; 15 | import io.vertx.ext.unit.TestContext; 16 | import io.vertx.ext.unit.junit.VertxUnitRunner; 17 | import org.junit.After; 18 | import org.junit.Before; 19 | import org.junit.runner.RunWith; 20 | 21 | import java.io.ByteArrayInputStream; 22 | import java.io.ByteArrayOutputStream; 23 | import java.io.IOException; 24 | import java.util.zip.GZIPInputStream; 25 | import java.util.zip.GZIPOutputStream; 26 | 27 | /** 28 | * @author Julien Viet 29 | */ 30 | @RunWith(VertxUnitRunner.class) 31 | public abstract class GrpcTestBase { 32 | 33 | /* The port on which the server should run */ 34 | protected Vertx vertx; 35 | protected int port; 36 | 37 | @Before 38 | public void setUp() { 39 | port = 8080; 40 | vertx = Vertx.vertx(); 41 | } 42 | 43 | @After 44 | public void tearDown(TestContext should) { 45 | vertx.close().onComplete(should.asyncAssertSuccess()); 46 | } 47 | 48 | public static Buffer unzip(Buffer buffer) { 49 | Buffer ret = Buffer.buffer(); 50 | try { 51 | GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(buffer.getBytes())); 52 | byte[] tmp = new byte[256]; 53 | for (int l = 0;l != -1;l = in.read(tmp)) { 54 | ret.appendBytes(tmp, 0, l); 55 | } 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | return ret; 60 | } 61 | 62 | public static Buffer zip(Buffer buffer) { 63 | ByteArrayOutputStream ret = new ByteArrayOutputStream(); 64 | try { 65 | GZIPOutputStream in = new GZIPOutputStream(ret); 66 | in.write(buffer.getBytes()); 67 | in.flush(); 68 | in.close(); 69 | } catch (IOException e) { 70 | e.printStackTrace(); 71 | } 72 | return Buffer.buffer(ret.toByteArray()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/impl/BridgeMessageEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common.impl; 12 | 13 | import io.grpc.Compressor; 14 | import io.grpc.Drainable; 15 | import io.grpc.MethodDescriptor; 16 | import io.vertx.core.buffer.Buffer; 17 | import io.vertx.grpc.common.GrpcMessage; 18 | import io.vertx.grpc.common.GrpcMessageEncoder; 19 | 20 | import java.io.ByteArrayOutputStream; 21 | import java.io.IOException; 22 | import java.io.OutputStream; 23 | 24 | public class BridgeMessageEncoder implements GrpcMessageEncoder { 25 | 26 | private MethodDescriptor.Marshaller marshaller; 27 | private Compressor compressor; 28 | 29 | public BridgeMessageEncoder(MethodDescriptor.Marshaller marshaller, Compressor compressor) { 30 | this.marshaller = marshaller; 31 | this.compressor = compressor; 32 | } 33 | 34 | @Override 35 | public GrpcMessage encode(T msg) { 36 | return new GrpcMessage() { 37 | private Buffer encoded; 38 | @Override 39 | public String encoding() { 40 | return compressor == null ? "identity" : compressor.getMessageEncoding(); 41 | } 42 | @Override 43 | public Buffer payload() { 44 | if (encoded == null) { 45 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Improve that ??? 46 | Drainable stream = (Drainable) marshaller.stream(msg); 47 | try { 48 | OutputStream compressingStream; 49 | if (compressor == null) { 50 | compressingStream = baos; 51 | } else { 52 | compressingStream = compressor.compress(baos); 53 | } 54 | stream.drainTo(compressingStream); 55 | compressingStream.close(); 56 | } catch (IOException e) { 57 | throw new RuntimeException(e); 58 | } 59 | byte[] bytes = baos.toByteArray(); 60 | encoded = Buffer.buffer(bytes); 61 | } 62 | return encoded; 63 | } 64 | }; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/GrpcError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import io.vertx.codegen.annotations.VertxGen; 14 | 15 | /** 16 | * gRPC error, a subset of {@link GrpcStatus} elements. 17 | */ 18 | @VertxGen 19 | public enum GrpcError { 20 | 21 | INTERNAL(GrpcStatus.INTERNAL, 0x02), 22 | 23 | UNAVAILABLE(GrpcStatus.UNAVAILABLE, 0x07), 24 | 25 | CANCELLED(GrpcStatus.CANCELLED, 0x08), 26 | 27 | RESOURCE_EXHAUSTED(GrpcStatus.RESOURCE_EXHAUSTED, 0x0B), 28 | 29 | PERMISSION_DENIED(GrpcStatus.PERMISSION_DENIED, 0x0C); 30 | 31 | public final GrpcStatus status; 32 | public final long http2ResetCode; 33 | 34 | GrpcError(GrpcStatus status, long http2ResetCode) { 35 | this.status = status; 36 | this.http2ResetCode = http2ResetCode; 37 | } 38 | 39 | /** 40 | * Map the HTTP/2 code to the gRPC error. 41 | * @param code the HTTP/2 code 42 | * @return the gRPC error or {@code null} when none applies 43 | */ 44 | public static GrpcError mapHttp2ErrorCode(long code) { 45 | switch ((int)code) { 46 | case 0x00: 47 | // NO_ERROR 48 | case 0x01: 49 | // PROTOCOL_ERROR 50 | case 0x02: 51 | // INTERNAL_ERROR 52 | case 0x03: 53 | // FLOW_CONTROL_ERROR 54 | case 0x04: 55 | // FRAME_SIZE_ERROR 56 | case 0x06: 57 | // FRAME_SIZE_ERROR 58 | case 0x09: 59 | // COMPRESSION_ERROR 60 | return GrpcError.INTERNAL; 61 | case 0x07: 62 | // REFUSED_STREAM 63 | return GrpcError.UNAVAILABLE; 64 | case 0x0A: 65 | // CONNECT_ERROR 66 | case 0x08: 67 | // CANCEL 68 | return GrpcError.CANCELLED; 69 | case 0x0B: 70 | // ENHANCE_YOUR_CALM 71 | return GrpcError.RESOURCE_EXHAUSTED; 72 | case 0x0C: 73 | // INADEQUATE_SECURITY 74 | return GrpcError.PERMISSION_DENIED; 75 | default: 76 | // STREAM_CLOSED; 77 | // HTTP_1_1_REQUIRED 78 | return null; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/io/vertx/grpc/server/GrpcServerRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.server; 12 | 13 | import io.vertx.codegen.annotations.CacheReturn; 14 | import io.vertx.codegen.annotations.Fluent; 15 | import io.vertx.codegen.annotations.Nullable; 16 | import io.vertx.codegen.annotations.VertxGen; 17 | import io.vertx.core.Handler; 18 | import io.vertx.core.http.HttpConnection; 19 | import io.vertx.grpc.common.GrpcError; 20 | import io.vertx.grpc.common.GrpcMessage; 21 | import io.vertx.grpc.common.GrpcReadStream; 22 | import io.vertx.grpc.common.ServiceName; 23 | 24 | @VertxGen 25 | public interface GrpcServerRequest extends GrpcReadStream { 26 | 27 | /** 28 | * @return the service name 29 | */ 30 | @CacheReturn 31 | ServiceName serviceName(); 32 | 33 | /** 34 | * @return the method name 35 | */ 36 | @CacheReturn 37 | String methodName(); 38 | 39 | /** 40 | * @return the full method name sent by the client 41 | */ 42 | @CacheReturn 43 | String fullMethodName(); 44 | 45 | /** 46 | * @return the response 47 | */ 48 | @CacheReturn 49 | GrpcServerResponse response(); 50 | 51 | @Override 52 | @Fluent 53 | GrpcServerRequest messageHandler(@Nullable Handler handler); 54 | 55 | @Override 56 | @Fluent 57 | GrpcServerRequest errorHandler(@Nullable Handler handler); 58 | 59 | @Override 60 | GrpcServerRequest exceptionHandler(@Nullable Handler handler); 61 | 62 | @Override 63 | GrpcServerRequest handler(@Nullable Handler handler); 64 | 65 | @Override 66 | GrpcServerRequest pause(); 67 | 68 | @Override 69 | GrpcServerRequest resume(); 70 | 71 | @Override 72 | GrpcServerRequest fetch(long amount); 73 | 74 | @Override 75 | GrpcServerRequest endHandler(@Nullable Handler endHandler); 76 | 77 | /** 78 | * @return the underlying HTTP connection 79 | */ 80 | HttpConnection connection(); 81 | } 82 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/test/java/io/vertx/grpc/server/ServerTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.server; 12 | 13 | import io.grpc.ManagedChannel; 14 | import io.vertx.core.Vertx; 15 | import io.vertx.core.http.HttpServerOptions; 16 | import io.vertx.ext.unit.TestContext; 17 | import io.vertx.ext.unit.junit.VertxUnitRunner; 18 | import io.vertx.grpc.common.GrpcTestBase; 19 | import junit.framework.AssertionFailedError; 20 | import org.junit.After; 21 | import org.junit.Before; 22 | import org.junit.runner.RunWith; 23 | 24 | import java.util.concurrent.CompletableFuture; 25 | import java.util.concurrent.ExecutionException; 26 | import java.util.concurrent.TimeUnit; 27 | import java.util.concurrent.TimeoutException; 28 | 29 | /** 30 | * @author Julien Viet 31 | */ 32 | @RunWith(VertxUnitRunner.class) 33 | public abstract class ServerTestBase extends GrpcTestBase { 34 | 35 | protected volatile ManagedChannel channel; 36 | 37 | @Override 38 | public void tearDown(TestContext should) { 39 | if (channel != null) { 40 | channel.shutdown(); 41 | } 42 | super.tearDown(should); 43 | } 44 | 45 | protected void startServer(GrpcServer server) { 46 | startServer(new HttpServerOptions().setPort(8080).setHost("localhost"), server); 47 | } 48 | 49 | protected void startServer(HttpServerOptions options, GrpcServer server) { 50 | CompletableFuture res = new CompletableFuture<>(); 51 | vertx.createHttpServer(options).requestHandler(server).listen() 52 | .onComplete(ar -> { 53 | if (ar.succeeded()) { 54 | res.complete(null); 55 | } else { 56 | res.completeExceptionally(ar.cause()); 57 | } 58 | }); 59 | try { 60 | res.get(20, TimeUnit.SECONDS); 61 | } catch (InterruptedException e) { 62 | Thread.currentThread().interrupt(); 63 | AssertionFailedError afe = new AssertionFailedError(); 64 | afe.initCause(e); 65 | throw afe; 66 | } catch (ExecutionException e) { 67 | AssertionFailedError afe = new AssertionFailedError(); 68 | afe.initCause(e.getCause()); 69 | throw afe; 70 | } catch (TimeoutException e) { 71 | AssertionFailedError afe = new AssertionFailedError(); 72 | afe.initCause(e); 73 | throw afe; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/examples/HelloWorldProto.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: helloworld.proto 3 | 4 | package examples; 5 | 6 | public final class HelloWorldProto { 7 | private HelloWorldProto() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistryLite registry) { 10 | } 11 | 12 | public static void registerAllExtensions( 13 | com.google.protobuf.ExtensionRegistry registry) { 14 | registerAllExtensions( 15 | (com.google.protobuf.ExtensionRegistryLite) registry); 16 | } 17 | static final com.google.protobuf.Descriptors.Descriptor 18 | internal_static_helloworld_HelloRequest_descriptor; 19 | static final 20 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 21 | internal_static_helloworld_HelloRequest_fieldAccessorTable; 22 | static final com.google.protobuf.Descriptors.Descriptor 23 | internal_static_helloworld_HelloReply_descriptor; 24 | static final 25 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 26 | internal_static_helloworld_HelloReply_fieldAccessorTable; 27 | 28 | public static com.google.protobuf.Descriptors.FileDescriptor 29 | getDescriptor() { 30 | return descriptor; 31 | } 32 | private static com.google.protobuf.Descriptors.FileDescriptor 33 | descriptor; 34 | static { 35 | java.lang.String[] descriptorData = { 36 | "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" + 37 | "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" + 38 | "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" + 39 | "loworld.HelloRequest\032\026.helloworld.HelloR" + 40 | "eply\"\000B#\n\010examplesB\017HelloWorldProtoP\001\242\002\003" + 41 | "HLWb\006proto3" 42 | }; 43 | descriptor = com.google.protobuf.Descriptors.FileDescriptor 44 | .internalBuildGeneratedFileFrom(descriptorData, 45 | new com.google.protobuf.Descriptors.FileDescriptor[] { 46 | }); 47 | internal_static_helloworld_HelloRequest_descriptor = 48 | getDescriptor().getMessageTypes().get(0); 49 | internal_static_helloworld_HelloRequest_fieldAccessorTable = new 50 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 51 | internal_static_helloworld_HelloRequest_descriptor, 52 | new java.lang.String[] { "Name", }); 53 | internal_static_helloworld_HelloReply_descriptor = 54 | getDescriptor().getMessageTypes().get(1); 55 | internal_static_helloworld_HelloReply_fieldAccessorTable = new 56 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 57 | internal_static_helloworld_HelloReply_descriptor, 58 | new java.lang.String[] { "Message", }); 59 | } 60 | 61 | // @@protoc_insertion_point(outer_class_scope) 62 | } 63 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/examples/HelloWorldProto.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: helloworld.proto 3 | 4 | package examples; 5 | 6 | public final class HelloWorldProto { 7 | private HelloWorldProto() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistryLite registry) { 10 | } 11 | 12 | public static void registerAllExtensions( 13 | com.google.protobuf.ExtensionRegistry registry) { 14 | registerAllExtensions( 15 | (com.google.protobuf.ExtensionRegistryLite) registry); 16 | } 17 | static final com.google.protobuf.Descriptors.Descriptor 18 | internal_static_helloworld_HelloRequest_descriptor; 19 | static final 20 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 21 | internal_static_helloworld_HelloRequest_fieldAccessorTable; 22 | static final com.google.protobuf.Descriptors.Descriptor 23 | internal_static_helloworld_HelloReply_descriptor; 24 | static final 25 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 26 | internal_static_helloworld_HelloReply_fieldAccessorTable; 27 | 28 | public static com.google.protobuf.Descriptors.FileDescriptor 29 | getDescriptor() { 30 | return descriptor; 31 | } 32 | private static com.google.protobuf.Descriptors.FileDescriptor 33 | descriptor; 34 | static { 35 | java.lang.String[] descriptorData = { 36 | "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" + 37 | "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" + 38 | "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" + 39 | "loworld.HelloRequest\032\026.helloworld.HelloR" + 40 | "eply\"\000B#\n\010examplesB\017HelloWorldProtoP\001\242\002\003" + 41 | "HLWb\006proto3" 42 | }; 43 | descriptor = com.google.protobuf.Descriptors.FileDescriptor 44 | .internalBuildGeneratedFileFrom(descriptorData, 45 | new com.google.protobuf.Descriptors.FileDescriptor[] { 46 | }); 47 | internal_static_helloworld_HelloRequest_descriptor = 48 | getDescriptor().getMessageTypes().get(0); 49 | internal_static_helloworld_HelloRequest_fieldAccessorTable = new 50 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 51 | internal_static_helloworld_HelloRequest_descriptor, 52 | new java.lang.String[] { "Name", }); 53 | internal_static_helloworld_HelloReply_descriptor = 54 | getDescriptor().getMessageTypes().get(1); 55 | internal_static_helloworld_HelloReply_fieldAccessorTable = new 56 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 57 | internal_static_helloworld_HelloReply_descriptor, 58 | new java.lang.String[] { "Message", }); 59 | } 60 | 61 | // @@protoc_insertion_point(outer_class_scope) 62 | } 63 | -------------------------------------------------------------------------------- /vertx-grpc-context-storage/src/main/java/io/grpc/override/ContextStorageOverride.java: -------------------------------------------------------------------------------- 1 | package io.grpc.override; 2 | 3 | import io.grpc.Context; 4 | import io.vertx.core.Vertx; 5 | import io.vertx.core.impl.ContextInternal; 6 | import io.vertx.core.impl.logging.Logger; 7 | import io.vertx.core.impl.logging.LoggerFactory; 8 | 9 | import java.util.concurrent.ConcurrentMap; 10 | 11 | /** 12 | * A {@link io.grpc.Context.Storage} implementation that uses Vert.x local context data maps when running on a duplicated context. 13 | * Otherwise, it falls back to thread-local storage. 14 | */ 15 | public class ContextStorageOverride extends Context.Storage { 16 | 17 | private static final Logger LOG = LoggerFactory.getLogger(ContextStorageOverride.class); 18 | 19 | private static final Object CONTEXT_KEY = new Object(); 20 | private static final ThreadLocal fallback = new ThreadLocal<>(); 21 | 22 | public ContextStorageOverride() { 23 | // Do not remove, empty constructor required by gRPC 24 | } 25 | 26 | @Override 27 | public Context doAttach(Context toAttach) { 28 | ContextInternal vertxContext = vertxContext(); 29 | Context toRestoreLater; 30 | if (vertxContext != null) { 31 | toRestoreLater = (Context) vertxContext.localContextData().put(CONTEXT_KEY, toAttach); 32 | } else { 33 | toRestoreLater = fallback.get(); 34 | fallback.set(toAttach); 35 | } 36 | return rootIfNull(toRestoreLater); 37 | } 38 | 39 | @Override 40 | public void detach(Context toDetach, Context toRestore) { 41 | ContextInternal vertxContext = vertxContext(); 42 | Context current; 43 | if (vertxContext != null) { 44 | ConcurrentMap dataMap = vertxContext.localContextData(); 45 | if (toRestore == Context.ROOT) { 46 | current = (Context) dataMap.remove(CONTEXT_KEY); 47 | } else { 48 | current = (Context) dataMap.put(CONTEXT_KEY, toRestore); 49 | } 50 | } else { 51 | current = fallback.get(); 52 | fallback.remove(); 53 | fallback.set(toRestore == Context.ROOT ? null : toRestore); 54 | } 55 | if (rootIfNull(current) != toDetach) { 56 | if (LOG.isWarnEnabled()) { 57 | LOG.warn("Context was not attached when detaching", new Exception("Stack trace")); 58 | } 59 | } 60 | } 61 | 62 | @Override 63 | public Context current() { 64 | ContextInternal vertxContext = vertxContext(); 65 | return rootIfNull(vertxContext != null ? vertxContext.getLocal(CONTEXT_KEY) : fallback.get()); 66 | } 67 | 68 | private static ContextInternal vertxContext() { 69 | ContextInternal ctx = (ContextInternal) Vertx.currentContext(); 70 | return ctx != null && ctx.isDuplicate() ? ctx : null; 71 | } 72 | 73 | private static Context rootIfNull(Context context) { 74 | return context == null ? Context.ROOT : context; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/examples/StreamingProto.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: streaming.proto 3 | 4 | package examples; 5 | 6 | public final class StreamingProto { 7 | private StreamingProto() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistryLite registry) { 10 | } 11 | 12 | public static void registerAllExtensions( 13 | com.google.protobuf.ExtensionRegistry registry) { 14 | registerAllExtensions( 15 | (com.google.protobuf.ExtensionRegistryLite) registry); 16 | } 17 | static final com.google.protobuf.Descriptors.Descriptor 18 | internal_static_streaming_Item_descriptor; 19 | static final 20 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 21 | internal_static_streaming_Item_fieldAccessorTable; 22 | static final com.google.protobuf.Descriptors.Descriptor 23 | internal_static_streaming_Empty_descriptor; 24 | static final 25 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 26 | internal_static_streaming_Empty_fieldAccessorTable; 27 | 28 | public static com.google.protobuf.Descriptors.FileDescriptor 29 | getDescriptor() { 30 | return descriptor; 31 | } 32 | private static com.google.protobuf.Descriptors.FileDescriptor 33 | descriptor; 34 | static { 35 | java.lang.String[] descriptorData = { 36 | "\n\017streaming.proto\022\tstreaming\"\025\n\004Item\022\r\n\005" + 37 | "value\030\001 \001(\t\"\007\n\005Empty2\233\001\n\tStreaming\022/\n\006So" + 38 | "urce\022\020.streaming.Empty\032\017.streaming.Item\"" + 39 | "\0000\001\022-\n\004Sink\022\017.streaming.Item\032\020.streaming" + 40 | ".Empty\"\000(\001\022.\n\004Pipe\022\017.streaming.Item\032\017.st" + 41 | "reaming.Item\"\000(\0010\001B\"\n\010examplesB\016Streamin" + 42 | "gProtoP\001\242\002\003RTGb\006proto3" 43 | }; 44 | descriptor = com.google.protobuf.Descriptors.FileDescriptor 45 | .internalBuildGeneratedFileFrom(descriptorData, 46 | new com.google.protobuf.Descriptors.FileDescriptor[] { 47 | }); 48 | internal_static_streaming_Item_descriptor = 49 | getDescriptor().getMessageTypes().get(0); 50 | internal_static_streaming_Item_fieldAccessorTable = new 51 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 52 | internal_static_streaming_Item_descriptor, 53 | new java.lang.String[] { "Value", }); 54 | internal_static_streaming_Empty_descriptor = 55 | getDescriptor().getMessageTypes().get(1); 56 | internal_static_streaming_Empty_fieldAccessorTable = new 57 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 58 | internal_static_streaming_Empty_descriptor, 59 | new java.lang.String[] { }); 60 | } 61 | 62 | // @@protoc_insertion_point(outer_class_scope) 63 | } 64 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/examples/StreamingProto.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: streaming.proto 3 | 4 | package examples; 5 | 6 | public final class StreamingProto { 7 | private StreamingProto() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistryLite registry) { 10 | } 11 | 12 | public static void registerAllExtensions( 13 | com.google.protobuf.ExtensionRegistry registry) { 14 | registerAllExtensions( 15 | (com.google.protobuf.ExtensionRegistryLite) registry); 16 | } 17 | static final com.google.protobuf.Descriptors.Descriptor 18 | internal_static_streaming_Item_descriptor; 19 | static final 20 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 21 | internal_static_streaming_Item_fieldAccessorTable; 22 | static final com.google.protobuf.Descriptors.Descriptor 23 | internal_static_streaming_Empty_descriptor; 24 | static final 25 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 26 | internal_static_streaming_Empty_fieldAccessorTable; 27 | 28 | public static com.google.protobuf.Descriptors.FileDescriptor 29 | getDescriptor() { 30 | return descriptor; 31 | } 32 | private static com.google.protobuf.Descriptors.FileDescriptor 33 | descriptor; 34 | static { 35 | java.lang.String[] descriptorData = { 36 | "\n\017streaming.proto\022\tstreaming\"\025\n\004Item\022\r\n\005" + 37 | "value\030\001 \001(\t\"\007\n\005Empty2\233\001\n\tStreaming\022/\n\006So" + 38 | "urce\022\020.streaming.Empty\032\017.streaming.Item\"" + 39 | "\0000\001\022-\n\004Sink\022\017.streaming.Item\032\020.streaming" + 40 | ".Empty\"\000(\001\022.\n\004Pipe\022\017.streaming.Item\032\017.st" + 41 | "reaming.Item\"\000(\0010\001B\"\n\010examplesB\016Streamin" + 42 | "gProtoP\001\242\002\003RTGb\006proto3" 43 | }; 44 | descriptor = com.google.protobuf.Descriptors.FileDescriptor 45 | .internalBuildGeneratedFileFrom(descriptorData, 46 | new com.google.protobuf.Descriptors.FileDescriptor[] { 47 | }); 48 | internal_static_streaming_Item_descriptor = 49 | getDescriptor().getMessageTypes().get(0); 50 | internal_static_streaming_Item_fieldAccessorTable = new 51 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 52 | internal_static_streaming_Item_descriptor, 53 | new java.lang.String[] { "Value", }); 54 | internal_static_streaming_Empty_descriptor = 55 | getDescriptor().getMessageTypes().get(1); 56 | internal_static_streaming_Empty_fieldAccessorTable = new 57 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 58 | internal_static_streaming_Empty_descriptor, 59 | new java.lang.String[] { }); 60 | } 61 | 62 | // @@protoc_insertion_point(outer_class_scope) 63 | } 64 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/io/vertx/grpc/server/GrpcServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.server; 12 | 13 | import io.grpc.MethodDescriptor; 14 | import io.vertx.codegen.annotations.Fluent; 15 | import io.vertx.codegen.annotations.GenIgnore; 16 | import io.vertx.codegen.annotations.VertxGen; 17 | import io.vertx.core.Handler; 18 | import io.vertx.core.Vertx; 19 | import io.vertx.core.buffer.Buffer; 20 | import io.vertx.core.http.HttpServerRequest; 21 | import io.vertx.grpc.server.impl.GrpcServerImpl; 22 | 23 | /** 24 | * A gRPC server based on Vert.x HTTP server. 25 | * 26 | *

The server can be used as a {@link io.vertx.core.http.HttpServer} handler or mounted as a Vert.x Web handler. 27 | * 28 | *

Unlike traditional gRPC servers, this server does not rely on a generated RPC interface to interact with the service. 29 | * 30 | * Instead, you can interact with the service with a request/response interfaces and gRPC messages, very much like 31 | * a traditional client. 32 | * 33 | * The server exposes 2 levels of handlers 34 | * 35 | *

    36 | *
  • a Protobuf message {@link #callHandler(Handler) handler}: {@link GrpcServerRequest}/{@link GrpcServerResponse} with Protobuf message that handles any method call in a generic way
  • 37 | *
  • a gRPC message {@link #callHandler(MethodDescriptor, Handler) handler}: {@link GrpcServerRequest}/{@link GrpcServerRequest} with gRPC messages that handles specific service method calls
  • 38 | *
39 | * 40 | */ 41 | @VertxGen 42 | public interface GrpcServer extends Handler { 43 | 44 | /** 45 | * Create a blank gRPC server 46 | * 47 | * @return the created server 48 | */ 49 | static GrpcServer server(Vertx vertx) { 50 | return new GrpcServerImpl(vertx); 51 | } 52 | 53 | /** 54 | * Set a call handler that handles any call made to the server. 55 | * 56 | * @param handler the service method call handler 57 | * @return a reference to this, so the API can be used fluently 58 | */ 59 | @Fluent 60 | GrpcServer callHandler(Handler> handler); 61 | 62 | /** 63 | * Set a service method call handler that handles any call call made to the server for the {@link MethodDescriptor} service method. 64 | * 65 | * @param handler the service method call handler 66 | * @return a reference to this, so the API can be used fluently 67 | */ 68 | @GenIgnore(GenIgnore.PERMITTED_TYPE) 69 | GrpcServer callHandler(MethodDescriptor methodDesc, Handler> handler); 70 | 71 | } 72 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/GrpcMessageEncoder.java: -------------------------------------------------------------------------------- 1 | package io.vertx.grpc.common; 2 | 3 | import io.grpc.MethodDescriptor; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.CompositeByteBuf; 6 | import io.netty.buffer.Unpooled; 7 | import io.netty.channel.embedded.EmbeddedChannel; 8 | import io.netty.handler.codec.compression.GzipOptions; 9 | import io.netty.handler.codec.compression.StandardCompressionOptions; 10 | import io.netty.handler.codec.compression.ZlibCodecFactory; 11 | import io.netty.handler.codec.compression.ZlibEncoder; 12 | import io.netty.handler.codec.compression.ZlibWrapper; 13 | import io.vertx.codegen.annotations.GenIgnore; 14 | import io.vertx.codegen.annotations.VertxGen; 15 | import io.vertx.core.VertxException; 16 | import io.vertx.core.buffer.Buffer; 17 | import io.vertx.core.buffer.impl.VertxByteBufAllocator; 18 | 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.util.Queue; 22 | 23 | @VertxGen 24 | public interface GrpcMessageEncoder { 25 | 26 | GrpcMessageEncoder IDENTITY = new GrpcMessageEncoder() { 27 | @Override 28 | public GrpcMessage encode(Buffer payload) { 29 | return GrpcMessage.message("identity", payload); 30 | } 31 | }; 32 | 33 | GrpcMessageEncoder GZIP = new GrpcMessageEncoder() { 34 | @Override 35 | public GrpcMessage encode(Buffer payload) { 36 | CompositeByteBuf composite = Unpooled.compositeBuffer(); 37 | GzipOptions options = StandardCompressionOptions.gzip(); 38 | ZlibEncoder encoder = ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP, options.compressionLevel(), options.windowBits(), options.memLevel()); 39 | EmbeddedChannel channel = new EmbeddedChannel(encoder); 40 | channel.config().setAllocator(VertxByteBufAllocator.UNPOOLED_ALLOCATOR); 41 | channel.writeOutbound(payload.getByteBuf()); 42 | channel.finish(); 43 | Queue messages = channel.outboundMessages(); 44 | ByteBuf a; 45 | while ((a = (ByteBuf) messages.poll()) != null) { 46 | composite.addComponent(true, a); 47 | } 48 | channel.close(); 49 | return GrpcMessage.message("gzip", Buffer.buffer(composite)); 50 | } 51 | }; 52 | 53 | @GenIgnore(GenIgnore.PERMITTED_TYPE) 54 | static GrpcMessageEncoder marshaller(MethodDescriptor.Marshaller desc) { 55 | return new GrpcMessageEncoder() { 56 | @Override 57 | public GrpcMessage encode(T msg) { 58 | Buffer encoded = Buffer.buffer(); 59 | InputStream stream = desc.stream(msg); 60 | byte[] tmp = new byte[256]; 61 | int i; 62 | try { 63 | while ((i = stream.read(tmp)) != -1) { 64 | encoded.appendBytes(tmp, 0, i); 65 | } 66 | } catch (IOException e) { 67 | throw new VertxException(e); 68 | } 69 | return GrpcMessage.message("identity", encoded); 70 | } 71 | }; 72 | } 73 | 74 | GrpcMessage encode(T msg); 75 | 76 | } 77 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/io/vertx/grpc/client/impl/GrpcClientImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.client.impl; 12 | 13 | import io.grpc.MethodDescriptor; 14 | import io.vertx.core.Future; 15 | import io.vertx.core.Vertx; 16 | import io.vertx.core.buffer.Buffer; 17 | import io.vertx.core.http.HttpClient; 18 | import io.vertx.core.http.HttpClientOptions; 19 | import io.vertx.core.http.HttpMethod; 20 | import io.vertx.core.http.HttpVersion; 21 | import io.vertx.core.http.RequestOptions; 22 | import io.vertx.core.net.SocketAddress; 23 | import io.vertx.grpc.client.GrpcClient; 24 | import io.vertx.grpc.client.GrpcClientRequest; 25 | import io.vertx.grpc.common.GrpcMessageDecoder; 26 | import io.vertx.grpc.common.GrpcMessageEncoder; 27 | 28 | /** 29 | * @author Julien Viet 30 | */ 31 | public class GrpcClientImpl implements GrpcClient { 32 | 33 | private final Vertx vertx; 34 | private HttpClient client; 35 | 36 | public GrpcClientImpl(HttpClientOptions options, Vertx vertx) { 37 | this.vertx = vertx; 38 | this.client = vertx.createHttpClient(new HttpClientOptions(options) 39 | .setProtocolVersion(HttpVersion.HTTP_2)); 40 | } 41 | 42 | public GrpcClientImpl(Vertx vertx) { 43 | this(new HttpClientOptions().setHttp2ClearTextUpgrade(false), vertx); 44 | } 45 | 46 | @Override public Future> request(SocketAddress server) { 47 | RequestOptions options = new RequestOptions() 48 | .setMethod(HttpMethod.POST) 49 | .setServer(server); 50 | return client.request(options) 51 | .map(request -> new GrpcClientRequestImpl<>(request, GrpcMessageEncoder.IDENTITY, GrpcMessageDecoder.IDENTITY)); 52 | } 53 | 54 | @Override public Future> request(SocketAddress server, MethodDescriptor service) { 55 | RequestOptions options = new RequestOptions() 56 | .setMethod(HttpMethod.POST) 57 | .setServer(server); 58 | GrpcMessageDecoder messageDecoder = GrpcMessageDecoder.unmarshaller(service.getResponseMarshaller()); 59 | GrpcMessageEncoder messageEncoder = GrpcMessageEncoder.marshaller(service.getRequestMarshaller()); 60 | return client.request(options) 61 | .map(request -> { 62 | GrpcClientRequestImpl call = new GrpcClientRequestImpl<>(request, messageEncoder, messageDecoder); 63 | call.fullMethodName(service.getFullMethodName()); 64 | return call; 65 | }); 66 | } 67 | 68 | @Override 69 | public Future close() { 70 | return client.close(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /vertx-grpc-common/src/main/java/io/vertx/grpc/common/GrpcMessageDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.common; 12 | 13 | import io.grpc.MethodDescriptor; 14 | import io.netty.buffer.ByteBuf; 15 | import io.netty.channel.ChannelFuture; 16 | import io.netty.channel.embedded.EmbeddedChannel; 17 | import io.netty.handler.codec.compression.ZlibCodecFactory; 18 | import io.netty.handler.codec.compression.ZlibWrapper; 19 | import io.vertx.codegen.annotations.GenIgnore; 20 | import io.vertx.codegen.annotations.VertxGen; 21 | import io.vertx.core.buffer.Buffer; 22 | import io.vertx.core.buffer.impl.VertxByteBufAllocator; 23 | 24 | import java.io.ByteArrayInputStream; 25 | import java.io.IOException; 26 | 27 | @VertxGen 28 | public interface GrpcMessageDecoder { 29 | 30 | GrpcMessageDecoder IDENTITY = new GrpcMessageDecoder() { 31 | @Override 32 | public Buffer decode(GrpcMessage msg) { 33 | return msg.payload(); 34 | } 35 | }; 36 | 37 | 38 | GrpcMessageDecoder GZIP = new GrpcMessageDecoder() { 39 | @Override 40 | public Buffer decode(GrpcMessage msg) throws CodecException { 41 | EmbeddedChannel channel = new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); 42 | channel.config().setAllocator(VertxByteBufAllocator.UNPOOLED_ALLOCATOR); 43 | try { 44 | ChannelFuture fut = channel.writeOneInbound(msg.payload().getByteBuf()); 45 | if (fut.isSuccess()) { 46 | Buffer decoded = null; 47 | while (true) { 48 | ByteBuf buf = channel.readInbound(); 49 | if (buf == null) { 50 | break; 51 | } 52 | if (decoded == null) { 53 | decoded = Buffer.buffer(buf); 54 | } else { 55 | decoded.appendBuffer(Buffer.buffer(buf)); 56 | } 57 | } 58 | if (decoded == null) { 59 | throw new CodecException("Invalid GZIP input"); 60 | } 61 | return decoded; 62 | } else { 63 | throw new CodecException(fut.cause()); 64 | } 65 | } finally { 66 | channel.close(); 67 | } 68 | } 69 | }; 70 | 71 | @GenIgnore(GenIgnore.PERMITTED_TYPE) 72 | static GrpcMessageDecoder unmarshaller(MethodDescriptor.Marshaller desc) { 73 | return new GrpcMessageDecoder() { 74 | @Override 75 | public T decode(GrpcMessage msg) { 76 | ByteArrayInputStream in = new ByteArrayInputStream(msg.payload().getBytes()); 77 | try { 78 | return desc.parse(in); 79 | } finally { 80 | try { 81 | in.close(); 82 | } catch (IOException ignore) { 83 | } 84 | } 85 | } 86 | }; 87 | } 88 | 89 | T decode(GrpcMessage msg) throws CodecException; 90 | 91 | } 92 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/io/vertx/grpc/server/impl/GrpcServerRequestImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.server.impl; 12 | 13 | import io.vertx.core.Future; 14 | import io.vertx.core.Handler; 15 | import io.vertx.core.MultiMap; 16 | import io.vertx.core.http.HttpConnection; 17 | import io.vertx.core.http.HttpServerRequest; 18 | import io.vertx.core.http.impl.HttpServerRequestInternal; 19 | import io.vertx.grpc.common.CodecException; 20 | import io.vertx.grpc.common.GrpcMessageDecoder; 21 | import io.vertx.grpc.common.GrpcMessageEncoder; 22 | import io.vertx.grpc.common.ServiceName; 23 | import io.vertx.grpc.common.impl.GrpcReadStreamBase; 24 | import io.vertx.grpc.common.impl.GrpcMethodCall; 25 | import io.vertx.grpc.server.GrpcServerRequest; 26 | import io.vertx.grpc.server.GrpcServerResponse; 27 | 28 | /** 29 | * @author Julien Viet 30 | */ 31 | public class GrpcServerRequestImpl extends GrpcReadStreamBase, Req> implements GrpcServerRequest { 32 | 33 | final HttpServerRequest httpRequest; 34 | final GrpcServerResponse response; 35 | private GrpcMethodCall methodCall; 36 | 37 | public GrpcServerRequestImpl(HttpServerRequest httpRequest, GrpcMessageDecoder messageDecoder, GrpcMessageEncoder messageEncoder, GrpcMethodCall methodCall) { 38 | super(((HttpServerRequestInternal) httpRequest).context(), httpRequest, httpRequest.headers().get("grpc-encoding"), messageDecoder); 39 | this.httpRequest = httpRequest; 40 | this.response = new GrpcServerResponseImpl<>(this, httpRequest.response(), messageEncoder); 41 | this.methodCall = methodCall; 42 | } 43 | 44 | public String fullMethodName() { 45 | return methodCall.fullMethodName(); 46 | } 47 | 48 | @Override 49 | public MultiMap headers() { 50 | return httpRequest.headers(); 51 | } 52 | 53 | @Override 54 | public String encoding() { 55 | return httpRequest.getHeader("grpc-encoding"); 56 | } 57 | 58 | @Override 59 | public ServiceName serviceName() { 60 | return methodCall.serviceName(); 61 | } 62 | 63 | @Override 64 | public String methodName() { 65 | return methodCall.methodName(); 66 | } 67 | 68 | @Override 69 | public GrpcServerRequest handler(Handler handler) { 70 | if (handler != null) { 71 | return messageHandler(msg -> { 72 | Req decoded; 73 | try { 74 | decoded = decodeMessage(msg); 75 | } catch (CodecException e) { 76 | response.cancel(); 77 | return; 78 | } 79 | handler.handle(decoded); 80 | }); 81 | } else { 82 | return messageHandler(null); 83 | } 84 | } 85 | 86 | public GrpcServerResponse response() { 87 | return response; 88 | } 89 | 90 | @Override 91 | public HttpConnection connection() { 92 | return httpRequest.connection(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/java/io/vertx/grpc/it/ProxyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.it; 12 | 13 | import io.grpc.examples.helloworld.GreeterGrpc; 14 | import io.grpc.examples.helloworld.HelloReply; 15 | import io.grpc.examples.helloworld.HelloRequest; 16 | import io.vertx.core.Future; 17 | import io.vertx.core.buffer.Buffer; 18 | import io.vertx.core.http.HttpServer; 19 | import io.vertx.core.net.SocketAddress; 20 | import io.vertx.ext.unit.Async; 21 | import io.vertx.ext.unit.TestContext; 22 | import io.vertx.grpc.client.GrpcClient; 23 | import io.vertx.grpc.server.GrpcServer; 24 | import io.vertx.grpc.server.GrpcServerResponse; 25 | import org.junit.Test; 26 | 27 | import java.util.concurrent.atomic.AtomicInteger; 28 | 29 | /** 30 | * @author Julien Viet 31 | */ 32 | public class ProxyTest extends ProxyTestBase { 33 | 34 | @Test 35 | public void testUnary(TestContext should) { 36 | 37 | GrpcClient client = GrpcClient.client(vertx); 38 | 39 | Future server = vertx.createHttpServer().requestHandler(GrpcServer.server(vertx).callHandler(GreeterGrpc.getSayHelloMethod(), call -> { 40 | call.handler(helloRequest -> { 41 | HelloReply helloReply = HelloReply.newBuilder().setMessage("Hello " + helloRequest.getName()).build(); 42 | call.response().end(helloReply); 43 | }); 44 | })).listen(8080, "localhost"); 45 | 46 | Future proxy = vertx.createHttpServer().requestHandler(GrpcServer.server(vertx).callHandler(clientReq -> { 47 | clientReq.pause(); 48 | client.request(SocketAddress.inetSocketAddress(8080, "localhost")).onComplete(should.asyncAssertSuccess(proxyReq -> { 49 | proxyReq.response().onSuccess(resp -> { 50 | GrpcServerResponse bc = clientReq.response(); 51 | resp.messageHandler(bc::writeMessage); 52 | resp.endHandler(v -> bc.end()); 53 | }); 54 | proxyReq.fullMethodName(clientReq.fullMethodName()); 55 | clientReq.messageHandler(proxyReq::writeMessage); 56 | clientReq.endHandler(v -> proxyReq.end()); 57 | clientReq.resume(); 58 | })); 59 | })).listen(8081, "localhost"); 60 | 61 | Async test = should.async(); 62 | server.flatMap(v -> proxy).onComplete(should.asyncAssertSuccess(v -> { 63 | client.request(SocketAddress.inetSocketAddress(8081, "localhost"), GreeterGrpc.getSayHelloMethod()) 64 | .onComplete(should.asyncAssertSuccess(callRequest -> { 65 | callRequest.response().onComplete(should.asyncAssertSuccess(callResponse -> { 66 | AtomicInteger count = new AtomicInteger(); 67 | callResponse.handler(reply -> { 68 | should.assertEquals(1, count.incrementAndGet()); 69 | should.assertEquals("Hello Julien", reply.getMessage()); 70 | }); 71 | callResponse.endHandler(v2 -> { 72 | should.assertEquals(1, count.get()); 73 | test.complete(); 74 | }); 75 | })); 76 | callRequest.end(HelloRequest.newBuilder().setName("Julien").build()); 77 | })); 78 | })); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/io/vertx/grpc/client/impl/GrpcClientResponseImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.client.impl; 12 | 13 | import io.vertx.core.Future; 14 | import io.vertx.core.Handler; 15 | import io.vertx.core.MultiMap; 16 | import io.vertx.core.Promise; 17 | import io.vertx.core.Vertx; 18 | import io.vertx.core.http.HttpClientResponse; 19 | 20 | import io.vertx.grpc.client.GrpcClientResponse; 21 | import io.vertx.grpc.common.CodecException; 22 | import io.vertx.grpc.common.GrpcMessageDecoder; 23 | import io.vertx.grpc.common.impl.GrpcReadStreamBase; 24 | import io.vertx.grpc.common.GrpcStatus; 25 | 26 | /** 27 | * @author Julien Viet 28 | */ 29 | public class GrpcClientResponseImpl extends GrpcReadStreamBase, Resp> implements GrpcClientResponse { 30 | 31 | private final GrpcClientRequestImpl request; 32 | private final HttpClientResponse httpResponse; 33 | private GrpcStatus status; 34 | private String encoding; 35 | 36 | public GrpcClientResponseImpl(GrpcClientRequestImpl request, HttpClientResponse httpResponse, GrpcMessageDecoder messageDecoder) { 37 | super(Vertx.currentContext(), httpResponse, httpResponse.headers().get("grpc-encoding"), messageDecoder); // A bit ugly 38 | this.request = request; 39 | this.encoding = httpResponse.headers().get("grpc-encoding"); 40 | this.httpResponse = httpResponse; 41 | 42 | String responseStatus = httpResponse.getHeader("grpc-status"); 43 | if (responseStatus != null) { 44 | status = GrpcStatus.valueOf(Integer.parseInt(responseStatus)); 45 | } 46 | } 47 | 48 | @Override 49 | public MultiMap headers() { 50 | return httpResponse.headers(); 51 | } 52 | 53 | @Override 54 | public String encoding() { 55 | return encoding; 56 | } 57 | 58 | @Override 59 | public MultiMap trailers() { 60 | return httpResponse.trailers(); 61 | } 62 | 63 | protected void handleEnd() { 64 | String responseStatus = httpResponse.getTrailer("grpc-status"); 65 | if (responseStatus != null) { 66 | status = GrpcStatus.valueOf(Integer.parseInt(responseStatus)); 67 | } 68 | super.handleEnd(); 69 | if (!request.trailersSent) { 70 | request.cancel(); 71 | } 72 | } 73 | 74 | @Override 75 | public GrpcStatus status() { 76 | return status; 77 | } 78 | 79 | @Override 80 | public Future end() { 81 | return super.end() 82 | .compose(v -> { 83 | if (status == GrpcStatus.OK) { 84 | return Future.succeededFuture(); 85 | } else { 86 | return Future.failedFuture("Invalid gRPC status " + status); 87 | } 88 | }); 89 | } 90 | 91 | @Override 92 | public GrpcClientResponseImpl handler(Handler handler) { 93 | if (handler != null) { 94 | return messageHandler(msg -> { 95 | Resp decoded; 96 | try { 97 | decoded = decodeMessage(msg); 98 | } catch (CodecException e) { 99 | request.cancel(); 100 | return; 101 | } 102 | handler.handle(decoded); 103 | }); 104 | } else { 105 | return messageHandler(null); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/java/io/vertx/grpc/server/impl/GrpcServerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.server.impl; 12 | 13 | import io.grpc.MethodDescriptor; 14 | import io.vertx.core.Handler; 15 | import io.vertx.core.Vertx; 16 | import io.vertx.core.buffer.Buffer; 17 | import io.vertx.core.http.HttpServerRequest; 18 | import io.vertx.grpc.common.GrpcMessageDecoder; 19 | import io.vertx.grpc.common.GrpcMessageEncoder; 20 | import io.vertx.grpc.common.impl.GrpcMethodCall; 21 | import io.vertx.grpc.server.GrpcServer; 22 | import io.vertx.grpc.server.GrpcServerRequest; 23 | 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | /** 28 | * @author Julien Viet 29 | */ 30 | public class GrpcServerImpl implements GrpcServer { 31 | 32 | private final Vertx vertx; 33 | private Handler> requestHandler; 34 | private Map> methodCallHandlers = new HashMap<>(); 35 | 36 | public GrpcServerImpl(Vertx vertx) { 37 | this.vertx = vertx; 38 | } 39 | 40 | @Override 41 | public void handle(HttpServerRequest httpRequest) { 42 | GrpcMethodCall methodCall = new GrpcMethodCall(httpRequest.path()); 43 | String fmn = methodCall.fullMethodName(); 44 | MethodCallHandler method = methodCallHandlers.get(fmn); 45 | if (method != null) { 46 | handle(method, httpRequest, methodCall); 47 | } else { 48 | Handler> handler = requestHandler; 49 | if (handler != null) { 50 | GrpcServerRequestImpl grpcRequest = new GrpcServerRequestImpl<>(httpRequest, GrpcMessageDecoder.IDENTITY, GrpcMessageEncoder.IDENTITY, methodCall); 51 | grpcRequest.init(); 52 | handler.handle(grpcRequest); 53 | } else { 54 | httpRequest.response().setStatusCode(500).end(); 55 | } 56 | } 57 | } 58 | 59 | private void handle(MethodCallHandler method, HttpServerRequest httpRequest, GrpcMethodCall methodCall) { 60 | GrpcServerRequestImpl grpcRequest = new GrpcServerRequestImpl<>(httpRequest, method.messageDecoder, method.messageEncoder, methodCall); 61 | grpcRequest.init(); 62 | method.handle(grpcRequest); 63 | } 64 | 65 | public GrpcServer callHandler(Handler> handler) { 66 | this.requestHandler = handler; 67 | return this; 68 | } 69 | 70 | public GrpcServer callHandler(MethodDescriptor methodDesc, Handler> handler) { 71 | if (handler != null) { 72 | methodCallHandlers.put(methodDesc.getFullMethodName(), new MethodCallHandler<>(methodDesc, GrpcMessageDecoder.unmarshaller(methodDesc.getRequestMarshaller()), GrpcMessageEncoder.marshaller(methodDesc.getResponseMarshaller()), handler)); 73 | } else { 74 | methodCallHandlers.remove(methodDesc.getFullMethodName()); 75 | } 76 | return this; 77 | } 78 | 79 | private static class MethodCallHandler implements Handler> { 80 | 81 | final MethodDescriptor def; 82 | final GrpcMessageDecoder messageDecoder; 83 | final GrpcMessageEncoder messageEncoder; 84 | final Handler> handler; 85 | 86 | MethodCallHandler(MethodDescriptor def, GrpcMessageDecoder messageDecoder, GrpcMessageEncoder messageEncoder, Handler> handler) { 87 | this.def = def; 88 | this.messageDecoder = messageDecoder; 89 | this.messageEncoder = messageEncoder; 90 | this.handler = handler; 91 | } 92 | 93 | @Override 94 | public void handle(GrpcServerRequest grpcRequest) { 95 | handler.handle(grpcRequest); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/io/vertx/grpc/client/GrpcClientRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.client; 12 | 13 | import io.vertx.codegen.annotations.CacheReturn; 14 | import io.vertx.codegen.annotations.Fluent; 15 | import io.vertx.codegen.annotations.Nullable; 16 | import io.vertx.codegen.annotations.VertxGen; 17 | import io.vertx.core.Future; 18 | import io.vertx.core.Handler; 19 | import io.vertx.core.MultiMap; 20 | import io.vertx.core.buffer.Buffer; 21 | import io.vertx.core.http.HttpClientResponse; 22 | import io.vertx.core.http.HttpConnection; 23 | import io.vertx.core.http.HttpHeaders; 24 | import io.vertx.core.streams.ReadStream; 25 | import io.vertx.grpc.common.GrpcWriteStream; 26 | import io.vertx.grpc.common.ServiceName; 27 | 28 | /** 29 | * A request to a gRPC server. 30 | * 31 | *

You interact with the remote service with gRPC generated messages or protobuf encoded messages. 32 | * 33 | *

Before sending a request you need to set {@link #serviceName)} and {@link #methodName)} or 34 | * alternatively the service {@link #fullMethodName}. 35 | * 36 | *

Writing a request message will send the request to the service: 37 | * 38 | *

    39 | *
  • To send a unary request, just call {@link #end(Req)}
  • 40 | *
  • To send a streaming request, call {@link #write(Req)} any time you need and then {@link #end()}
  • 41 | *
42 | */ 43 | @VertxGen 44 | public interface GrpcClientRequest extends GrpcWriteStream { 45 | 46 | @Fluent 47 | GrpcClientRequest encoding(String encoding); 48 | 49 | /** 50 | * Set the full method name to call, it must follow the format {@code package-name + '.' + service-name + '/' + method-name} 51 | * or an {@code IllegalArgumentException} is thrown. 52 | * 53 | *

It must be called before sending the request otherwise an {@code IllegalStateException} is thrown. 54 | * 55 | * @param fullMethodName the full method name to call 56 | * @return a reference to this, so the API can be used fluently 57 | */ 58 | @Fluent 59 | GrpcClientRequest fullMethodName(String fullMethodName); 60 | 61 | /** 62 | * Set the service name to call. 63 | * 64 | *

It must be called before sending the request otherwise an {@code IllegalStateException} is thrown. 65 | * 66 | * @param serviceName the service name to call 67 | * @return a reference to this, so the API can be used fluently 68 | */ 69 | @Fluent 70 | GrpcClientRequest serviceName(ServiceName serviceName); 71 | 72 | /** 73 | * Set the method name to call. 74 | * 75 | *

It must be called before sending the request otherwise an {@code IllegalStateException} is thrown. 76 | * 77 | * @param methodName the method name to call 78 | * @return a reference to this, so the API can be used fluently 79 | */ 80 | @Fluent 81 | GrpcClientRequest methodName(String methodName); 82 | 83 | /** 84 | * @return the gRPC response 85 | */ 86 | @CacheReturn 87 | Future> response(); 88 | 89 | @Override 90 | GrpcClientRequest exceptionHandler(@Nullable Handler handler); 91 | 92 | @Override 93 | GrpcClientRequest setWriteQueueMaxSize(int maxSize); 94 | 95 | @Override 96 | GrpcClientRequest drainHandler(@Nullable Handler handler); 97 | 98 | /** 99 | * @return the underlying HTTP connection 100 | */ 101 | HttpConnection connection(); 102 | 103 | default Future> send(Req item) { 104 | this.end(item); 105 | return this.response(); 106 | } 107 | 108 | default Future> send(ReadStream body) { 109 | body.pipeTo(this); 110 | return this.response(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /vertx-grpc-it/src/test/proto/test.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // An integration test service that covers all the method signature permutations 31 | // of unary/streaming requests/responses. 32 | syntax = "proto3"; 33 | 34 | import "empty.proto"; 35 | import "messages.proto"; 36 | 37 | package grpc.testing; 38 | 39 | option java_package = "io.grpc.testing.integration"; 40 | 41 | // A simple service to test the various types of RPCs and experiment with 42 | // performance with various types of payload. 43 | service TestService { 44 | // One empty request followed by one empty response. 45 | rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); 46 | 47 | // One request followed by one response. 48 | rpc UnaryCall(SimpleRequest) returns (SimpleResponse); 49 | 50 | // One request followed by a sequence of responses (streamed download). 51 | // The server returns the payload with client desired type and sizes. 52 | rpc StreamingOutputCall(StreamingOutputCallRequest) 53 | returns (stream StreamingOutputCallResponse); 54 | 55 | // A sequence of requests followed by one response (streamed upload). 56 | // The server returns the aggregated size of client payload as the result. 57 | rpc StreamingInputCall(stream StreamingInputCallRequest) 58 | returns (StreamingInputCallResponse); 59 | 60 | // A sequence of requests with each request served by the server immediately. 61 | // As one request could lead to multiple responses, this interface 62 | // demonstrates the idea of full duplexing. 63 | rpc FullDuplexCall(stream StreamingOutputCallRequest) 64 | returns (stream StreamingOutputCallResponse); 65 | 66 | // A sequence of requests followed by a sequence of responses. 67 | // The server buffers all the client requests and then serves them in order. A 68 | // stream of responses are returned to the client when the server starts with 69 | // first request. 70 | rpc HalfDuplexCall(stream StreamingOutputCallRequest) 71 | returns (stream StreamingOutputCallResponse); 72 | 73 | // The test server will not implement this method. It will be used 74 | // to test the behavior when clients call unimplemented methods. 75 | rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); 76 | } 77 | 78 | // A simple service NOT implemented at servers so clients can test for 79 | // that case. 80 | service UnimplementedService { 81 | // A call that no server should implement 82 | rpc UnimplementedCall(grpc.testing.Empty) returns(grpc.testing.Empty); 83 | } 84 | 85 | // A service used to control reconnect server. 86 | service ReconnectService { 87 | rpc Start(grpc.testing.Empty) returns (grpc.testing.Empty); 88 | rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); 89 | } 90 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/test/proto/test.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // An integration test service that covers all the method signature permutations 31 | // of unary/streaming requests/responses. 32 | syntax = "proto3"; 33 | 34 | import "empty.proto"; 35 | import "messages.proto"; 36 | 37 | package grpc.testing; 38 | 39 | option java_package = "io.grpc.testing.integration"; 40 | 41 | // A simple service to test the various types of RPCs and experiment with 42 | // performance with various types of payload. 43 | service TestService { 44 | // One empty request followed by one empty response. 45 | rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); 46 | 47 | // One request followed by one response. 48 | rpc UnaryCall(SimpleRequest) returns (SimpleResponse); 49 | 50 | // One request followed by a sequence of responses (streamed download). 51 | // The server returns the payload with client desired type and sizes. 52 | rpc StreamingOutputCall(StreamingOutputCallRequest) 53 | returns (stream StreamingOutputCallResponse); 54 | 55 | // A sequence of requests followed by one response (streamed upload). 56 | // The server returns the aggregated size of client payload as the result. 57 | rpc StreamingInputCall(stream StreamingInputCallRequest) 58 | returns (StreamingInputCallResponse); 59 | 60 | // A sequence of requests with each request served by the server immediately. 61 | // As one request could lead to multiple responses, this interface 62 | // demonstrates the idea of full duplexing. 63 | rpc FullDuplexCall(stream StreamingOutputCallRequest) 64 | returns (stream StreamingOutputCallResponse); 65 | 66 | // A sequence of requests followed by a sequence of responses. 67 | // The server buffers all the client requests and then serves them in order. A 68 | // stream of responses are returned to the client when the server starts with 69 | // first request. 70 | rpc HalfDuplexCall(stream StreamingOutputCallRequest) 71 | returns (stream StreamingOutputCallResponse); 72 | 73 | // The test server will not implement this method. It will be used 74 | // to test the behavior when clients call unimplemented methods. 75 | rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); 76 | } 77 | 78 | // A simple service NOT implemented at servers so clients can test for 79 | // that case. 80 | service UnimplementedService { 81 | // A call that no server should implement 82 | rpc UnimplementedCall(grpc.testing.Empty) returns(grpc.testing.Empty); 83 | } 84 | 85 | // A service used to control reconnect server. 86 | service ReconnectService { 87 | rpc Start(grpc.testing.Empty) returns (grpc.testing.Empty); 88 | rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); 89 | } 90 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/test/proto/test.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // An integration test service that covers all the method signature permutations 31 | // of unary/streaming requests/responses. 32 | syntax = "proto3"; 33 | 34 | import "empty.proto"; 35 | import "messages.proto"; 36 | 37 | package grpc.testing; 38 | 39 | option java_package = "io.grpc.testing.integration"; 40 | 41 | // A simple service to test the various types of RPCs and experiment with 42 | // performance with various types of payload. 43 | service TestService { 44 | // One empty request followed by one empty response. 45 | rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); 46 | 47 | // One request followed by one response. 48 | rpc UnaryCall(SimpleRequest) returns (SimpleResponse); 49 | 50 | // One request followed by a sequence of responses (streamed download). 51 | // The server returns the payload with client desired type and sizes. 52 | rpc StreamingOutputCall(StreamingOutputCallRequest) 53 | returns (stream StreamingOutputCallResponse); 54 | 55 | // A sequence of requests followed by one response (streamed upload). 56 | // The server returns the aggregated size of client payload as the result. 57 | rpc StreamingInputCall(stream StreamingInputCallRequest) 58 | returns (StreamingInputCallResponse); 59 | 60 | // A sequence of requests with each request served by the server immediately. 61 | // As one request could lead to multiple responses, this interface 62 | // demonstrates the idea of full duplexing. 63 | rpc FullDuplexCall(stream StreamingOutputCallRequest) 64 | returns (stream StreamingOutputCallResponse); 65 | 66 | // A sequence of requests followed by a sequence of responses. 67 | // The server buffers all the client requests and then serves them in order. A 68 | // stream of responses are returned to the client when the server starts with 69 | // first request. 70 | rpc HalfDuplexCall(stream StreamingOutputCallRequest) 71 | returns (stream StreamingOutputCallResponse); 72 | 73 | // The test server will not implement this method. It will be used 74 | // to test the behavior when clients call unimplemented methods. 75 | rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); 76 | } 77 | 78 | // A simple service NOT implemented at servers so clients can test for 79 | // that case. 80 | service UnimplementedService { 81 | // A call that no server should implement 82 | rpc UnimplementedCall(grpc.testing.Empty) returns(grpc.testing.Empty); 83 | } 84 | 85 | // A service used to control reconnect server. 86 | service ReconnectService { 87 | rpc Start(grpc.testing.Empty) returns (grpc.testing.Empty); 88 | rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); 89 | } 90 | -------------------------------------------------------------------------------- /vertx-grpc-context-storage/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | 9 | io.vertx 10 | vertx-grpc-aggregator 11 | 5.0.0-SNAPSHOT 12 | ../pom.xml 13 | 14 | 15 | vertx-grpc-context-storage 16 | 17 | Vert.x gRPC Context Storage implementation 18 | This modules provides an io.grpc.override.ContextStorageOverride implementation which uses Vert.x local 19 | context data maps. 20 | 21 | 22 | 23 | false 24 | 25 | 26 | 27 | 28 | io.vertx 29 | vertx-grpc-common 30 | 31 | 32 | 33 | io.vertx 34 | vertx-unit 35 | test 36 | 37 | 38 | io.vertx 39 | vertx-grpc-client 40 | test 41 | 42 | 43 | io.vertx 44 | vertx-grpc-server 45 | test 46 | 47 | 48 | io.grpc 49 | grpc-netty 50 | ${grpc.version} 51 | test 52 | 53 | 54 | com.google.guava 55 | guava 56 | 57 | 58 | com.google.errorprone 59 | error_prone_annotations 60 | 61 | 62 | org.codehaus.mojo 63 | animal-sniffer-annotations 64 | 65 | 66 | io.netty 67 | * 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | kr.motd.maven 77 | os-maven-plugin 78 | 1.4.1.Final 79 | 80 | 81 | 82 | 83 | org.xolstice.maven.plugins 84 | protobuf-maven-plugin 85 | 0.6.1 86 | 87 | 92 | com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} 93 | grpc-java 94 | io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} 95 | 96 | 97 | 98 | test-compile 99 | 100 | test-compile 101 | test-compile-custom 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | java-11 112 | 113 | (1.8,) 114 | 115 | 116 | 117 | javax.annotation 118 | javax.annotation-api 119 | 1.3.2 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /vertx-grpc-server/src/main/asciidoc/server.adoc: -------------------------------------------------------------------------------- 1 | == Vert.x gRPC Server 2 | 3 | Vert.x gRPC Server is a new gRPC server powered by Vert.x HTTP server superseding the integrated Netty based gRPC client. 4 | 5 | This server provides a gRPC request/response oriented API as well as a the generated stub approach with a service bridge. 6 | 7 | === Using Vert.x gRPC Server 8 | 9 | To use Vert.x gRPC Server, add the following dependency to the _dependencies_ section of your build descriptor: 10 | 11 | * Maven (in your `pom.xml`): 12 | 13 | [source,xml,subs="+attributes"] 14 | ---- 15 | 16 | io.vertx 17 | vertx-grpc-server 18 | ${maven.version} 19 | 20 | ---- 21 | 22 | * Gradle (in your `build.gradle` file): 23 | 24 | [source,groovy,subs="+attributes"] 25 | ---- 26 | dependencies { 27 | compile 'io.vertx:vertx-grpc-server:${maven.version}' 28 | } 29 | ---- 30 | 31 | === gRPC request/response server API 32 | 33 | The gRPC request/response server API provides an alternative way to interact with a client without the need of a generated stub. 34 | 35 | A `{@link io.vertx.grpc.server.GrpcServer}` is a `Handler` and can be used as an HTTP server request handler. 36 | 37 | [source,java] 38 | ---- 39 | {@link examples.GrpcServerExamples#createServer} 40 | ---- 41 | 42 | TIP: a `GrpcServer` can be mounted in a Vert.x Web router 43 | 44 | ==== Request/response 45 | 46 | Each service method is processed by a handler 47 | 48 | [source,java] 49 | ---- 50 | {@link examples.GrpcServerExamples#requestResponse} 51 | ---- 52 | 53 | ==== Streaming request 54 | 55 | You can set handlers to process request events 56 | 57 | [source,java] 58 | ---- 59 | {@link examples.GrpcServerExamples#streamingRequest} 60 | ---- 61 | 62 | ==== Streaming response 63 | 64 | A streaming response involves calling `{@link io.vertx.grpc.server.GrpcServerResponse#write}` for each element of the stream 65 | and using `{@link io.vertx.grpc.server.GrpcServerResponse#end()}` to end the stream 66 | 67 | [source,java] 68 | ---- 69 | {@link examples.GrpcServerExamples#streamingResponse} 70 | ---- 71 | 72 | ==== Bidi request/response 73 | 74 | A bidi request/response is simply the combination of a streaming request and a streaming response 75 | 76 | [source,java] 77 | ---- 78 | {@link examples.GrpcServerExamples#bidi} 79 | ---- 80 | 81 | === Flow control 82 | 83 | Request and response are back pressured Vert.x streams. 84 | 85 | You can pause/resume/fetch a request 86 | 87 | [source,java] 88 | ---- 89 | {@link examples.GrpcServerExamples#requestFlowControl} 90 | ---- 91 | 92 | You can check the writability of a response and set a drain handler 93 | 94 | [source,java] 95 | ---- 96 | {@link examples.GrpcServerExamples#responseFlowControl} 97 | ---- 98 | 99 | === Compression 100 | 101 | You can compress response messages by setting the response encoding *prior* before sending any message 102 | 103 | [source,java] 104 | ---- 105 | {@link examples.GrpcServerExamples#responseCompression} 106 | ---- 107 | 108 | === Decompression 109 | 110 | Decompression is done transparently by the server when the client send encoded requests. 111 | 112 | === Stub API 113 | 114 | The Vert.x gRPC Server can bridge a gRPC service to use with a generated server stub in a more traditional fashion 115 | 116 | [source,java] 117 | ---- 118 | {@link examples.GrpcServerExamples#stubExample} 119 | ---- 120 | 121 | === Message level API 122 | 123 | The server provides a message level API to interact directly with protobuf encoded gRPC messages. 124 | 125 | TIP: the server message level API can be used with the client message level API to write a gRPC reverse proxy 126 | 127 | Such API is useful when you are not interested in the content of the messages, and instead you want to forward them to 128 | another service, e.g. you are writing a proxy. 129 | 130 | [source,java] 131 | ---- 132 | {@link examples.GrpcServerExamples#protobufLevelAPI} 133 | ---- 134 | 135 | You can also set a `messageHandler` to handle `{@link io.vertx.grpc.common.GrpcMessage}`, such messages preserve the 136 | client encoding, which is useful the service you are forwarding to can handle compressed messages directly, in this case 137 | the message does not need to be decompressed and compressed again. 138 | 139 | [source,java] 140 | ---- 141 | {@link examples.GrpcServerExamples#messageLevelAPI} 142 | ---- 143 | 144 | The `{@link io.vertx.grpc.server.GrpcServerResponse#writeMessage}` and `{@link io.vertx.grpc.server.GrpcServerResponse#endMessage}` will 145 | handle the message encoding: 146 | 147 | - when the message uses the response encoding, the message is sent as is 148 | - when the message uses a different encoding, it will be encoded, e.g. compressed or uncompressed 149 | -------------------------------------------------------------------------------- /vertx-grpc-client/src/main/java/io/vertx/grpc/client/GrpcClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2022 Contributors to the Eclipse Foundation 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 | */ 11 | package io.vertx.grpc.client; 12 | 13 | import io.grpc.MethodDescriptor; 14 | import io.vertx.codegen.annotations.GenIgnore; 15 | import io.vertx.codegen.annotations.VertxGen; 16 | import io.vertx.core.Future; 17 | import io.vertx.core.Handler; 18 | import io.vertx.core.Vertx; 19 | import io.vertx.core.buffer.Buffer; 20 | import io.vertx.core.http.HttpClientOptions; 21 | import io.vertx.core.net.SocketAddress; 22 | import io.vertx.core.streams.ReadStream; 23 | import io.vertx.grpc.client.impl.GrpcClientImpl; 24 | 25 | import java.util.function.Function; 26 | 27 | /** 28 | * A gRPC client for Vert.x 29 | * 30 | * Unlike traditional gRPC clients, this client does not rely on a generated RPC interface to interact with the service. 31 | * 32 | * Instead, you can interact with the service with a request/response interfaces and gRPC messages, very much like 33 | * a traditional client. 34 | * 35 | * The client exposes 2 levels of API 36 | * 37 | *

    38 | *
  • a Protobuf message {@link #request(SocketAddress) API}: {@link GrpcClientRequest}/{@link GrpcClientResponse} with Protobuf messages to call any gRPC service in a generic way
  • 39 | *
  • a gRPC message {@link #request(SocketAddress, MethodDescriptor)}: {@link GrpcClientRequest}/{@link GrpcClientRequest} with gRPC messages to call a given method of a gRPC service
  • 40 | *
41 | */ 42 | @VertxGen 43 | public interface GrpcClient { 44 | 45 | /** 46 | * Create a new client 47 | * 48 | * @param vertx the vertx instance 49 | * @return the created client 50 | */ 51 | static GrpcClient client(Vertx vertx) { 52 | return new GrpcClientImpl(vertx); 53 | } 54 | 55 | /** 56 | * Create a new client 57 | * 58 | * @param vertx the vertx instance 59 | * @param options the client options 60 | * @return the created client 61 | */ 62 | static GrpcClient client(Vertx vertx, HttpClientOptions options) { 63 | return new GrpcClientImpl(options, vertx); 64 | } 65 | 66 | /** 67 | * Connect to the remote {@code server} and create a request for any hosted gRPC service. 68 | * 69 | * @param server the server hosting the service 70 | * @return a future request 71 | */ 72 | Future> request(SocketAddress server); 73 | 74 | /** 75 | * Connect to the remote {@code server} and create a request for given {@code method} of a hosted gRPC service. 76 | * 77 | * @param server the server hosting the service 78 | * @param service the service to be called 79 | * @return a future request 80 | */ 81 | @GenIgnore(GenIgnore.PERMITTED_TYPE) 82 | Future> request(SocketAddress server, MethodDescriptor service); 83 | 84 | /** 85 | * Call the {@code service} gRPC service hosted by {@code server}. 86 | *

87 | * The {@code requestHandler} is called to send the request, e.g. {@code req -> req.send(item)} 88 | *

89 | * The {@code responseFunction} extracts the result, e.g. {@code resp -> resp.last()} 90 | *

91 | * It can be used in various ways: 92 | *

    93 | *
  • {@code Future fut = client.call(..., req -> req.send(item), resp -> resp.last());}
  • 94 | *
  • {@code Future fut = client.call(..., req -> req.send(stream), resp -> resp.pipeTo(anotherService));}
  • 95 | *
  • {@code Future> fut = client.call(..., req -> req.send(stream), resp -> resp.collecting(Collectors.toList()));}
  • 96 | *
97 | *
 98 |    *
 99 |    * @param server the server hosting the service
100 |    * @param service the service to call
101 |    * @param requestHandler the handler called to send the request
102 |    * @param resultFn the function applied to extract the result.
103 |    * @return a future of the result
104 |    */
105 |   @GenIgnore(GenIgnore.PERMITTED_TYPE)
106 |   default  Future call(SocketAddress server, MethodDescriptor service, Handler> requestHandler, Function, Future> resultFn) {
107 |     return request(server, service).compose(req -> {
108 |       requestHandler.handle(req);
109 |       return req
110 |         .response()
111 |         .compose(resultFn);
112 |     });
113 |   }
114 | 
115 |   /**
116 |    * Close this client.
117 |    */
118 |   Future close();
119 | 
120 | }
121 | 


--------------------------------------------------------------------------------
/vertx-grpc-client/src/main/asciidoc/client.adoc:
--------------------------------------------------------------------------------
  1 | == Vert.x gRPC Client
  2 | 
  3 | Vert.x gRPC Client is a new gRPC client powered by Vert.x HTTP client superseding the integrated Netty based gRPC client.
  4 | 
  5 | This client provides a gRPC request/response oriented API as well as a the generated stub approach with a gRPC Channel
  6 | 
  7 | === Using Vert.x gRPC Client
  8 | 
  9 | To use Vert.x gRPC Client, add the following dependency to the _dependencies_ section of your build descriptor:
 10 | 
 11 | * Maven (in your `pom.xml`):
 12 | 
 13 | [source,xml,subs="+attributes"]
 14 | ----
 15 | 
 16 |   io.vertx
 17 |   vertx-grpc-client
 18 |   ${maven.version}
 19 | 
 20 | ----
 21 | 
 22 | * Gradle (in your `build.gradle` file):
 23 | 
 24 | [source,groovy,subs="+attributes"]
 25 | ----
 26 | dependencies {
 27 |   compile 'io.vertx:vertx-grpc-client:${maven.version}'
 28 | }
 29 | ----
 30 | 
 31 | === gRPC request/response client API
 32 | 
 33 | The gRPC request/response client API provides an alternative way to interact with a server without the need of a generated stub.
 34 | 
 35 | You can easily create the gRPC client
 36 | 
 37 | [source,java]
 38 | ----
 39 | {@link examples.GrpcClientExamples#createClient}
 40 | ----
 41 | 
 42 | ==== Request/response
 43 | 
 44 | Any interaction with a gRPC server involves creating a request to the remote gRPC service
 45 | 
 46 | [source,java]
 47 | ----
 48 | {@link examples.GrpcClientExamples#sendRequest}
 49 | ----
 50 | 
 51 | The `{@link io.vertx.grpc.client.GrpcClientRequest#response}` holds the response and the
 52 | `{@link io.vertx.grpc.client.GrpcClientResponse#last}` holds the result
 53 | 
 54 | [source,java]
 55 | ----
 56 | {@link examples.GrpcClientExamples#receiveResponse}
 57 | ----
 58 | 
 59 | Future composition can combine all the previous steps together in a compact fashion
 60 | 
 61 | [source,java]
 62 | ----
 63 | {@link examples.GrpcClientExamples#requestResponse}
 64 | ----
 65 | 
 66 | ==== Streaming request
 67 | 
 68 | A streaming request involves calling `{@link io.vertx.grpc.client.GrpcClientRequest#write}` for each element of the stream
 69 | and using `{@link io.vertx.grpc.client.GrpcClientRequest#end()}` to end the stream
 70 | 
 71 | [source,java]
 72 | ----
 73 | {@link examples.GrpcClientExamples#streamingRequest}
 74 | ----
 75 | 
 76 | ==== Streaming response
 77 | 
 78 | You can set handlers to process response events
 79 | 
 80 | [source,java]
 81 | ----
 82 | {@link examples.GrpcClientExamples#streamingResponse}
 83 | ----
 84 | 
 85 | ==== Bidi request/response
 86 | 
 87 | A bidi request/response is simply the combination of a streaming request and a streaming response.
 88 | 
 89 | === Flow control
 90 | 
 91 | Request and response are back pressured Vert.x streams.
 92 | 
 93 | You can check the writability of a request and set a drain handler
 94 | 
 95 | [source,java]
 96 | ----
 97 | {@link examples.GrpcClientExamples#requestFlowControl}
 98 | ----
 99 | 
100 | You can pause/resume/fetch a response
101 | 
102 | [source,java]
103 | ----
104 | {@link examples.GrpcClientExamples#responseFlowControl}
105 | ----
106 | 
107 | === Cancellation
108 | 
109 | You can call `{@link io.vertx.grpc.client.GrpcClientRequest#cancel}` to cancel a request
110 | 
111 | [source,java]
112 | ----
113 | {@link examples.GrpcClientExamples#requestCancellation}
114 | ----
115 | 
116 | NOTE: cancellation sends an HTTP/2 reset frame to the server
117 | 
118 | === Compression
119 | 
120 | You can compress request messages by setting the request encoding *prior* before sending any message
121 | 
122 | [source,java]
123 | ----
124 | {@link examples.GrpcClientExamples#requestCompression}
125 | ----
126 | 
127 | === Decompression
128 | 
129 | Decompression is done transparently by the client when the server send encoded responses.
130 | 
131 | === Stub API
132 | 
133 | The Vert.x gRPC Client provides a gRPC channel to use with a generated client stub in a more traditional fashion
134 | 
135 | [source,java]
136 | ----
137 | {@link examples.GrpcClientExamples#stubExample}
138 | ----
139 | 
140 | === Message level API
141 | 
142 | The client provides a message level API to interact directly with protobuf encoded gRPC messages.
143 | 
144 | TIP: the client message level API can be used with the server message level API to write a gRPC reverse proxy
145 | 
146 | Such API is useful when you are not interested in the content of the messages, and instead you want to forward them to
147 | another service, e.g. you are writing a proxy.
148 | 
149 | [source,java]
150 | ----
151 | {@link examples.GrpcClientExamples#protobufLevelAPI}
152 | ----
153 | 
154 | You can also set a `messageHandler` to handle `{@link io.vertx.grpc.common.GrpcMessage}`, such messages preserve the server encoding.
155 | 
156 | [source,java]
157 | ----
158 | {@link examples.GrpcClientExamples#messageLevelAPI}
159 | ----
160 | 
161 | The `{@link io.vertx.grpc.client.GrpcClientRequest#writeMessage}` and `{@link io.vertx.grpc.client.GrpcClientRequest#endMessage}` will
162 | handle the message encoding:
163 | 
164 | - when the message uses the response encoding, the message is sent as is
165 | - when the message uses a different encoding, it will be encoded, e.g. compressed or uncompressed
166 | 


--------------------------------------------------------------------------------
/vertx-grpc-it/pom.xml:
--------------------------------------------------------------------------------
  1 | 
  2 | 
 17 | 
 18 | 
 19 |   4.0.0
 20 | 
 21 |   
 22 |     io.vertx
 23 |     vertx-grpc-aggregator
 24 |     5.0.0-SNAPSHOT
 25 |     ../pom.xml
 26 |   
 27 | 
 28 |   vertx-grpc-it
 29 | 
 30 |   Vert.x gRPC integration tests
 31 | 
 32 |   
 33 |     true
 34 |     ${project.basedir}/src/main/resources/META-INF/MANIFEST.MF
 35 |   
 36 | 
 37 |   
 38 |     
 39 |       io.vertx
 40 |       vertx-grpc-client
 41 |     
 42 |     
 43 |       io.vertx
 44 |       vertx-grpc-server
 45 |     
 46 | 
 47 |     
 48 |       io.vertx
 49 |       vertx-grpc-common
 50 |       ${project.version}
 51 |       test-jar
 52 |       test
 53 |     
 54 |     
 55 |       io.vertx
 56 |       vertx-unit
 57 |       test
 58 |     
 59 |     
 60 |     
 61 |       org.bouncycastle
 62 |       bcpkix-jdk15on
 63 |       1.65
 64 |       test
 65 |     
 66 |     
 67 |       io.grpc
 68 |       grpc-stub
 69 |       ${grpc.version}
 70 |       test
 71 |       
 72 |         
 73 |           com.google.errorprone
 74 |           error_prone_annotations
 75 |         
 76 |       
 77 |     
 78 |     
 79 |       io.grpc
 80 |       grpc-netty
 81 |       ${grpc.version}
 82 |       test
 83 |       
 84 |         
 85 |           com.google.guava
 86 |           guava
 87 |         
 88 |         
 89 |           com.google.errorprone
 90 |           error_prone_annotations
 91 |         
 92 |         
 93 |           org.codehaus.mojo
 94 |           animal-sniffer-annotations
 95 |         
 96 |         
 97 |           io.netty
 98 |           *
 99 |         
100 |       
101 |     
102 |   
103 | 
104 |   
105 |     
106 |       
107 |         kr.motd.maven
108 |         os-maven-plugin
109 |         1.4.1.Final
110 |       
111 |     
112 |     
113 |       
114 |         org.xolstice.maven.plugins
115 |         protobuf-maven-plugin
116 |         0.6.1
117 |         
118 |           
123 |           com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
124 |           grpc-java
125 |           io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
126 |         
127 |         
128 |           
129 |             test-compile
130 |             
131 |               test-compile
132 |               test-compile-custom
133 |             
134 |           
135 |         
136 |       
137 |     
138 |   
139 | 
140 |   
141 |     
142 |       java-11
143 |       
144 |         (1.8,)
145 |       
146 |       
147 |         
148 |           javax.annotation
149 |           javax.annotation-api
150 |           1.3.2
151 |         
152 |       
153 |     
154 |   
155 | 
156 | 
157 | 


--------------------------------------------------------------------------------
/vertx-grpc-common/pom.xml:
--------------------------------------------------------------------------------
  1 | 
  2 | 
 17 | 
 18 | 
 19 |   4.0.0
 20 | 
 21 |   
 22 |     io.vertx
 23 |     vertx-grpc-aggregator
 24 |     5.0.0-SNAPSHOT
 25 |     ../pom.xml
 26 |   
 27 | 
 28 |   vertx-grpc-common
 29 | 
 30 |   Vert.x gRPC Common
 31 | 
 32 |   
 33 |     false
 34 |     ${project.basedir}/src/main/resources/META-INF/MANIFEST.MF
 35 |   
 36 | 
 37 |   
 38 |     
 39 |       io.vertx
 40 |       vertx-core
 41 |     
 42 |     
 43 |       io.grpc
 44 |       grpc-protobuf
 45 |       ${grpc.version}
 46 |       
 47 |         
 48 |           com.google.guava
 49 |           guava
 50 |         
 51 |         
 52 |           com.google.errorprone
 53 |           error_prone_annotations
 54 |         
 55 |         
 56 |           org.codehaus.mojo
 57 |           animal-sniffer-annotations
 58 |         
 59 |       
 60 |     
 61 |     
 62 |       io.grpc
 63 |       grpc-api
 64 |       ${grpc.version}
 65 |       
 66 |         
 67 |           com.google.errorprone
 68 |           error_prone_annotations
 69 |         
 70 |       
 71 |     
 72 |     
 73 |       com.google.guava
 74 |       guava
 75 |     
 76 | 
 77 |     
 78 |       io.grpc
 79 |       grpc-netty
 80 |       ${grpc.version}
 81 |       test
 82 |       
 83 |         
 84 |           com.google.guava
 85 |           guava
 86 |         
 87 |         
 88 |           com.google.errorprone
 89 |           error_prone_annotations
 90 |         
 91 |         
 92 |           org.codehaus.mojo
 93 |           animal-sniffer-annotations
 94 |         
 95 |         
 96 |           io.netty
 97 |           *
 98 |         
 99 |       
100 |     
101 |     
102 |       io.vertx
103 |       vertx-unit
104 |       test
105 |     
106 |   
107 | 
108 |   
109 |     
110 |       
111 |         kr.motd.maven
112 |         os-maven-plugin
113 |         1.4.1.Final
114 |       
115 |     
116 |     
117 |       
118 |         org.xolstice.maven.plugins
119 |         protobuf-maven-plugin
120 |         0.6.1
121 |         
122 |           
127 |           com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
128 |           grpc-java
129 |           io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
130 |         
131 |         
132 |           
133 |             test-compile
134 |             
135 |               test-compile
136 |               test-compile-custom
137 |             
138 |           
139 |         
140 |       
141 |     
142 |   
143 | 
144 |   
145 |     
146 |       java-11
147 |       
148 |         (1.8,)
149 |       
150 |       
151 |         
152 |           javax.annotation
153 |           javax.annotation-api
154 |           1.3.2
155 |         
156 |       
157 |     
158 |   
159 | 
160 | 
161 | 


--------------------------------------------------------------------------------
/vertx-grpc-server/pom.xml:
--------------------------------------------------------------------------------
  1 | 
  2 | 
 17 | 
 18 | 
 19 |   4.0.0
 20 | 
 21 |   
 22 |     io.vertx
 23 |     vertx-grpc-aggregator
 24 |     5.0.0-SNAPSHOT
 25 |     ../pom.xml
 26 |   
 27 | 
 28 |   vertx-grpc-server
 29 | 
 30 |   Vert.x gRPC Server
 31 | 
 32 |   
 33 |     false
 34 |     ${project.basedir}/src/main/resources/META-INF/MANIFEST.MF
 35 |   
 36 | 
 37 |   
 38 |     
 39 |       io.vertx
 40 |       vertx-grpc-common
 41 |     
 42 |     
 43 |       io.grpc
 44 |       grpc-stub
 45 |       ${grpc.version}
 46 |       
 47 |         
 48 |           com.google.errorprone
 49 |           error_prone_annotations
 50 |         
 51 |       
 52 |     
 53 | 
 54 |     
 55 |       io.vertx
 56 |       vertx-grpc-common
 57 |       ${project.version}
 58 |       test-jar
 59 |       test
 60 |     
 61 |     
 62 |       io.vertx
 63 |       vertx-unit
 64 |       test
 65 |     
 66 |     
 67 |     
 68 |       org.bouncycastle
 69 |       bcpkix-jdk15on
 70 |       1.65
 71 |       test
 72 |     
 73 |     
 74 |       io.grpc
 75 |       grpc-netty
 76 |       ${grpc.version}
 77 |       test
 78 |       
 79 |         
 80 |           com.google.guava
 81 |           guava
 82 |         
 83 |         
 84 |           com.google.errorprone
 85 |           error_prone_annotations
 86 |         
 87 |         
 88 |           org.codehaus.mojo
 89 |           animal-sniffer-annotations
 90 |         
 91 |         
 92 |           io.netty
 93 |           *
 94 |         
 95 |       
 96 |     
 97 |   
 98 | 
 99 |   
100 |     
101 |       
102 |         kr.motd.maven
103 |         os-maven-plugin
104 |         1.4.1.Final
105 |       
106 |     
107 |     
108 |       
109 |         org.xolstice.maven.plugins
110 |         protobuf-maven-plugin
111 |         0.6.1
112 |         
113 |           
118 |           com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
119 |           grpc-java
120 |           io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
121 |         
122 |         
123 |           
124 |             compile
125 |             
126 |               compile
127 |               compile-custom
128 |             
129 |             
130 |               ${project.basedir}/src/main/java
131 |               false
132 |             
133 |           
134 |           
135 |             test-compile
136 |             
137 |               test-compile
138 |               test-compile-custom
139 |             
140 |           
141 |         
142 |       
143 |     
144 |   
145 | 
146 |   
147 |     
148 |       java-11
149 |       
150 |         (1.8,)
151 |       
152 |       
153 |         
154 |           javax.annotation
155 |           javax.annotation-api
156 |           1.3.2
157 |         
158 |       
159 |     
160 |   
161 | 
162 | 
163 | 


--------------------------------------------------------------------------------
/vertx-grpc-context-storage/src/test/java/io/vertx/grpc/context/storage/ContextStorageTest.java:
--------------------------------------------------------------------------------
  1 | package io.vertx.grpc.context.storage;
  2 | 
  3 | import io.grpc.CallOptions;
  4 | import io.grpc.Channel;
  5 | import io.grpc.ClientCall;
  6 | import io.grpc.ClientInterceptor;
  7 | import io.grpc.ClientInterceptors;
  8 | import io.grpc.Context;
  9 | import io.grpc.ForwardingClientCall;
 10 | import io.grpc.ForwardingServerCallListener;
 11 | import io.grpc.ManagedChannel;
 12 | import io.grpc.ManagedChannelBuilder;
 13 | import io.grpc.Metadata;
 14 | import io.grpc.MethodDescriptor;
 15 | import io.grpc.ServerCall;
 16 | import io.grpc.ServerCallHandler;
 17 | import io.grpc.ServerInterceptor;
 18 | import io.grpc.ServerInterceptors;
 19 | import io.grpc.ServerServiceDefinition;
 20 | import io.grpc.examples.helloworld.GreeterGrpc;
 21 | import io.grpc.examples.helloworld.HelloReply;
 22 | import io.grpc.examples.helloworld.HelloRequest;
 23 | import io.grpc.stub.StreamObserver;
 24 | import io.vertx.core.Vertx;
 25 | import io.vertx.core.http.HttpServer;
 26 | import io.vertx.ext.unit.Async;
 27 | import io.vertx.ext.unit.TestContext;
 28 | import io.vertx.ext.unit.junit.Repeat;
 29 | import io.vertx.ext.unit.junit.RepeatRule;
 30 | import io.vertx.ext.unit.junit.VertxUnitRunner;
 31 | import io.vertx.grpc.server.GrpcServer;
 32 | import io.vertx.grpc.server.GrpcServiceBridge;
 33 | import org.junit.After;
 34 | import org.junit.Before;
 35 | import org.junit.Rule;
 36 | import org.junit.Test;
 37 | import org.junit.runner.RunWith;
 38 | 
 39 | import java.util.UUID;
 40 | 
 41 | import static io.grpc.Metadata.*;
 42 | 
 43 | @RunWith(VertxUnitRunner.class)
 44 | public class ContextStorageTest {
 45 | 
 46 |   @Rule
 47 |   public RepeatRule repeatRule = new RepeatRule();
 48 | 
 49 |   private Vertx vertx;
 50 |   private volatile HttpServer httpServer;
 51 |   private volatile ManagedChannel channel;
 52 | 
 53 |   @Before
 54 |   public void setUp() {
 55 |     vertx = Vertx.vertx();
 56 |   }
 57 | 
 58 |   @After
 59 |   public void tearDown(TestContext should) {
 60 |     if (channel != null) {
 61 |       channel.shutdown();
 62 |     }
 63 |     if (httpServer != null) {
 64 |       httpServer.close().onComplete(should.asyncAssertSuccess());
 65 |     }
 66 |     if (vertx != null) {
 67 |       vertx.close().onComplete(should.asyncAssertSuccess());
 68 |     }
 69 |   }
 70 | 
 71 |   @Test
 72 |   @Repeat(10)
 73 |   public void testGrpcContextPropagatedAcrossVertxAsyncCalls(TestContext should) {
 74 |     CallOptions.Key traceOptionsKey = CallOptions.Key.create("trace");
 75 |     Key traceMetadataKey = Key.of("trace", ASCII_STRING_MARSHALLER);
 76 |     Context.Key traceContextKey = Context.key("trace");
 77 | 
 78 |     GreeterGrpc.GreeterImplBase impl = new GreeterGrpc.GreeterImplBase() {
 79 |       @Override
 80 |       public void sayHello(HelloRequest request, StreamObserver responseObserver) {
 81 |         vertx.executeBlocking(prom -> {
 82 |           prom.complete("Hello " + request.getName() + ", trace: " + traceContextKey.get());
 83 |         }).onSuccess(greeting -> {
 84 |           responseObserver.onNext(HelloReply.newBuilder().setMessage(greeting).build());
 85 |           responseObserver.onCompleted();
 86 |         }).onFailure(should::fail);
 87 |       }
 88 |     };
 89 | 
 90 |     ServerServiceDefinition def = ServerInterceptors.intercept(impl, new ServerInterceptor() {
 91 |       @Override
 92 |       public  ServerCall.Listener interceptCall(ServerCall call, Metadata headers, ServerCallHandler next) {
 93 |         String traceId = headers.get(traceMetadataKey);
 94 |         should.assertNotNull(traceId);
 95 |         Context context = Context.current().withValue(traceContextKey, traceId);
 96 |         Context previous = context.attach();
 97 |         return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) {
 98 |           @Override
 99 |           public void onComplete() {
100 |             context.detach(previous);
101 |             super.onComplete();
102 |           }
103 |         };
104 |       }
105 |     });
106 | 
107 |     GrpcServer server = GrpcServer.server(vertx);
108 |     GrpcServiceBridge serverStub = GrpcServiceBridge.bridge(def);
109 |     serverStub.bind(server);
110 | 
111 |     Async servertStart = should.async();
112 |     vertx.createHttpServer()
113 |       .requestHandler(server)
114 |       .listen(0).onComplete(should.asyncAssertSuccess(httpServer -> {
115 |         this.httpServer = httpServer;
116 |         servertStart.complete();
117 |       }));
118 |     servertStart.await();
119 | 
120 |     channel = ManagedChannelBuilder.forAddress("localhost", httpServer.actualPort())
121 |       .usePlaintext()
122 |       .build();
123 | 
124 |     GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(ClientInterceptors.intercept(channel, new ClientInterceptor() {
125 |         @Override
126 |         public  ClientCall interceptCall(MethodDescriptor method, CallOptions callOptions, Channel next) {
127 |           return new ForwardingClientCall.SimpleForwardingClientCall(next.newCall(method, callOptions)) {
128 |             @Override
129 |             public void start(Listener responseListener, Metadata headers) {
130 |               Metadata traceHeaders = new Metadata();
131 |               traceHeaders.put(traceMetadataKey, callOptions.getOption(traceOptionsKey));
132 |               headers.merge(traceHeaders);
133 |               super.start(responseListener, headers);
134 |             }
135 |           };
136 |         }
137 |       }))
138 |       .withCompression("identity");
139 | 
140 |     String trace = UUID.randomUUID().toString();
141 |     HelloRequest request = HelloRequest.newBuilder().setName("Julien").build();
142 |     HelloReply res = stub.withOption(traceOptionsKey, trace).sayHello(request);
143 | 
144 |     should.assertEquals("Hello Julien, trace: " + trace, res.getMessage());
145 |   }
146 | }
147 | 


--------------------------------------------------------------------------------
/vertx-grpc-client/src/main/java/io/vertx/grpc/client/VertxClientCall.java:
--------------------------------------------------------------------------------
  1 | package io.vertx.grpc.client;
  2 | 
  3 | import io.grpc.ClientCall;
  4 | import io.grpc.Compressor;
  5 | import io.grpc.Decompressor;
  6 | import io.grpc.DecompressorRegistry;
  7 | import io.grpc.Metadata;
  8 | import io.grpc.MethodDescriptor;
  9 | import io.grpc.Status;
 10 | import io.vertx.core.Future;
 11 | import io.vertx.core.http.StreamResetException;
 12 | import io.vertx.core.net.SocketAddress;
 13 | import io.vertx.grpc.common.GrpcError;
 14 | import io.vertx.grpc.common.impl.BridgeMessageDecoder;
 15 | import io.vertx.grpc.common.impl.BridgeMessageEncoder;
 16 | import io.vertx.grpc.common.impl.ReadStreamAdapter;
 17 | import io.vertx.grpc.common.impl.Utils;
 18 | import io.vertx.grpc.common.impl.WriteStreamAdapter;
 19 | 
 20 | import javax.annotation.Nullable;
 21 | import java.util.concurrent.Executor;
 22 | 
 23 | class VertxClientCall extends ClientCall {
 24 | 
 25 |   private final GrpcClient client;
 26 |   private final SocketAddress server;
 27 |   private final Executor exec;
 28 |   private final MethodDescriptor methodDescriptor;
 29 |   private final String encoding;
 30 |   private final Compressor compressor;
 31 |   private Future> fut;
 32 |   private Listener listener;
 33 |   private WriteStreamAdapter writeAdapter;
 34 |   private ReadStreamAdapter readAdapter;
 35 |   private GrpcClientRequest request;
 36 |   private GrpcClientResponse grpcResponse;
 37 | 
 38 |   VertxClientCall(GrpcClient client, SocketAddress server, Executor exec, MethodDescriptor methodDescriptor, String encoding, Compressor compressor) {
 39 |     this.client = client;
 40 |     this.server = server;
 41 |     this.exec = exec;
 42 |     this.methodDescriptor = methodDescriptor;
 43 |     this.encoding = encoding;
 44 |     this.compressor = compressor;
 45 |     writeAdapter = new WriteStreamAdapter() {
 46 |       @Override
 47 |       protected void handleReady() {
 48 |         listener.onReady();
 49 |       }
 50 |     };
 51 |     readAdapter = new ReadStreamAdapter() {
 52 |       @Override
 53 |       protected void handleMessage(ResponseT msg) {
 54 |         if (exec == null) {
 55 |           listener.onMessage(msg);
 56 |         } else {
 57 |           exec.execute(() -> listener.onMessage(msg));
 58 |         }
 59 |       }
 60 |     };
 61 |   }
 62 | 
 63 |   @Override
 64 |   public boolean isReady() {
 65 |     return writeAdapter.isReady();
 66 |   }
 67 | 
 68 |   @Override
 69 |   public void start(Listener responseListener, Metadata headers) {
 70 |     listener = responseListener;
 71 |     fut = client.request(server, methodDescriptor);
 72 |     fut.onComplete(ar1 -> {
 73 |       if (ar1.succeeded()) {
 74 |         request = ar1.result();
 75 |         Utils.writeMetadata(headers, request.headers());
 76 |         if (encoding != null) {
 77 |           request.encoding(encoding);
 78 |         }
 79 |         Future> responseFuture = request.response();
 80 |         responseFuture.onComplete(ar2 -> {
 81 |           if (ar2.succeeded()) {
 82 | 
 83 |             grpcResponse = ar2.result();
 84 | 
 85 |             String respEncoding = grpcResponse.encoding();
 86 |             Decompressor decompressor = DecompressorRegistry.getDefaultInstance().lookupDecompressor(respEncoding);
 87 | 
 88 |             BridgeMessageDecoder decoder = new BridgeMessageDecoder<>(methodDescriptor.getResponseMarshaller(), decompressor);
 89 | 
 90 |             Metadata responseHeaders = Utils.readMetadata(grpcResponse.headers());
 91 |             if (exec == null) {
 92 |               responseListener.onHeaders(responseHeaders);
 93 |             } else {
 94 |               exec.execute(() -> {
 95 |                 responseListener.onHeaders(responseHeaders);
 96 |               });
 97 |             }
 98 |             readAdapter.init(grpcResponse, decoder);
 99 |             grpcResponse.end().onComplete(ar -> {
100 |               Status status;
101 |               Metadata trailers;
102 |               if (grpcResponse.status() != null) {
103 |                 status = Status.fromCodeValue(grpcResponse.status().code);
104 |                 trailers = Utils.readMetadata(grpcResponse.trailers());
105 |               } else {
106 |                 status = Status.fromThrowable(ar.cause());
107 |                 trailers = new Metadata();
108 |               }
109 |               doClose(status, trailers);
110 |             });
111 |           } else {
112 |             Throwable err = ar2.cause();
113 |             if (err instanceof StreamResetException) {
114 |               StreamResetException reset = (StreamResetException) err;
115 |               GrpcError grpcError = GrpcError.mapHttp2ErrorCode(reset.getCode());
116 |               if (grpcError != null) {
117 |                 doClose(Status.fromCodeValue(grpcError.status.code), new Metadata());
118 |               } else {
119 |                 doClose(Status.UNKNOWN, new Metadata());
120 |               }
121 |             } else {
122 |               doClose(Status.fromThrowable(err), new Metadata());
123 |             }
124 |           }
125 |         });
126 |         writeAdapter.init(request, new BridgeMessageEncoder<>(methodDescriptor.getRequestMarshaller(), compressor));
127 |       } else {
128 |         doClose(Status.UNAVAILABLE, new Metadata());
129 |       }
130 |     });
131 |   }
132 | 
133 |   private void doClose(Status status, Metadata trailers) {
134 |     Runnable cmd = () -> {
135 |       listener.onClose(status, trailers);
136 |     };
137 |     if (exec == null) {
138 |       cmd.run();
139 |     } else {
140 |       exec.execute(cmd);
141 |     }
142 |   }
143 | 
144 |   @Override
145 |   public void request(int numMessages) {
146 |     readAdapter.request(numMessages);
147 |   }
148 | 
149 |   @Override
150 |   public void cancel(@Nullable String message, @Nullable Throwable cause) {
151 |     fut.onSuccess(req -> {
152 |       req.cancel();
153 |     });
154 |   }
155 | 
156 |   @Override
157 |   public void halfClose() {
158 |     fut.onSuccess(req -> {
159 |       req.end();
160 |     });
161 |   }
162 | 
163 |   @Override
164 |   public void sendMessage(RequestT message) {
165 |     fut.onSuccess(v -> {
166 |       writeAdapter.write(message);
167 |     });
168 |   }
169 | }
170 | 


--------------------------------------------------------------------------------
/vertx-grpc-client/pom.xml:
--------------------------------------------------------------------------------
  1 | 
  2 | 
 17 | 
 18 | 
 19 |   4.0.0
 20 | 
 21 |   
 22 |     io.vertx
 23 |     vertx-grpc-aggregator
 24 |     5.0.0-SNAPSHOT
 25 |     ../pom.xml
 26 |   
 27 | 
 28 |   vertx-grpc-client
 29 | 
 30 |   Vert.x gRPC Client
 31 | 
 32 |   
 33 |     false
 34 |     ${project.basedir}/src/main/resources/META-INF/MANIFEST.MF
 35 |   
 36 | 
 37 |   
 38 |     
 39 |       io.vertx
 40 |       vertx-grpc-common
 41 |     
 42 |     
 43 |       io.grpc
 44 |       grpc-stub
 45 |       ${grpc.version}
 46 |       
 47 |         
 48 |           com.google.errorprone
 49 |           error_prone_annotations
 50 |         
 51 |       
 52 |     
 53 |     
 54 |       io.grpc
 55 |       grpc-api
 56 |       ${grpc.version}
 57 |       
 58 |         
 59 |           com.google.errorprone
 60 |           error_prone_annotations
 61 |         
 62 |         
 63 |           org.codehaus.mojo
 64 |           animal-sniffer-annotations
 65 |         
 66 |       
 67 |     
 68 | 
 69 |     
 70 |       io.vertx
 71 |       vertx-grpc-common
 72 |       ${project.version}
 73 |       test-jar
 74 |       test
 75 |     
 76 |     
 77 |       io.vertx
 78 |       vertx-unit
 79 |       test
 80 |     
 81 |     
 82 |     
 83 |       org.bouncycastle
 84 |       bcpkix-jdk15on
 85 |       1.65
 86 |       test
 87 |     
 88 |     
 89 |       io.grpc
 90 |       grpc-netty
 91 |       ${grpc.version}
 92 |       test
 93 |       
 94 |         
 95 |           com.google.guava
 96 |           guava
 97 |         
 98 |         
 99 |           com.google.errorprone
100 |           error_prone_annotations
101 |         
102 |         
103 |           org.codehaus.mojo
104 |           animal-sniffer-annotations
105 |         
106 |         
107 |           io.netty
108 |           *
109 |         
110 |       
111 |     
112 |   
113 | 
114 |   
115 |     
116 |       
117 |         kr.motd.maven
118 |         os-maven-plugin
119 |         1.4.1.Final
120 |       
121 |     
122 |     
123 |       
124 |         org.xolstice.maven.plugins
125 |         protobuf-maven-plugin
126 |         0.6.1
127 |         
128 |           
133 |           com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
134 |           grpc-java
135 |           io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
136 |         
137 |         
138 |           
139 |             compile
140 |             
141 |               compile
142 |               compile-custom
143 |             
144 |             
145 |               ${project.basedir}/src/main/java
146 |               false
147 |             
148 |           
149 |           
150 |             test-compile
151 |             
152 |               test-compile
153 |               test-compile-custom
154 |             
155 |           
156 |         
157 |       
158 |     
159 |   
160 | 
161 |   
162 |     
163 |       java-11
164 |       
165 |         (1.8,)
166 |       
167 |       
168 |         
169 |           javax.annotation
170 |           javax.annotation-api
171 |           1.3.2
172 |         
173 |       
174 |     
175 |   
176 | 
177 | 
178 | 


--------------------------------------------------------------------------------
/vertx-grpc-it/src/test/proto/messages.proto:
--------------------------------------------------------------------------------
  1 | // Copyright 2015, Google Inc.
  2 | // All rights reserved.
  3 | //
  4 | // Redistribution and use in source and binary forms, with or without
  5 | // modification, are permitted provided that the following conditions are
  6 | // met:
  7 | //
  8 | //     * Redistributions of source code must retain the above copyright
  9 | // notice, this list of conditions and the following disclaimer.
 10 | //     * Redistributions in binary form must reproduce the above
 11 | // copyright notice, this list of conditions and the following disclaimer
 12 | // in the documentation and/or other materials provided with the
 13 | // distribution.
 14 | //     * Neither the name of Google Inc. nor the names of its
 15 | // contributors may be used to endorse or promote products derived from
 16 | // this software without specific prior written permission.
 17 | //
 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 29 | 
 30 | // Message definitions to be used by integration test service definitions.
 31 | 
 32 | syntax = "proto3";
 33 | 
 34 | package grpc.testing;
 35 | 
 36 | option java_package = "io.grpc.testing.integration";
 37 | 
 38 | // The type of payload that should be returned.
 39 | enum PayloadType {
 40 |   // Compressable text format.
 41 |   COMPRESSABLE = 0;
 42 | 
 43 |   // Uncompressable binary format.
 44 |   UNCOMPRESSABLE = 1;
 45 | 
 46 |   // Randomly chosen from all other formats defined in this enum.
 47 |   RANDOM = 2;
 48 | }
 49 | 
 50 | // Compression algorithms
 51 | enum CompressionType {
 52 |   // No compression
 53 |   NONE = 0;
 54 |   GZIP = 1;
 55 |   DEFLATE = 2;
 56 | }
 57 | 
 58 | // A block of data, to simply increase gRPC message size.
 59 | message Payload {
 60 |   // The type of data in body.
 61 |   PayloadType type = 1;
 62 |   // Primary contents of payload.
 63 |   bytes body = 2;
 64 | }
 65 | 
 66 | // A protobuf representation for grpc status. This is used by test
 67 | // clients to specify a status that the server should attempt to return.
 68 | message EchoStatus {
 69 |   int32 code = 1;
 70 |   string message = 2;
 71 | }
 72 | 
 73 | // Unary request.
 74 | message SimpleRequest {
 75 |   // Desired payload type in the response from the server.
 76 |   // If response_type is RANDOM, server randomly chooses one from other formats.
 77 |   PayloadType response_type = 1;
 78 | 
 79 |   // Desired payload size in the response from the server.
 80 |   // If response_type is COMPRESSABLE, this denotes the size before compression.
 81 |   int32 response_size = 2;
 82 | 
 83 |   // Optional input payload sent along with the request.
 84 |   Payload payload = 3;
 85 | 
 86 |   // Whether SimpleResponse should include username.
 87 |   bool fill_username = 4;
 88 | 
 89 |   // Whether SimpleResponse should include OAuth scope.
 90 |   bool fill_oauth_scope = 5;
 91 | 
 92 |   // Compression algorithm to be used by the server for the response (stream)
 93 |   CompressionType response_compression = 6;
 94 | 
 95 |   // Whether server should return a given status
 96 |   EchoStatus response_status = 7;
 97 | }
 98 | 
 99 | // Unary response, as configured by the request.
100 | message SimpleResponse {
101 |   // Payload to increase message size.
102 |   Payload payload = 1;
103 |   // The user the request came from, for verifying authentication was
104 |   // successful when the client expected it.
105 |   string username = 2;
106 |   // OAuth scope.
107 |   string oauth_scope = 3;
108 | }
109 | 
110 | message SimpleContext {
111 |   string value = 1;
112 | }
113 | 
114 | // Client-streaming request.
115 | message StreamingInputCallRequest {
116 |   // Optional input payload sent along with the request.
117 |   Payload payload = 1;
118 | 
119 |   // Not expecting any payload from the response.
120 | }
121 | 
122 | // Client-streaming response.
123 | message StreamingInputCallResponse {
124 |   // Aggregated size of payloads received from the client.
125 |   int32 aggregated_payload_size = 1;
126 | }
127 | 
128 | // Configuration for a particular response.
129 | message ResponseParameters {
130 |   // Desired payload sizes in responses from the server.
131 |   // If response_type is COMPRESSABLE, this denotes the size before compression.
132 |   int32 size = 1;
133 | 
134 |   // Desired interval between consecutive responses in the response stream in
135 |   // microseconds.
136 |   int32 interval_us = 2;
137 | }
138 | 
139 | // Server-streaming request.
140 | message StreamingOutputCallRequest {
141 |   // Desired payload type in the response from the server.
142 |   // If response_type is RANDOM, the payload from each response in the stream
143 |   // might be of different types. This is to simulate a mixed type of payload
144 |   // stream.
145 |   PayloadType response_type = 1;
146 | 
147 |   // Configuration for each expected response message.
148 |   repeated ResponseParameters response_parameters = 2;
149 | 
150 |   // Optional input payload sent along with the request.
151 |   Payload payload = 3;
152 | 
153 |   // Compression algorithm to be used by the server for the response (stream)
154 |   CompressionType response_compression = 6;
155 | 
156 |   // Whether server should return a given status
157 |   EchoStatus response_status = 7;
158 | }
159 | 
160 | // Server-streaming response, as configured by the request and parameters.
161 | message StreamingOutputCallResponse {
162 |   // Payload to increase response size.
163 |   Payload payload = 1;
164 | }
165 | 
166 | // For reconnect interop test only.
167 | // Client tells server what reconnection parameters it used.
168 | message ReconnectParams {
169 |   int32 max_reconnect_backoff_ms = 1;
170 | }
171 | 
172 | // For reconnect interop test only.
173 | // Server tells client whether its reconnects are following the spec and the
174 | // reconnect backoffs it saw.
175 | message ReconnectInfo {
176 |   bool passed = 1;
177 |   repeated int32 backoff_ms = 2;
178 | }
179 | 


--------------------------------------------------------------------------------