grpc 1.6.7-universal-darwin → 1.7.0.pre1-universal-darwin
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grpc might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/src/ruby/ext/grpc/rb_call_credentials.c +6 -2
- data/src/ruby/ext/grpc/rb_grpc.c +1 -1
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +30 -20
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +50 -35
- data/src/ruby/lib/grpc.rb +1 -0
- data/src/ruby/lib/grpc/2.0/grpc_c.bundle +0 -0
- data/src/ruby/lib/grpc/2.1/grpc_c.bundle +0 -0
- data/src/ruby/lib/grpc/2.2/grpc_c.bundle +0 -0
- data/src/ruby/lib/grpc/2.3/grpc_c.bundle +0 -0
- data/src/ruby/lib/grpc/2.4/grpc_c.bundle +0 -0
- data/src/ruby/lib/grpc/generic/active_call.rb +34 -9
- data/src/ruby/lib/grpc/generic/bidi_call.rb +19 -10
- data/src/ruby/lib/grpc/generic/client_stub.rb +95 -38
- data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
- data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
- data/src/ruby/lib/grpc/generic/rpc_desc.rb +66 -20
- data/src/ruby/lib/grpc/generic/rpc_server.rb +15 -3
- data/src/ruby/lib/grpc/google_rpc_status_utils.rb +1 -2
- data/src/ruby/lib/grpc/version.rb +1 -1
- data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +1 -0
- data/src/ruby/spec/channel_connection_spec.rb +1 -34
- data/src/ruby/spec/client_server_spec.rb +188 -82
- data/src/ruby/spec/generic/active_call_spec.rb +65 -11
- data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
- data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
- data/src/ruby/spec/generic/rpc_desc_spec.rb +38 -0
- data/src/ruby/spec/generic/rpc_server_spec.rb +1 -34
- data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
- data/src/ruby/spec/spec_helper.rb +4 -0
- data/src/ruby/spec/support/helpers.rb +73 -0
- data/src/ruby/spec/support/services.rb +147 -0
- metadata +24 -12
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright 2017 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
|
+
|
15
|
+
# GRPC contains the General RPC module.
|
16
|
+
module GRPC
|
17
|
+
##
|
18
|
+
# Represents a registry of added interceptors available for enumeration.
|
19
|
+
# The registry can be used for both server and client interceptors.
|
20
|
+
# This class is internal to gRPC and not meant for public usage.
|
21
|
+
#
|
22
|
+
class InterceptorRegistry
|
23
|
+
##
|
24
|
+
# An error raised when an interceptor is attempted to be added
|
25
|
+
# that does not extend GRPC::Interceptor
|
26
|
+
#
|
27
|
+
class DescendantError < StandardError; end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Initialize the registry with an empty interceptor list
|
31
|
+
# This is an EXPERIMENTAL API.
|
32
|
+
#
|
33
|
+
def initialize(interceptors = [])
|
34
|
+
@interceptors = []
|
35
|
+
interceptors.each do |i|
|
36
|
+
base = GRPC::Interceptor
|
37
|
+
unless i.class.ancestors.include?(base)
|
38
|
+
fail DescendantError, "Interceptors must descend from #{base}"
|
39
|
+
end
|
40
|
+
@interceptors << i
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Builds an interception context from this registry
|
46
|
+
#
|
47
|
+
# @return [InterceptionContext]
|
48
|
+
#
|
49
|
+
def build_context
|
50
|
+
InterceptionContext.new(@interceptors)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# Copyright 2017 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
|
+
require_relative 'interceptor_registry'
|
15
|
+
|
16
|
+
# GRPC contains the General RPC module.
|
17
|
+
module GRPC
|
18
|
+
##
|
19
|
+
# Base class for interception in GRPC
|
20
|
+
#
|
21
|
+
class Interceptor
|
22
|
+
##
|
23
|
+
# @param [Hash] options A hash of options that will be used
|
24
|
+
# by the interceptor. This is an EXPERIMENTAL API.
|
25
|
+
#
|
26
|
+
def initialize(options = {})
|
27
|
+
@options = options || {}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# ClientInterceptor allows for wrapping outbound gRPC client stub requests.
|
33
|
+
# This is an EXPERIMENTAL API.
|
34
|
+
#
|
35
|
+
class ClientInterceptor < Interceptor
|
36
|
+
##
|
37
|
+
# Intercept a unary request response call
|
38
|
+
#
|
39
|
+
# @param [Object] request
|
40
|
+
# @param [GRPC::ActiveCall] call
|
41
|
+
# @param [Method] method
|
42
|
+
# @param [Hash] metadata
|
43
|
+
#
|
44
|
+
def request_response(request:, call:, method:, metadata:)
|
45
|
+
GRPC.logger.debug "Intercepting request response method #{method}" \
|
46
|
+
" for request #{request} with call #{call} and metadata: #{metadata}"
|
47
|
+
yield
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Intercept a client streaming call
|
52
|
+
#
|
53
|
+
# @param [Enumerable] requests
|
54
|
+
# @param [GRPC::ActiveCall] call
|
55
|
+
# @param [Method] method
|
56
|
+
# @param [Hash] metadata
|
57
|
+
#
|
58
|
+
def client_streamer(requests:, call:, method:, metadata:)
|
59
|
+
GRPC.logger.debug "Intercepting client streamer method #{method}" \
|
60
|
+
" for requests #{requests} with call #{call} and metadata: #{metadata}"
|
61
|
+
yield
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Intercept a server streaming call
|
66
|
+
#
|
67
|
+
# @param [Object] request
|
68
|
+
# @param [GRPC::ActiveCall] call
|
69
|
+
# @param [Method] method
|
70
|
+
# @param [Hash] metadata
|
71
|
+
#
|
72
|
+
def server_streamer(request:, call:, method:, metadata:)
|
73
|
+
GRPC.logger.debug "Intercepting server streamer method #{method}" \
|
74
|
+
" for request #{request} with call #{call} and metadata: #{metadata}"
|
75
|
+
yield
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Intercept a BiDi streaming call
|
80
|
+
#
|
81
|
+
# @param [Enumerable] requests
|
82
|
+
# @param [GRPC::ActiveCall] call
|
83
|
+
# @param [Method] method
|
84
|
+
# @param [Hash] metadata
|
85
|
+
#
|
86
|
+
def bidi_streamer(requests:, call:, method:, metadata:)
|
87
|
+
GRPC.logger.debug "Intercepting bidi streamer method #{method}" \
|
88
|
+
" for requests #{requests} with call #{call} and metadata: #{metadata}"
|
89
|
+
yield
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# ServerInterceptor allows for wrapping gRPC server execution handling.
|
95
|
+
# This is an EXPERIMENTAL API.
|
96
|
+
#
|
97
|
+
class ServerInterceptor < Interceptor
|
98
|
+
##
|
99
|
+
# Intercept a unary request response call.
|
100
|
+
#
|
101
|
+
# @param [Object] request
|
102
|
+
# @param [GRPC::ActiveCall::SingleReqView] call
|
103
|
+
# @param [Method] method
|
104
|
+
#
|
105
|
+
def request_response(request:, call:, method:)
|
106
|
+
GRPC.logger.debug "Intercepting request response method #{method}" \
|
107
|
+
" for request #{request} with call #{call}"
|
108
|
+
yield
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Intercept a client streaming call
|
113
|
+
#
|
114
|
+
# @param [GRPC::ActiveCall::MultiReqView] call
|
115
|
+
# @param [Method] method
|
116
|
+
#
|
117
|
+
def client_streamer(call:, method:)
|
118
|
+
GRPC.logger.debug "Intercepting client streamer method #{method}" \
|
119
|
+
" with call #{call}"
|
120
|
+
yield
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Intercept a server streaming call
|
125
|
+
#
|
126
|
+
# @param [Object] request
|
127
|
+
# @param [GRPC::ActiveCall::SingleReqView] call
|
128
|
+
# @param [Method] method
|
129
|
+
#
|
130
|
+
def server_streamer(request:, call:, method:)
|
131
|
+
GRPC.logger.debug "Intercepting server streamer method #{method}" \
|
132
|
+
" for request #{request} with call #{call}"
|
133
|
+
yield
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Intercept a BiDi streaming call
|
138
|
+
#
|
139
|
+
# @param [Enumerable<Object>] requests
|
140
|
+
# @param [GRPC::ActiveCall::MultiReqView] call
|
141
|
+
# @param [Method] method
|
142
|
+
#
|
143
|
+
def bidi_streamer(requests:, call:, method:)
|
144
|
+
GRPC.logger.debug "Intercepting bidi streamer method #{method}" \
|
145
|
+
" for requests #{requests} with call #{call}"
|
146
|
+
yield
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# Represents the context in which an interceptor runs. Used to provide an
|
152
|
+
# injectable mechanism for handling interception. This is an EXPERIMENTAL API.
|
153
|
+
#
|
154
|
+
class InterceptionContext
|
155
|
+
##
|
156
|
+
# @param [Array<GRPC::Interceptor>]
|
157
|
+
#
|
158
|
+
def initialize(interceptors = [])
|
159
|
+
@interceptors = interceptors.dup
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# Intercept the call and fire out to interceptors in a FIFO execution.
|
164
|
+
# This is an EXPERIMENTAL API.
|
165
|
+
#
|
166
|
+
# @param [Symbol] type The request type
|
167
|
+
# @param [Hash] args The arguments for the call
|
168
|
+
#
|
169
|
+
def intercept!(type, args = {})
|
170
|
+
return yield if @interceptors.none?
|
171
|
+
|
172
|
+
i = @interceptors.pop
|
173
|
+
return yield unless i
|
174
|
+
|
175
|
+
i.send(type, args) do
|
176
|
+
if @interceptors.any?
|
177
|
+
intercept!(type, args) do
|
178
|
+
yield
|
179
|
+
end
|
180
|
+
else
|
181
|
+
yield
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -47,43 +47,85 @@ module GRPC
|
|
47
47
|
proc { |o| unmarshal_class.method(unmarshal_method).call(o) }
|
48
48
|
end
|
49
49
|
|
50
|
-
def handle_request_response(active_call, mth)
|
50
|
+
def handle_request_response(active_call, mth, inter_ctx)
|
51
51
|
req = active_call.read_unary_request
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
call = active_call.single_req_view
|
53
|
+
|
54
|
+
inter_ctx.intercept!(
|
55
|
+
:request_response,
|
56
|
+
method: mth,
|
57
|
+
call: call,
|
58
|
+
request: req
|
59
|
+
) do
|
60
|
+
resp = mth.call(req, call)
|
61
|
+
active_call.server_unary_response(
|
62
|
+
resp,
|
63
|
+
trailing_metadata: active_call.output_metadata
|
64
|
+
)
|
65
|
+
end
|
55
66
|
end
|
56
67
|
|
57
|
-
def handle_client_streamer(active_call,
|
58
|
-
|
59
|
-
|
60
|
-
|
68
|
+
def handle_client_streamer(active_call, mth, inter_ctx)
|
69
|
+
call = active_call.multi_req_view
|
70
|
+
|
71
|
+
inter_ctx.intercept!(
|
72
|
+
:client_streamer,
|
73
|
+
method: mth,
|
74
|
+
call: call
|
75
|
+
) do
|
76
|
+
resp = mth.call(call)
|
77
|
+
active_call.server_unary_response(
|
78
|
+
resp,
|
79
|
+
trailing_metadata: active_call.output_metadata
|
80
|
+
)
|
81
|
+
end
|
61
82
|
end
|
62
83
|
|
63
|
-
def handle_server_streamer(active_call, mth)
|
84
|
+
def handle_server_streamer(active_call, mth, inter_ctx)
|
64
85
|
req = active_call.read_unary_request
|
65
|
-
|
66
|
-
|
67
|
-
|
86
|
+
call = active_call.single_req_view
|
87
|
+
|
88
|
+
inter_ctx.intercept!(
|
89
|
+
:server_streamer,
|
90
|
+
method: mth,
|
91
|
+
call: call,
|
92
|
+
request: req
|
93
|
+
) do
|
94
|
+
replies = mth.call(req, call)
|
95
|
+
replies.each { |r| active_call.remote_send(r) }
|
96
|
+
send_status(active_call, OK, 'OK', active_call.output_metadata)
|
97
|
+
end
|
68
98
|
end
|
69
99
|
|
70
|
-
|
71
|
-
|
100
|
+
##
|
101
|
+
# @param [GRPC::ActiveCall] active_call
|
102
|
+
# @param [Method] mth
|
103
|
+
# @param [Array<GRPC::InterceptionContext>] inter_ctx
|
104
|
+
#
|
105
|
+
def handle_bidi_streamer(active_call, mth, inter_ctx)
|
106
|
+
active_call.run_server_bidi(mth, inter_ctx)
|
72
107
|
send_status(active_call, OK, 'OK', active_call.output_metadata)
|
73
108
|
end
|
74
109
|
|
75
|
-
|
110
|
+
##
|
111
|
+
# @param [GRPC::ActiveCall] active_call The current active call object
|
112
|
+
# for the request
|
113
|
+
# @param [Method] mth The current RPC method being called
|
114
|
+
# @param [GRPC::InterceptionContext] inter_ctx The interception context
|
115
|
+
# being executed
|
116
|
+
#
|
117
|
+
def run_server_method(active_call, mth, inter_ctx = InterceptionContext.new)
|
76
118
|
# While a server method is running, it might be cancelled, its deadline
|
77
119
|
# might be reached, the handler could throw an unknown error, or a
|
78
120
|
# well-behaved handler could throw a StatusError.
|
79
121
|
if request_response?
|
80
|
-
handle_request_response(active_call, mth)
|
122
|
+
handle_request_response(active_call, mth, inter_ctx)
|
81
123
|
elsif client_streamer?
|
82
|
-
handle_client_streamer(active_call, mth)
|
124
|
+
handle_client_streamer(active_call, mth, inter_ctx)
|
83
125
|
elsif server_streamer?
|
84
|
-
handle_server_streamer(active_call, mth)
|
126
|
+
handle_server_streamer(active_call, mth, inter_ctx)
|
85
127
|
else # is a bidi_stream
|
86
|
-
handle_bidi_streamer(active_call, mth)
|
128
|
+
handle_bidi_streamer(active_call, mth, inter_ctx)
|
87
129
|
end
|
88
130
|
rescue BadStatus => e
|
89
131
|
# this is raised by handlers that want GRPC to send an application error
|
@@ -99,9 +141,13 @@ module GRPC
|
|
99
141
|
# event. Send a status of deadline exceeded
|
100
142
|
GRPC.logger.warn("late call: #{active_call}")
|
101
143
|
send_status(active_call, DEADLINE_EXCEEDED, 'late')
|
102
|
-
rescue StandardError => e
|
144
|
+
rescue StandardError, NotImplementedError => e
|
103
145
|
# This will usuaally be an unhandled error in the handling code.
|
104
146
|
# Send back a UNKNOWN status to the client
|
147
|
+
#
|
148
|
+
# Note: this intentionally does not map NotImplementedError to
|
149
|
+
# UNIMPLEMENTED because NotImplementedError is intended for low-level
|
150
|
+
# OS interaction (e.g. syscalls) not supported by the current OS.
|
105
151
|
GRPC.logger.warn("failed handler: #{active_call}; sending status:UNKNOWN")
|
106
152
|
GRPC.logger.warn(e)
|
107
153
|
send_status(active_call, UNKNOWN, "#{e.class}: #{e.message}")
|
@@ -196,11 +196,18 @@ module GRPC
|
|
196
196
|
#
|
197
197
|
# * server_args:
|
198
198
|
# A server arguments hash to be passed down to the underlying core server
|
199
|
+
#
|
200
|
+
# * interceptors:
|
201
|
+
# Am array of GRPC::ServerInterceptor objects that will be used for
|
202
|
+
# intercepting server handlers to provide extra functionality.
|
203
|
+
# Interceptors are an EXPERIMENTAL API.
|
204
|
+
#
|
199
205
|
def initialize(pool_size:DEFAULT_POOL_SIZE,
|
200
206
|
max_waiting_requests:DEFAULT_MAX_WAITING_REQUESTS,
|
201
207
|
poll_period:DEFAULT_POLL_PERIOD,
|
202
208
|
connect_md_proc:nil,
|
203
|
-
server_args:{}
|
209
|
+
server_args:{},
|
210
|
+
interceptors:[])
|
204
211
|
@connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc)
|
205
212
|
@max_waiting_requests = max_waiting_requests
|
206
213
|
@poll_period = poll_period
|
@@ -212,6 +219,7 @@ module GRPC
|
|
212
219
|
# :stopped. State transitions can only proceed in that order.
|
213
220
|
@running_state = :not_started
|
214
221
|
@server = Core::Server.new(server_args)
|
222
|
+
@interceptors = InterceptorRegistry.new(interceptors)
|
215
223
|
end
|
216
224
|
|
217
225
|
# stops a running server
|
@@ -374,7 +382,11 @@ module GRPC
|
|
374
382
|
@pool.schedule(active_call) do |ac|
|
375
383
|
c, mth = ac
|
376
384
|
begin
|
377
|
-
rpc_descs[mth].run_server_method(
|
385
|
+
rpc_descs[mth].run_server_method(
|
386
|
+
c,
|
387
|
+
rpc_handlers[mth],
|
388
|
+
@interceptors.build_context
|
389
|
+
)
|
378
390
|
rescue StandardError
|
379
391
|
c.send_status(GRPC::Core::StatusCodes::INTERNAL,
|
380
392
|
'Server handler failed')
|
@@ -382,7 +394,7 @@ module GRPC
|
|
382
394
|
end
|
383
395
|
end
|
384
396
|
rescue Core::CallError, RuntimeError => e
|
385
|
-
# these might happen for various
|
397
|
+
# these might happen for various reasons. The correct behavior of
|
386
398
|
# the server is to log them and continue, if it's not shutting down.
|
387
399
|
if running_state == :running
|
388
400
|
GRPC.logger.warn("server call failed: #{e}")
|
@@ -29,8 +29,7 @@ module GRPC
|
|
29
29
|
fail ArgumentError, 'bad type' unless status.is_a? Struct::Status
|
30
30
|
grpc_status_details_bin_trailer = 'grpc-status-details-bin'
|
31
31
|
return nil if status.metadata[grpc_status_details_bin_trailer].nil?
|
32
|
-
Google::Rpc::Status.decode(
|
33
|
-
status.metadata[grpc_status_details_bin_trailer])
|
32
|
+
Google::Rpc::Status.decode(status.metadata[grpc_status_details_bin_trailer])
|
34
33
|
end
|
35
34
|
end
|
36
35
|
end
|
@@ -34,6 +34,7 @@ module Grpc
|
|
34
34
|
self.service_name = 'grpc.testing.duplicate.EchoTestService'
|
35
35
|
|
36
36
|
rpc :Echo, Grpc::Testing::EchoRequest, Grpc::Testing::EchoResponse
|
37
|
+
rpc :ResponseStream, Grpc::Testing::EchoRequest, stream(Grpc::Testing::EchoResponse)
|
37
38
|
end
|
38
39
|
|
39
40
|
Stub = Service.rpc_stub_class
|
@@ -11,45 +11,12 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
-
|
15
|
-
require 'grpc'
|
14
|
+
require 'spec_helper'
|
16
15
|
require 'timeout'
|
17
16
|
|
18
17
|
include Timeout
|
19
18
|
include GRPC::Core
|
20
19
|
|
21
|
-
# A test message
|
22
|
-
class EchoMsg
|
23
|
-
def self.marshal(_o)
|
24
|
-
''
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.unmarshal(_o)
|
28
|
-
EchoMsg.new
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# A test service with an echo implementation.
|
33
|
-
class EchoService
|
34
|
-
include GRPC::GenericService
|
35
|
-
rpc :an_rpc, EchoMsg, EchoMsg
|
36
|
-
attr_reader :received_md
|
37
|
-
|
38
|
-
def initialize(**kw)
|
39
|
-
@trailing_metadata = kw
|
40
|
-
@received_md = []
|
41
|
-
end
|
42
|
-
|
43
|
-
def an_rpc(req, call)
|
44
|
-
GRPC.logger.info('echo service received a request')
|
45
|
-
call.output_metadata.update(@trailing_metadata)
|
46
|
-
@received_md << call.metadata unless call.metadata.nil?
|
47
|
-
req
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
EchoStub = EchoService.rpc_stub_class
|
52
|
-
|
53
20
|
def start_server(port = 0)
|
54
21
|
@srv = GRPC::RpcServer.new(pool_size: 1)
|
55
22
|
server_port = @srv.add_http2_port("localhost:#{port}", :this_port_is_insecure)
|