grpc 1.49.0.pre1-x64-mingw-ucrt

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.

Files changed (127) hide show
  1. checksums.yaml +7 -0
  2. data/etc/roots.pem +4337 -0
  3. data/grpc_c.32-msvcrt.ruby +0 -0
  4. data/grpc_c.64-msvcrt.ruby +0 -0
  5. data/grpc_c.64-ucrt.ruby +0 -0
  6. data/src/ruby/bin/math_client.rb +140 -0
  7. data/src/ruby/bin/math_pb.rb +34 -0
  8. data/src/ruby/bin/math_server.rb +191 -0
  9. data/src/ruby/bin/math_services_pb.rb +51 -0
  10. data/src/ruby/bin/noproto_client.rb +93 -0
  11. data/src/ruby/bin/noproto_server.rb +97 -0
  12. data/src/ruby/ext/grpc/ext-export-truffleruby.clang +2 -0
  13. data/src/ruby/ext/grpc/ext-export-truffleruby.gcc +7 -0
  14. data/src/ruby/ext/grpc/ext-export.clang +2 -0
  15. data/src/ruby/ext/grpc/ext-export.gcc +7 -0
  16. data/src/ruby/ext/grpc/extconf.rb +163 -0
  17. data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
  18. data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
  19. data/src/ruby/ext/grpc/rb_call.c +1051 -0
  20. data/src/ruby/ext/grpc/rb_call.h +57 -0
  21. data/src/ruby/ext/grpc/rb_call_credentials.c +341 -0
  22. data/src/ruby/ext/grpc/rb_call_credentials.h +31 -0
  23. data/src/ruby/ext/grpc/rb_channel.c +849 -0
  24. data/src/ruby/ext/grpc/rb_channel.h +34 -0
  25. data/src/ruby/ext/grpc/rb_channel_args.c +155 -0
  26. data/src/ruby/ext/grpc/rb_channel_args.h +38 -0
  27. data/src/ruby/ext/grpc/rb_channel_credentials.c +286 -0
  28. data/src/ruby/ext/grpc/rb_channel_credentials.h +37 -0
  29. data/src/ruby/ext/grpc/rb_completion_queue.c +101 -0
  30. data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
  31. data/src/ruby/ext/grpc/rb_compression_options.c +471 -0
  32. data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
  33. data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
  34. data/src/ruby/ext/grpc/rb_event_thread.c +145 -0
  35. data/src/ruby/ext/grpc/rb_event_thread.h +21 -0
  36. data/src/ruby/ext/grpc/rb_grpc.c +333 -0
  37. data/src/ruby/ext/grpc/rb_grpc.h +77 -0
  38. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +597 -0
  39. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +901 -0
  40. data/src/ruby/ext/grpc/rb_loader.c +61 -0
  41. data/src/ruby/ext/grpc/rb_loader.h +25 -0
  42. data/src/ruby/ext/grpc/rb_server.c +388 -0
  43. data/src/ruby/ext/grpc/rb_server.h +32 -0
  44. data/src/ruby/ext/grpc/rb_server_credentials.c +259 -0
  45. data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
  46. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +218 -0
  47. data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +37 -0
  48. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +170 -0
  49. data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
  50. data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
  51. data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
  52. data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
  53. data/src/ruby/lib/grpc/errors.rb +277 -0
  54. data/src/ruby/lib/grpc/generic/active_call.rb +675 -0
  55. data/src/ruby/lib/grpc/generic/bidi_call.rb +233 -0
  56. data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
  57. data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
  58. data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
  59. data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
  60. data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
  61. data/src/ruby/lib/grpc/generic/service.rb +211 -0
  62. data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
  63. data/src/ruby/lib/grpc/grpc.rb +24 -0
  64. data/src/ruby/lib/grpc/logconfig.rb +44 -0
  65. data/src/ruby/lib/grpc/notifier.rb +45 -0
  66. data/src/ruby/lib/grpc/structs.rb +15 -0
  67. data/src/ruby/lib/grpc/version.rb +18 -0
  68. data/src/ruby/lib/grpc.rb +37 -0
  69. data/src/ruby/pb/README.md +42 -0
  70. data/src/ruby/pb/generate_proto_ruby.sh +52 -0
  71. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  72. data/src/ruby/pb/grpc/health/v1/health_pb.rb +31 -0
  73. data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
  74. data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
  75. data/src/ruby/pb/grpc/testing/metrics_pb.rb +28 -0
  76. data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
  77. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +17 -0
  78. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +149 -0
  79. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +17 -0
  80. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +152 -0
  81. data/src/ruby/pb/test/client.rb +769 -0
  82. data/src/ruby/pb/test/server.rb +252 -0
  83. data/src/ruby/pb/test/xds_client.rb +415 -0
  84. data/src/ruby/spec/call_credentials_spec.rb +42 -0
  85. data/src/ruby/spec/call_spec.rb +180 -0
  86. data/src/ruby/spec/channel_connection_spec.rb +126 -0
  87. data/src/ruby/spec/channel_credentials_spec.rb +124 -0
  88. data/src/ruby/spec/channel_spec.rb +245 -0
  89. data/src/ruby/spec/client_auth_spec.rb +152 -0
  90. data/src/ruby/spec/client_server_spec.rb +664 -0
  91. data/src/ruby/spec/compression_options_spec.rb +149 -0
  92. data/src/ruby/spec/debug_message_spec.rb +134 -0
  93. data/src/ruby/spec/error_sanity_spec.rb +49 -0
  94. data/src/ruby/spec/errors_spec.rb +142 -0
  95. data/src/ruby/spec/generic/active_call_spec.rb +683 -0
  96. data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
  97. data/src/ruby/spec/generic/client_stub_spec.rb +1083 -0
  98. data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
  99. data/src/ruby/spec/generic/rpc_desc_spec.rb +374 -0
  100. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +127 -0
  101. data/src/ruby/spec/generic/rpc_server_spec.rb +748 -0
  102. data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
  103. data/src/ruby/spec/generic/service_spec.rb +263 -0
  104. data/src/ruby/spec/google_rpc_status_utils_spec.rb +282 -0
  105. data/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto +28 -0
  106. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
  107. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  108. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
  109. data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
  110. data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
  111. data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
  112. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
  113. data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
  114. data/src/ruby/spec/server_credentials_spec.rb +104 -0
  115. data/src/ruby/spec/server_spec.rb +231 -0
  116. data/src/ruby/spec/spec_helper.rb +61 -0
  117. data/src/ruby/spec/support/helpers.rb +107 -0
  118. data/src/ruby/spec/support/services.rb +160 -0
  119. data/src/ruby/spec/testdata/README +1 -0
  120. data/src/ruby/spec/testdata/ca.pem +20 -0
  121. data/src/ruby/spec/testdata/client.key +28 -0
  122. data/src/ruby/spec/testdata/client.pem +20 -0
  123. data/src/ruby/spec/testdata/server1.key +28 -0
  124. data/src/ruby/spec/testdata/server1.pem +22 -0
  125. data/src/ruby/spec/time_consts_spec.rb +74 -0
  126. data/src/ruby/spec/user_agent_spec.rb +74 -0
  127. metadata +406 -0
