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 |
--------------------------------------------------------------------------------