@@ -0,0 +1,675 @@
1
+ # Copyright 2015 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
+ require 'forwardable'
16
+ require 'weakref'
17
+ require_relative 'bidi_call'
18
+
19
+ class Struct
20
+ # BatchResult is the struct returned by calls to call#start_batch.
21
+ class BatchResult
22
+ # check_status returns the status, raising an error if the status
23
+ # is non-nil and not OK.
24
+ def check_status
25
+ return nil if status.nil?
26
+ if status.code != GRPC::Core::StatusCodes::OK
27
+ GRPC.logger.debug("Failing with status #{status}")
28
+ # raise BadStatus, propagating the metadata if present.
29
+ fail GRPC::BadStatus.new_status_exception(
30
+ status.code, status.details, status.metadata,
31
+ status.debug_error_string)
32
+ end
33
+ status
34
+ end
35
+ end
36
+ end
37
+
38
+ # GRPC contains the General RPC module.
39
+ module GRPC
40
+ # The ActiveCall class provides simple methods for sending marshallable
41
+ # data to a call
42
+ class ActiveCall # rubocop:disable Metrics/ClassLength
43
+ include Core::TimeConsts
44
+ include Core::CallOps
45
+ extend Forwardable
46
+ attr_reader :deadline, :metadata_sent, :metadata_to_send, :peer, :peer_cert
47
+ def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=,
48
+ :trailing_metadata, :status
49
+
50
+ # client_invoke begins a client invocation.
51
+ #
52
+ # Flow Control note: this blocks until flow control accepts that client
53
+ # request can go ahead.
54
+ #
55
+ # deadline is the absolute deadline for the call.
56
+ #
57
+ # == Keyword Arguments ==
58
+ # any keyword arguments are treated as metadata to be sent to the server
59
+ # if a keyword value is a list, multiple metadata for it's key are sent
60
+ #
61
+ # @param call [Call] a call on which to start and invocation
62
+ # @param metadata [Hash] the metadata
63
+ def self.client_invoke(call, metadata = {})
64
+ fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
65
+ call.run_batch(SEND_INITIAL_METADATA => metadata)
66
+ end
67
+
68
+ # Creates an ActiveCall.
69
+ #
70
+ # ActiveCall should only be created after a call is accepted. That
71
+ # means different things on a client and a server. On the client, the
72
+ # call is accepted after calling call.invoke. On the server, this is
73
+ # after call.accept.
74
+ #
75
+ # #initialize cannot determine if the call is accepted or not; so if a
76
+ # call that's not accepted is used here, the error won't be visible until
77
+ # the ActiveCall methods are called.
78
+ #
79
+ # deadline is the absolute deadline for the call.
80
+ #
81
+ # @param call [Call] the call used by the ActiveCall
82
+ # @param marshal [Function] f(obj)->string that marshal requests
83
+ # @param unmarshal [Function] f(string)->obj that unmarshals responses
84
+ # @param deadline [Fixnum] the deadline for the call to complete
85
+ # @param started [true|false] indicates that metadata was sent
86
+ # @param metadata_received [true|false] indicates if metadata has already
87
+ # been received. Should always be true for server calls
88
+ def initialize(call, marshal, unmarshal, deadline, started: true,
89
+ metadata_received: false, metadata_to_send: nil)
90
+ fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
91
+ @call = call
92
+ @deadline = deadline
93
+ @marshal = marshal
94
+ @unmarshal = unmarshal
95
+ @metadata_received = metadata_received
96
+ @metadata_sent = started
97
+ @op_notifier = nil
98
+
99
+ fail(ArgumentError, 'Already sent md') if started && metadata_to_send
100
+ @metadata_to_send = metadata_to_send || {} unless started
101
+ @send_initial_md_mutex = Mutex.new
102
+
103
+ @output_stream_done = false
104
+ @input_stream_done = false
105
+ @call_finished = false
106
+ @call_finished_mu = Mutex.new
107
+
108
+ @client_call_executed = false
109
+ @client_call_executed_mu = Mutex.new
110
+
111
+ # set the peer now so that the accessor can still function
112
+ # after the server closes the call
113
+ @peer = call.peer
114
+ end
115
+
116
+ # Sends the initial metadata that has yet to be sent.
117
+ # Does nothing if metadata has already been sent for this call.
118
+ def send_initial_metadata(new_metadata = {})
119
+ @send_initial_md_mutex.synchronize do
120
+ return if @metadata_sent
121
+ @metadata_to_send.merge!(new_metadata)
122
+ ActiveCall.client_invoke(@call, @metadata_to_send)
123
+ @metadata_sent = true
124
+ end
125
+ end
126
+
127
+ # output_metadata are provides access to hash that can be used to
128
+ # save metadata to be sent as trailer
129
+ def output_metadata
130
+ @output_metadata ||= {}
131
+ end
132
+
133
+ # cancelled indicates if the call was cancelled
134
+ def cancelled?
135
+ !@call.status.nil? && @call.status.code == Core::StatusCodes::CANCELLED
136
+ end
137
+
138
+ # multi_req_view provides a restricted view of this ActiveCall for use
139
+ # in a server client-streaming handler.
140
+ def multi_req_view
141
+ MultiReqView.new(self)
142
+ end
143
+
144
+ # single_req_view provides a restricted view of this ActiveCall for use in
145
+ # a server request-response handler.
146
+ def single_req_view
147
+ SingleReqView.new(self)
148
+ end
149
+
150
+ # operation provides a restricted view of this ActiveCall for use as
151
+ # a Operation.
152
+ def operation
153
+ @op_notifier = Notifier.new
154
+ Operation.new(self)
155
+ end
156
+
157
+ ##
158
+ # Returns a restricted view of this ActiveCall for use in interceptors
159
+ #
160
+ # @return [InterceptableView]
161
+ #
162
+ def interceptable
163
+ InterceptableView.new(self)
164
+ end
165
+
166
+ def receive_and_check_status
167
+ ops = { RECV_STATUS_ON_CLIENT => nil }
168
+ ops[RECV_INITIAL_METADATA] = nil unless @metadata_received
169
+ batch_result = @call.run_batch(ops)
170
+ unless @metadata_received
171
+ @call.metadata = batch_result.metadata
172
+ @metadata_received = true
173
+ end
174
+ set_input_stream_done
175
+ attach_status_results_and_complete_call(batch_result)
176
+ end
177
+
178
+ def attach_status_results_and_complete_call(recv_status_batch_result)
179
+ unless recv_status_batch_result.status.nil?
180
+ @call.trailing_metadata = recv_status_batch_result.status.metadata
181
+ end
182
+ @call.status = recv_status_batch_result.status
183
+
184
+ # The RECV_STATUS in run_batch always succeeds
185
+ # Check the status for a bad status or failed run batch
186
+ recv_status_batch_result.check_status
187
+ end
188
+
189
+ # remote_send sends a request to the remote endpoint.
190
+ #
191
+ # It blocks until the remote endpoint accepts the message.
192
+ #
193
+ # @param req [Object, String] the object to send or it's marshal form.
194
+ # @param marshalled [false, true] indicates if the object is already
195
+ # marshalled.
196
+ def remote_send(req, marshalled = false)
197
+ send_initial_metadata
198
+ GRPC.logger.debug("sending #{req}, marshalled? #{marshalled}")
199
+ payload = marshalled ? req : @marshal.call(req)
200
+ @call.run_batch(SEND_MESSAGE => payload)
201
+ end
202
+
203
+ # send_status sends a status to the remote endpoint.
204
+ #
205
+ # @param code [int] the status code to send
206
+ # @param details [String] details
207
+ # @param assert_finished [true, false] when true(default), waits for
208
+ # FINISHED.
209
+ # @param metadata [Hash] metadata to send to the server. If a value is a
210
+ # list, mulitple metadata for its key are sent
211
+ def send_status(code = OK, details = '', assert_finished = false,
212
+ metadata: {})
213
+ send_initial_metadata
214
+ ops = {
215
+ SEND_STATUS_FROM_SERVER => Struct::Status.new(code, details, metadata)
216
+ }
217
+ ops[RECV_CLOSE_ON_SERVER] = nil if assert_finished
218
+ @call.run_batch(ops)
219
+ set_output_stream_done
220
+
221
+ nil
222
+ end
223
+
224
+ # Intended for use on server-side calls when a single request from
225
+ # the client is expected (i.e., unary and server-streaming RPC types).
226
+ def read_unary_request
227
+ req = remote_read
228
+ set_input_stream_done
229
+ req
230
+ end
231
+
232
+ def server_unary_response(req, trailing_metadata: {},
233
+ code: Core::StatusCodes::OK, details: 'OK')
234
+ ops = {}
235
+ @send_initial_md_mutex.synchronize do
236
+ ops[SEND_INITIAL_METADATA] = @metadata_to_send unless @metadata_sent
237
+ @metadata_sent = true
238
+ end
239
+
240
+ payload = @marshal.call(req)
241
+ ops[SEND_MESSAGE] = payload
242
+ ops[SEND_STATUS_FROM_SERVER] = Struct::Status.new(
243
+ code, details, trailing_metadata)
244
+ ops[RECV_CLOSE_ON_SERVER] = nil
245
+
246
+ @call.run_batch(ops)
247
+ set_output_stream_done
248
+ end
249
+
250
+ # remote_read reads a response from the remote endpoint.
251
+ #
252
+ # It blocks until the remote endpoint replies with a message or status.
253
+ # On receiving a message, it returns the response after unmarshalling it.
254
+ # On receiving a status, it returns nil if the status is OK, otherwise
255
+ # raising BadStatus
256
+ def remote_read
257
+ ops = { RECV_MESSAGE => nil }
258
+ ops[RECV_INITIAL_METADATA] = nil unless @metadata_received
259
+ batch_result = @call.run_batch(ops)
260
+ unless @metadata_received
261
+ @call.metadata = batch_result.metadata
262
+ @metadata_received = true
263
+ end
264
+ get_message_from_batch_result(batch_result)
265
+ end
266
+
267
+ def get_message_from_batch_result(recv_message_batch_result)
268
+ unless recv_message_batch_result.nil? ||
269
+ recv_message_batch_result.message.nil?
270
+ return @unmarshal.call(recv_message_batch_result.message)
271
+ end
272
+ GRPC.logger.debug('found nil; the final response has been sent')
273
+ nil
274
+ end
275
+
276
+ # each_remote_read passes each response to the given block or returns an
277
+ # enumerator the responses if no block is given.
278
+ # Used to generate the request enumerable for
279
+ # server-side client-streaming RPC's.
280
+ #
281
+ # == Enumerator ==
282
+ #
283
+ # * #next blocks until the remote endpoint sends a READ or FINISHED
284
+ # * for each read, enumerator#next yields the response
285
+ # * on status
286
+ # * if it's is OK, enumerator#next raises StopException
287
+ # * if is not OK, enumerator#next raises RuntimeException
288
+ #
289
+ # == Block ==
290
+ #
291
+ # * if provided it is executed for each response
292
+ # * the call blocks until no more responses are provided
293
+ #
294
+ # @return [Enumerator] if no block was given
295
+ def each_remote_read
296
+ return enum_for(:each_remote_read) unless block_given?
297
+ begin
298
+ loop do
299
+ resp = remote_read
300
+ break if resp.nil? # the last response was received
301
+ yield resp
302
+ end
303
+ ensure
304
+ set_input_stream_done
305
+ end
306
+ end
307
+
308
+ # each_remote_read_then_finish passes each response to the given block or
309
+ # returns an enumerator of the responses if no block is given.
310
+ #
311
+ # It is like each_remote_read, but it blocks on finishing on detecting
312
+ # the final message.
313
+ #
314
+ # == Enumerator ==
315
+ #
316
+ # * #next blocks until the remote endpoint sends a READ or FINISHED
317
+ # * for each read, enumerator#next yields the response
318
+ # * on status
319
+ # * if it's is OK, enumerator#next raises StopException
320
+ # * if is not OK, enumerator#next raises RuntimeException
321
+ #
322
+ # == Block ==
323
+ #
324
+ # * if provided it is executed for each response
325
+ # * the call blocks until no more responses are provided
326
+ #
327
+ # @return [Enumerator] if no block was given
328
+ def each_remote_read_then_finish
329
+ return enum_for(:each_remote_read_then_finish) unless block_given?
330
+ loop do
331
+ resp =
332
+ begin
333
+ remote_read
334
+ rescue GRPC::Core::CallError => e
335
+ GRPC.logger.warn("In each_remote_read_then_finish: #{e}")
336
+ nil
337
+ end
338
+
339
+ break if resp.nil? # the last response was received
340
+ yield resp
341
+ end
342
+
343
+ receive_and_check_status
344
+ ensure
345
+ set_input_stream_done
346
+ end
347
+
348
+ # request_response sends a request to a GRPC server, and returns the
349
+ # response.
350
+ #
351
+ # @param req [Object] the request sent to the server
352
+ # @param metadata [Hash] metadata to be sent to the server. If a value is
353
+ # a list, multiple metadata for its key are sent
354
+ # @return [Object] the response received from the server
355
+ def request_response(req, metadata: {})
356
+ raise_error_if_already_executed
357
+ ops = {
358
+ SEND_MESSAGE => @marshal.call(req),
359
+ SEND_CLOSE_FROM_CLIENT => nil,
360
+ RECV_INITIAL_METADATA => nil,
361
+ RECV_MESSAGE => nil,
362
+ RECV_STATUS_ON_CLIENT => nil
363
+ }
364
+ @send_initial_md_mutex.synchronize do
365
+ # Metadata might have already been sent if this is an operation view
366
+ unless @metadata_sent
367
+ ops[SEND_INITIAL_METADATA] = @metadata_to_send.merge!(metadata)
368
+ end
369
+ @metadata_sent = true
370
+ end
371
+
372
+ begin
373
+ batch_result = @call.run_batch(ops)
374
+ # no need to check for cancellation after a CallError because this
375
+ # batch contains a RECV_STATUS op
376
+ ensure
377
+ set_input_stream_done
378
+ set_output_stream_done
379
+ end
380
+
381
+ @call.metadata = batch_result.metadata
382
+ attach_status_results_and_complete_call(batch_result)
383
+ get_message_from_batch_result(batch_result)
384
+ end
385
+
386
+ # client_streamer sends a stream of requests to a GRPC server, and
387
+ # returns a single response.
388
+ #
389
+ # requests provides an 'iterable' of Requests. I.e. it follows Ruby's
390
+ # #each enumeration protocol. In the simplest case, requests will be an
391
+ # array of marshallable objects; in typical case it will be an Enumerable
392
+ # that allows dynamic construction of the marshallable objects.
393
+ #
394
+ # @param requests [Object] an Enumerable of requests to send
395
+ # @param metadata [Hash] metadata to be sent to the server. If a value is
396
+ # a list, multiple metadata for its key are sent
397
+ # @return [Object] the response received from the server
398
+ def client_streamer(requests, metadata: {})
399
+ raise_error_if_already_executed
400
+ begin
401
+ send_initial_metadata(metadata)
402
+ requests.each { |r| @call.run_batch(SEND_MESSAGE => @marshal.call(r)) }
403
+ rescue GRPC::Core::CallError => e
404
+ receive_and_check_status # check for Cancelled
405
+ raise e
406
+ rescue => e
407
+ set_input_stream_done
408
+ raise e
409
+ ensure
410
+ set_output_stream_done
411
+ end
412
+
413
+ batch_result = @call.run_batch(
414
+ SEND_CLOSE_FROM_CLIENT => nil,
415
+ RECV_INITIAL_METADATA => nil,
416
+ RECV_MESSAGE => nil,
417
+ RECV_STATUS_ON_CLIENT => nil
418
+ )
419
+
420
+ set_input_stream_done
421
+
422
+ @call.metadata = batch_result.metadata
423
+ attach_status_results_and_complete_call(batch_result)
424
+ get_message_from_batch_result(batch_result)
425
+ end
426
+
427
+ # server_streamer sends one request to the GRPC server, which yields a
428
+ # stream of responses.
429
+ #
430
+ # responses provides an enumerator over the streamed responses, i.e. it
431
+ # follows Ruby's #each iteration protocol. The enumerator blocks while
432
+ # waiting for each response, stops when the server signals that no
433
+ # further responses will be supplied. If the implicit block is provided,
434
+ # it is executed with each response as the argument and no result is
435
+ # returned.
436
+ #
437
+ # @param req [Object] the request sent to the server
438
+ # @param metadata [Hash] metadata to be sent to the server. If a value is
439
+ # a list, multiple metadata for its key are sent
440
+ # @return [Enumerator|nil] a response Enumerator
441
+ def server_streamer(req, metadata: {})
442
+ raise_error_if_already_executed
443
+ ops = {
444
+ SEND_MESSAGE => @marshal.call(req),
445
+ SEND_CLOSE_FROM_CLIENT => nil
446
+ }
447
+ @send_initial_md_mutex.synchronize do
448
+ # Metadata might have already been sent if this is an operation view
449
+ unless @metadata_sent
450
+ ops[SEND_INITIAL_METADATA] = @metadata_to_send.merge!(metadata)
451
+ end
452
+ @metadata_sent = true
453
+ end
454
+
455
+ begin
456
+ @call.run_batch(ops)
457
+ rescue GRPC::Core::CallError => e
458
+ receive_and_check_status # checks for Cancelled
459
+ raise e
460
+ rescue => e
461
+ set_input_stream_done
462
+ raise e
463
+ ensure
464
+ set_output_stream_done
465
+ end
466
+
467
+ replies = enum_for(:each_remote_read_then_finish)
468
+ return replies unless block_given?
469
+ replies.each { |r| yield r }
470
+ end
471
+
472
+ # bidi_streamer sends a stream of requests to the GRPC server, and yields
473
+ # a stream of responses.
474
+ #
475
+ # This method takes an Enumerable of requests, and returns and enumerable
476
+ # of responses.
477
+ #
478
+ # == requests ==
479
+ #
480
+ # requests provides an 'iterable' of Requests. I.e. it follows Ruby's
481
+ # #each enumeration protocol. In the simplest case, requests will be an
482
+ # array of marshallable objects; in typical case it will be an
483
+ # Enumerable that allows dynamic construction of the marshallable
484
+ # objects.
485
+ #
486
+ # == responses ==
487
+ #
488
+ # This is an enumerator of responses. I.e, its #next method blocks
489
+ # waiting for the next response. Also, if at any point the block needs
490
+ # to consume all the remaining responses, this can be done using #each or
491
+ # #collect. Calling #each or #collect should only be done if
492
+ # the_call#writes_done has been called, otherwise the block will loop
493
+ # forever.
494
+ #
495
+ # @param requests [Object] an Enumerable of requests to send
496
+ # @param metadata [Hash] metadata to be sent to the server. If a value is
497
+ # a list, multiple metadata for its key are sent
498
+ # @return [Enumerator, nil] a response Enumerator
499
+ def bidi_streamer(requests, metadata: {}, &blk)
500
+ raise_error_if_already_executed
501
+ # Metadata might have already been sent if this is an operation view
502
+ begin
503
+ send_initial_metadata(metadata)
504
+ rescue GRPC::Core::CallError => e
505
+ batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil)
506
+ set_input_stream_done
507
+ set_output_stream_done
508
+ attach_status_results_and_complete_call(batch_result)
509
+ raise e
510
+ rescue => e
511
+ set_input_stream_done
512
+ set_output_stream_done
513
+ raise e
514
+ end
515
+
516
+ bd = BidiCall.new(@call,
517
+ @marshal,
518
+ @unmarshal,
519
+ metadata_received: @metadata_received)
520
+
521
+ bd.run_on_client(requests,
522
+ proc { set_input_stream_done },
523
+ proc { set_output_stream_done },
524
+ &blk)
525
+ end
526
+
527
+ # run_server_bidi orchestrates a BiDi stream processing on a server.
528
+ #
529
+ # N.B. gen_each_reply is a func(Enumerable<Requests>)
530
+ #
531
+ # It takes an enumerable of requests as an arg, in case there is a
532
+ # relationship between the stream of requests and the stream of replies.
533
+ #
534
+ # This does not mean that must necessarily be one. E.g, the replies
535
+ # produced by gen_each_reply could ignore the received_msgs
536
+ #
537
+ # @param mth [Proc] generates the BiDi stream replies
538
+ # @param interception_ctx [InterceptionContext]
539
+ #
540
+ def run_server_bidi(mth, interception_ctx)
541
+ view = multi_req_view
542
+ bidi_call = BidiCall.new(
543
+ @call,
544
+ @marshal,
545
+ @unmarshal,
546
+ metadata_received: @metadata_received,
547
+ req_view: view
548
+ )
549
+ requests = bidi_call.read_next_loop(proc { set_input_stream_done }, false)
550
+ interception_ctx.intercept!(
551
+ :bidi_streamer,
552
+ call: view,
553
+ method: mth,
554
+ requests: requests
555
+ ) do
556
+ bidi_call.run_on_server(mth, requests)
557
+ end
558
+ end
559
+
560
+ # Waits till an operation completes
561
+ def wait
562
+ return if @op_notifier.nil?
563
+ GRPC.logger.debug("active_call.wait: on #{@op_notifier}")
564
+ @op_notifier.wait
565
+ end
566
+
567
+ # Signals that an operation is done.
568
+ # Only relevant on the client-side (this is a no-op on the server-side)
569
+ def op_is_done
570
+ return if @op_notifier.nil?
571
+ @op_notifier.notify(self)
572
+ end
573
+
574
+ # Add to the metadata that will be sent from the server.
575
+ # Fails if metadata has already been sent.
576
+ # Unused by client calls.
577
+ def merge_metadata_to_send(new_metadata = {})
578
+ @send_initial_md_mutex.synchronize do
579
+ fail('cant change metadata after already sent') if @metadata_sent
580
+ @metadata_to_send.merge!(new_metadata)
581
+ end
582
+ end
583
+
584
+ def attach_peer_cert(peer_cert)
585
+ @peer_cert = peer_cert
586
+ end
587
+
588
+ private
589
+
590
+ # To be called once the "input stream" has been completelly
591
+ # read through (i.e, done reading from client or received status)
592
+ # note this is idempotent
593
+ def set_input_stream_done
594
+ @call_finished_mu.synchronize do
595
+ @input_stream_done = true
596
+ maybe_finish_and_close_call_locked
597
+ end
598
+ end
599
+
600
+ # To be called once the "output stream" has been completelly
601
+ # sent through (i.e, done sending from client or sent status)
602
+ # note this is idempotent
603
+ def set_output_stream_done
604
+ @call_finished_mu.synchronize do
605
+ @output_stream_done = true
606
+ maybe_finish_and_close_call_locked
607
+ end
608
+ end
609
+
610
+ def maybe_finish_and_close_call_locked
611
+ return unless @output_stream_done && @input_stream_done
612
+ return if @call_finished
613
+ @call_finished = true
614
+ op_is_done
615
+ @call.close
616
+ end
617
+
618
+ # Starts the call if not already started
619
+ # @param metadata [Hash] metadata to be sent to the server. If a value is
620
+ # a list, multiple metadata for its key are sent
621
+ def start_call(metadata = {})
622
+ merge_metadata_to_send(metadata) && send_initial_metadata
623
+ end
624
+
625
+ def raise_error_if_already_executed
626
+ @client_call_executed_mu.synchronize do
627
+ if @client_call_executed
628
+ fail GRPC::Core::CallError, 'attempting to re-run a call'
629
+ end
630
+ @client_call_executed = true
631
+ end
632
+ end
633
+
634
+ def self.view_class(*visible_methods)
635
+ Class.new do
636
+ extend ::Forwardable
637
+ def_delegators :@wrapped, *visible_methods
638
+
639
+ # @param wrapped [ActiveCall] the call whose methods are shielded
640
+ def initialize(wrapped)
641
+ @wrapped = wrapped
642
+ end
643
+ end
644
+ end
645
+
646
+ # SingleReqView limits access to an ActiveCall's methods for use in server
647
+ # handlers that receive just one request.
648
+ SingleReqView = view_class(:cancelled?, :deadline, :metadata,
649
+ :output_metadata, :peer, :peer_cert,
650
+ :send_initial_metadata,
651
+ :metadata_to_send,
652
+ :merge_metadata_to_send,
653
+ :metadata_sent)
654
+
655
+ # MultiReqView limits access to an ActiveCall's methods for use in
656
+ # server client_streamer handlers.
657
+ MultiReqView = view_class(:cancelled?, :deadline,
658
+ :each_remote_read, :metadata, :output_metadata,
659
+ :peer, :peer_cert,
660
+ :send_initial_metadata,
661
+ :metadata_to_send,
662
+ :merge_metadata_to_send,
663
+ :metadata_sent)
664
+
665
+ # Operation limits access to an ActiveCall's methods for use as
666
+ # a Operation on the client.
667
+ Operation = view_class(:cancel, :cancelled?, :deadline, :execute,
668
+ :metadata, :status, :start_call, :wait, :write_flag,
669
+ :write_flag=, :trailing_metadata)
670
+
671
+ # InterceptableView further limits access to an ActiveCall's methods
672
+ # for use in interceptors on the client, exposing only the deadline
673
+ InterceptableView = view_class(:deadline)
674
+ end
675
+ end