grpc 1.4.1 → 1.4.5
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/Makefile +2 -2
- data/src/ruby/ext/grpc/rb_call.c +23 -10
- data/src/ruby/ext/grpc/rb_call.h +3 -0
- data/src/ruby/ext/grpc/rb_call_credentials.c +6 -1
- data/src/ruby/ext/grpc/rb_channel_credentials.c +6 -0
- data/src/ruby/lib/grpc/generic/active_call.rb +137 -33
- data/src/ruby/lib/grpc/generic/bidi_call.rb +28 -34
- data/src/ruby/lib/grpc/generic/rpc_desc.rb +2 -2
- data/src/ruby/lib/grpc/generic/rpc_server.rb +1 -0
- data/src/ruby/lib/grpc/version.rb +1 -1
- data/src/ruby/spec/client_auth_spec.rb +152 -0
- data/src/ruby/spec/client_server_spec.rb +29 -5
- data/src/ruby/spec/generic/active_call_spec.rb +2 -2
- data/src/ruby/spec/generic/client_stub_spec.rb +313 -70
- data/src/ruby/spec/generic/rpc_desc_spec.rb +5 -5
- data/src/ruby/spec/generic/rpc_server_spec.rb +145 -0
- data/src/ruby/spec/testdata/client.key +16 -0
- data/src/ruby/spec/testdata/client.pem +14 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41d777c781a715c7193857593c53732018a49b3d
|
4
|
+
data.tar.gz: abcce4df9529daef3bd697bfa860a8247512e0f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec200f702fe2c9f8b169eec5df70a5e44aa6f8714fc2ab90a4d0d3ad92ff261859bbd1a535a49f556581710262b4201724762fad8f6172a7869bf63045e9d2fb
|
7
|
+
data.tar.gz: a0244c322356e3d54084347ea6bcceabd041065cbcab6d584b1dc93550b89aff2afb7d8462e11d65455adcf2de3ca4f74501ee0ddc010783e44cdb8f3819d0fa
|
data/Makefile
CHANGED
@@ -423,8 +423,8 @@ Q = @
|
|
423
423
|
endif
|
424
424
|
|
425
425
|
CORE_VERSION = 4.0.0
|
426
|
-
CPP_VERSION = 1.4.
|
427
|
-
CSHARP_VERSION = 1.4.
|
426
|
+
CPP_VERSION = 1.4.5
|
427
|
+
CSHARP_VERSION = 1.4.5
|
428
428
|
|
429
429
|
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
|
430
430
|
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
|
data/src/ruby/ext/grpc/rb_call.c
CHANGED
@@ -39,6 +39,8 @@
|
|
39
39
|
#include <grpc/grpc.h>
|
40
40
|
#include <grpc/impl/codegen/compression_types.h>
|
41
41
|
#include <grpc/support/alloc.h>
|
42
|
+
#include <grpc/support/alloc.h>
|
43
|
+
#include <grpc/support/log.h>
|
42
44
|
|
43
45
|
#include "rb_byte_buffer.h"
|
44
46
|
#include "rb_call_credentials.h"
|
@@ -383,7 +385,7 @@ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
|
|
383
385
|
to fill grpc_metadata_array.
|
384
386
|
|
385
387
|
it's capacity should have been computed via a prior call to
|
386
|
-
|
388
|
+
grpc_rb_md_ary_capacity_hash_cb
|
387
389
|
*/
|
388
390
|
static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
|
389
391
|
grpc_metadata_array *md_ary = NULL;
|
@@ -391,7 +393,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
|
|
391
393
|
long i;
|
392
394
|
grpc_slice key_slice;
|
393
395
|
grpc_slice value_slice;
|
394
|
-
char *tmp_str;
|
396
|
+
char *tmp_str = NULL;
|
395
397
|
|
396
398
|
if (TYPE(key) == T_SYMBOL) {
|
397
399
|
key_slice = grpc_slice_from_static_string(rb_id2name(SYM2ID(key)));
|
@@ -401,6 +403,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
|
|
401
403
|
} else {
|
402
404
|
rb_raise(rb_eTypeError,
|
403
405
|
"grpc_rb_md_ary_fill_hash_cb: bad type for key parameter");
|
406
|
+
return ST_STOP;
|
404
407
|
}
|
405
408
|
|
406
409
|
if (!grpc_header_key_is_legal(key_slice)) {
|
@@ -428,6 +431,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
|
|
428
431
|
tmp_str);
|
429
432
|
return ST_STOP;
|
430
433
|
}
|
434
|
+
GPR_ASSERT(md_ary->count < md_ary->capacity);
|
431
435
|
md_ary->metadata[md_ary->count].key = key_slice;
|
432
436
|
md_ary->metadata[md_ary->count].value = value_slice;
|
433
437
|
md_ary->count += 1;
|
@@ -443,6 +447,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
|
|
443
447
|
tmp_str);
|
444
448
|
return ST_STOP;
|
445
449
|
}
|
450
|
+
GPR_ASSERT(md_ary->count < md_ary->capacity);
|
446
451
|
md_ary->metadata[md_ary->count].key = key_slice;
|
447
452
|
md_ary->metadata[md_ary->count].value = value_slice;
|
448
453
|
md_ary->count += 1;
|
@@ -450,7 +455,6 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
|
|
450
455
|
rb_raise(rb_eArgError, "Header values must be of type string or array");
|
451
456
|
return ST_STOP;
|
452
457
|
}
|
453
|
-
|
454
458
|
return ST_CONTINUE;
|
455
459
|
}
|
456
460
|
|
@@ -473,6 +477,7 @@ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val,
|
|
473
477
|
} else {
|
474
478
|
md_ary->capacity += 1;
|
475
479
|
}
|
480
|
+
|
476
481
|
return ST_CONTINUE;
|
477
482
|
}
|
478
483
|
|
@@ -495,7 +500,7 @@ void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary) {
|
|
495
500
|
md_ary_obj =
|
496
501
|
TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary);
|
497
502
|
rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj);
|
498
|
-
md_ary->metadata =
|
503
|
+
md_ary->metadata = gpr_zalloc(md_ary->capacity * sizeof(grpc_metadata));
|
499
504
|
rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj);
|
500
505
|
}
|
501
506
|
|
@@ -626,13 +631,25 @@ static void grpc_run_batch_stack_init(run_batch_stack *st,
|
|
626
631
|
st->write_flag = write_flag;
|
627
632
|
}
|
628
633
|
|
634
|
+
void grpc_rb_metadata_array_destroy_including_entries(
|
635
|
+
grpc_metadata_array *array) {
|
636
|
+
size_t i;
|
637
|
+
if (array->metadata) {
|
638
|
+
for (i = 0; i < array->count; i++) {
|
639
|
+
grpc_slice_unref(array->metadata[i].key);
|
640
|
+
grpc_slice_unref(array->metadata[i].value);
|
641
|
+
}
|
642
|
+
}
|
643
|
+
grpc_metadata_array_destroy(array);
|
644
|
+
}
|
645
|
+
|
629
646
|
/* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
|
630
647
|
* cleaned up */
|
631
648
|
static void grpc_run_batch_stack_cleanup(run_batch_stack *st) {
|
632
649
|
size_t i = 0;
|
633
650
|
|
634
|
-
|
635
|
-
|
651
|
+
grpc_rb_metadata_array_destroy_including_entries(&st->send_metadata);
|
652
|
+
grpc_rb_metadata_array_destroy_including_entries(&st->send_trailing_metadata);
|
636
653
|
grpc_metadata_array_destroy(&st->recv_metadata);
|
637
654
|
grpc_metadata_array_destroy(&st->recv_trailing_metadata);
|
638
655
|
|
@@ -673,8 +690,6 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
|
|
673
690
|
st->ops[st->op_num].flags = 0;
|
674
691
|
switch (NUM2INT(this_op)) {
|
675
692
|
case GRPC_OP_SEND_INITIAL_METADATA:
|
676
|
-
/* N.B. later there is no need to explicitly delete the metadata keys
|
677
|
-
* and values, they are references to data in ruby objects. */
|
678
693
|
grpc_rb_md_ary_convert(this_value, &st->send_metadata);
|
679
694
|
st->ops[st->op_num].data.send_initial_metadata.count =
|
680
695
|
st->send_metadata.count;
|
@@ -690,8 +705,6 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
|
|
690
705
|
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
|
691
706
|
break;
|
692
707
|
case GRPC_OP_SEND_STATUS_FROM_SERVER:
|
693
|
-
/* N.B. later there is no need to explicitly delete the metadata keys
|
694
|
-
* and values, they are references to data in ruby objects. */
|
695
708
|
grpc_rb_op_update_status_from_server(
|
696
709
|
&st->ops[st->op_num], &st->send_trailing_metadata,
|
697
710
|
&st->send_status_details, this_value);
|
data/src/ruby/ext/grpc/rb_call.h
CHANGED
@@ -55,6 +55,9 @@ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary);
|
|
55
55
|
*/
|
56
56
|
void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary);
|
57
57
|
|
58
|
+
void grpc_rb_metadata_array_destroy_including_entries(
|
59
|
+
grpc_metadata_array *md_ary);
|
60
|
+
|
58
61
|
/* grpc_rb_eCallError is the ruby class of the exception thrown during call
|
59
62
|
operations. */
|
60
63
|
extern VALUE grpc_rb_eCallError;
|
@@ -123,7 +123,7 @@ static void grpc_rb_call_credentials_callback_with_gil(void *param) {
|
|
123
123
|
error_details = StringValueCStr(details);
|
124
124
|
params->callback(params->user_data, md_ary.metadata, md_ary.count, status,
|
125
125
|
error_details);
|
126
|
-
|
126
|
+
grpc_rb_metadata_array_destroy_including_entries(&md_ary);
|
127
127
|
gpr_free(params);
|
128
128
|
}
|
129
129
|
|
@@ -254,6 +254,7 @@ static VALUE grpc_rb_call_credentials_compose(int argc, VALUE *argv,
|
|
254
254
|
VALUE self) {
|
255
255
|
grpc_call_credentials *creds;
|
256
256
|
grpc_call_credentials *other;
|
257
|
+
grpc_call_credentials *prev = NULL;
|
257
258
|
VALUE mark;
|
258
259
|
if (argc == 0) {
|
259
260
|
return self;
|
@@ -264,6 +265,10 @@ static VALUE grpc_rb_call_credentials_compose(int argc, VALUE *argv,
|
|
264
265
|
rb_ary_push(mark, argv[i]);
|
265
266
|
other = grpc_rb_get_wrapped_call_credentials(argv[i]);
|
266
267
|
creds = grpc_composite_call_credentials_create(creds, other, NULL);
|
268
|
+
if (prev != NULL) {
|
269
|
+
grpc_call_credentials_release(prev);
|
270
|
+
}
|
271
|
+
prev = creds;
|
267
272
|
}
|
268
273
|
return grpc_rb_wrap_call_credentials(creds, mark);
|
269
274
|
}
|
@@ -199,6 +199,7 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
|
|
199
199
|
VALUE self) {
|
200
200
|
grpc_channel_credentials *creds;
|
201
201
|
grpc_call_credentials *other;
|
202
|
+
grpc_channel_credentials *prev = NULL;
|
202
203
|
VALUE mark;
|
203
204
|
if (argc == 0) {
|
204
205
|
return self;
|
@@ -210,6 +211,11 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
|
|
210
211
|
rb_ary_push(mark, argv[i]);
|
211
212
|
other = grpc_rb_get_wrapped_call_credentials(argv[i]);
|
212
213
|
creds = grpc_composite_channel_credentials_create(creds, other, NULL);
|
214
|
+
if (prev != NULL) {
|
215
|
+
grpc_channel_credentials_release(prev);
|
216
|
+
}
|
217
|
+
prev = creds;
|
218
|
+
|
213
219
|
if (creds == NULL) {
|
214
220
|
rb_raise(rb_eRuntimeError,
|
215
221
|
"Failed to compose channel and call credentials");
|
@@ -55,13 +55,13 @@ end
|
|
55
55
|
module GRPC
|
56
56
|
# The ActiveCall class provides simple methods for sending marshallable
|
57
57
|
# data to a call
|
58
|
-
class ActiveCall
|
58
|
+
class ActiveCall # rubocop:disable Metrics/ClassLength
|
59
59
|
include Core::TimeConsts
|
60
60
|
include Core::CallOps
|
61
61
|
extend Forwardable
|
62
|
-
attr_reader :deadline, :metadata_sent, :metadata_to_send
|
62
|
+
attr_reader :deadline, :metadata_sent, :metadata_to_send, :peer, :peer_cert
|
63
63
|
def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=,
|
64
|
-
:
|
64
|
+
:trailing_metadata, :status
|
65
65
|
|
66
66
|
# client_invoke begins a client invocation.
|
67
67
|
#
|
@@ -115,6 +115,18 @@ module GRPC
|
|
115
115
|
fail(ArgumentError, 'Already sent md') if started && metadata_to_send
|
116
116
|
@metadata_to_send = metadata_to_send || {} unless started
|
117
117
|
@send_initial_md_mutex = Mutex.new
|
118
|
+
|
119
|
+
@output_stream_done = false
|
120
|
+
@input_stream_done = false
|
121
|
+
@call_finished = false
|
122
|
+
@call_finished_mu = Mutex.new
|
123
|
+
|
124
|
+
@client_call_executed = false
|
125
|
+
@client_call_executed_mu = Mutex.new
|
126
|
+
|
127
|
+
# set the peer now so that the accessor can still function
|
128
|
+
# after the server closes the call
|
129
|
+
@peer = call.peer
|
118
130
|
end
|
119
131
|
|
120
132
|
# Sends the initial metadata that has yet to be sent.
|
@@ -157,11 +169,9 @@ module GRPC
|
|
157
169
|
Operation.new(self)
|
158
170
|
end
|
159
171
|
|
160
|
-
|
161
|
-
#
|
162
|
-
# It blocks until the remote endpoint acknowledges by sending a status.
|
163
|
-
def finished
|
172
|
+
def receive_and_check_status
|
164
173
|
batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil)
|
174
|
+
set_input_stream_done
|
165
175
|
attach_status_results_and_complete_call(batch_result)
|
166
176
|
end
|
167
177
|
|
@@ -170,8 +180,6 @@ module GRPC
|
|
170
180
|
@call.trailing_metadata = recv_status_batch_result.status.metadata
|
171
181
|
end
|
172
182
|
@call.status = recv_status_batch_result.status
|
173
|
-
@call.close
|
174
|
-
op_is_done
|
175
183
|
|
176
184
|
# The RECV_STATUS in run_batch always succeeds
|
177
185
|
# Check the status for a bad status or failed run batch
|
@@ -208,9 +216,19 @@ module GRPC
|
|
208
216
|
}
|
209
217
|
ops[RECV_CLOSE_ON_SERVER] = nil if assert_finished
|
210
218
|
@call.run_batch(ops)
|
219
|
+
set_output_stream_done
|
220
|
+
|
211
221
|
nil
|
212
222
|
end
|
213
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
|
+
|
214
232
|
def server_unary_response(req, trailing_metadata: {},
|
215
233
|
code: Core::StatusCodes::OK, details: 'OK')
|
216
234
|
ops = {}
|
@@ -226,6 +244,7 @@ module GRPC
|
|
226
244
|
ops[RECV_CLOSE_ON_SERVER] = nil
|
227
245
|
|
228
246
|
@call.run_batch(ops)
|
247
|
+
set_output_stream_done
|
229
248
|
end
|
230
249
|
|
231
250
|
# remote_read reads a response from the remote endpoint.
|
@@ -256,6 +275,8 @@ module GRPC
|
|
256
275
|
|
257
276
|
# each_remote_read passes each response to the given block or returns an
|
258
277
|
# enumerator the responses if no block is given.
|
278
|
+
# Used to generate the request enumerable for
|
279
|
+
# server-side client-streaming RPC's.
|
259
280
|
#
|
260
281
|
# == Enumerator ==
|
261
282
|
#
|
@@ -273,10 +294,14 @@ module GRPC
|
|
273
294
|
# @return [Enumerator] if no block was given
|
274
295
|
def each_remote_read
|
275
296
|
return enum_for(:each_remote_read) unless block_given?
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
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
|
280
305
|
end
|
281
306
|
end
|
282
307
|
|
@@ -302,13 +327,17 @@ module GRPC
|
|
302
327
|
# @return [Enumerator] if no block was given
|
303
328
|
def each_remote_read_then_finish
|
304
329
|
return enum_for(:each_remote_read_then_finish) unless block_given?
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
330
|
+
begin
|
331
|
+
loop do
|
332
|
+
resp = remote_read
|
333
|
+
if resp.nil? # the last response was received
|
334
|
+
receive_and_check_status
|
335
|
+
break
|
336
|
+
end
|
337
|
+
yield resp
|
310
338
|
end
|
311
|
-
|
339
|
+
ensure
|
340
|
+
set_input_stream_done
|
312
341
|
end
|
313
342
|
end
|
314
343
|
|
@@ -320,6 +349,7 @@ module GRPC
|
|
320
349
|
# a list, multiple metadata for its key are sent
|
321
350
|
# @return [Object] the response received from the server
|
322
351
|
def request_response(req, metadata: {})
|
352
|
+
raise_error_if_already_executed
|
323
353
|
ops = {
|
324
354
|
SEND_MESSAGE => @marshal.call(req),
|
325
355
|
SEND_CLOSE_FROM_CLIENT => nil,
|
@@ -334,7 +364,15 @@ module GRPC
|
|
334
364
|
end
|
335
365
|
@metadata_sent = true
|
336
366
|
end
|
337
|
-
|
367
|
+
|
368
|
+
begin
|
369
|
+
batch_result = @call.run_batch(ops)
|
370
|
+
# no need to check for cancellation after a CallError because this
|
371
|
+
# batch contains a RECV_STATUS op
|
372
|
+
ensure
|
373
|
+
set_input_stream_done
|
374
|
+
set_output_stream_done
|
375
|
+
end
|
338
376
|
|
339
377
|
@call.metadata = batch_result.metadata
|
340
378
|
attach_status_results_and_complete_call(batch_result)
|
@@ -354,10 +392,20 @@ module GRPC
|
|
354
392
|
# a list, multiple metadata for its key are sent
|
355
393
|
# @return [Object] the response received from the server
|
356
394
|
def client_streamer(requests, metadata: {})
|
357
|
-
|
358
|
-
|
395
|
+
raise_error_if_already_executed
|
396
|
+
begin
|
397
|
+
merge_metadata_and_send_if_not_already_sent(metadata)
|
398
|
+
requests.each { |r| @call.run_batch(SEND_MESSAGE => @marshal.call(r)) }
|
399
|
+
rescue GRPC::Core::CallError => e
|
400
|
+
receive_and_check_status # check for Cancelled
|
401
|
+
raise e
|
402
|
+
rescue => e
|
403
|
+
set_input_stream_done
|
404
|
+
raise e
|
405
|
+
ensure
|
406
|
+
set_output_stream_done
|
407
|
+
end
|
359
408
|
|
360
|
-
requests.each { |r| @call.run_batch(SEND_MESSAGE => @marshal.call(r)) }
|
361
409
|
batch_result = @call.run_batch(
|
362
410
|
SEND_CLOSE_FROM_CLIENT => nil,
|
363
411
|
RECV_INITIAL_METADATA => nil,
|
@@ -365,12 +413,11 @@ module GRPC
|
|
365
413
|
RECV_STATUS_ON_CLIENT => nil
|
366
414
|
)
|
367
415
|
|
416
|
+
set_input_stream_done
|
417
|
+
|
368
418
|
@call.metadata = batch_result.metadata
|
369
419
|
attach_status_results_and_complete_call(batch_result)
|
370
420
|
get_message_from_batch_result(batch_result)
|
371
|
-
rescue GRPC::Core::CallError => e
|
372
|
-
finished # checks for Cancelled
|
373
|
-
raise e
|
374
421
|
end
|
375
422
|
|
376
423
|
# server_streamer sends one request to the GRPC server, which yields a
|
@@ -388,6 +435,7 @@ module GRPC
|
|
388
435
|
# a list, multiple metadata for its key are sent
|
389
436
|
# @return [Enumerator|nil] a response Enumerator
|
390
437
|
def server_streamer(req, metadata: {})
|
438
|
+
raise_error_if_already_executed
|
391
439
|
ops = {
|
392
440
|
SEND_MESSAGE => @marshal.call(req),
|
393
441
|
SEND_CLOSE_FROM_CLIENT => nil
|
@@ -399,13 +447,22 @@ module GRPC
|
|
399
447
|
end
|
400
448
|
@metadata_sent = true
|
401
449
|
end
|
402
|
-
|
450
|
+
|
451
|
+
begin
|
452
|
+
@call.run_batch(ops)
|
453
|
+
rescue GRPC::Core::CallError => e
|
454
|
+
receive_and_check_status # checks for Cancelled
|
455
|
+
raise e
|
456
|
+
rescue => e
|
457
|
+
set_input_stream_done
|
458
|
+
raise e
|
459
|
+
ensure
|
460
|
+
set_output_stream_done
|
461
|
+
end
|
462
|
+
|
403
463
|
replies = enum_for(:each_remote_read_then_finish)
|
404
464
|
return replies unless block_given?
|
405
465
|
replies.each { |r| yield r }
|
406
|
-
rescue GRPC::Core::CallError => e
|
407
|
-
finished # checks for Cancelled
|
408
|
-
raise e
|
409
466
|
end
|
410
467
|
|
411
468
|
# bidi_streamer sends a stream of requests to the GRPC server, and yields
|
@@ -436,6 +493,7 @@ module GRPC
|
|
436
493
|
# a list, multiple metadata for its key are sent
|
437
494
|
# @return [Enumerator, nil] a response Enumerator
|
438
495
|
def bidi_streamer(requests, metadata: {}, &blk)
|
496
|
+
raise_error_if_already_executed
|
439
497
|
# Metadata might have already been sent if this is an operation view
|
440
498
|
merge_metadata_and_send_if_not_already_sent(metadata)
|
441
499
|
bd = BidiCall.new(@call,
|
@@ -443,7 +501,10 @@ module GRPC
|
|
443
501
|
@unmarshal,
|
444
502
|
metadata_received: @metadata_received)
|
445
503
|
|
446
|
-
bd.run_on_client(requests,
|
504
|
+
bd.run_on_client(requests,
|
505
|
+
proc { set_input_stream_done },
|
506
|
+
proc { set_output_stream_done },
|
507
|
+
&blk)
|
447
508
|
end
|
448
509
|
|
449
510
|
# run_server_bidi orchestrates a BiDi stream processing on a server.
|
@@ -464,7 +525,7 @@ module GRPC
|
|
464
525
|
metadata_received: @metadata_received,
|
465
526
|
req_view: MultiReqView.new(self))
|
466
527
|
|
467
|
-
bd.run_on_server(gen_each_reply)
|
528
|
+
bd.run_on_server(gen_each_reply, proc { set_input_stream_done })
|
468
529
|
end
|
469
530
|
|
470
531
|
# Waits till an operation completes
|
@@ -474,7 +535,8 @@ module GRPC
|
|
474
535
|
@op_notifier.wait
|
475
536
|
end
|
476
537
|
|
477
|
-
# Signals that an operation is done
|
538
|
+
# Signals that an operation is done.
|
539
|
+
# Only relevant on the client-side (this is a no-op on the server-side)
|
478
540
|
def op_is_done
|
479
541
|
return if @op_notifier.nil?
|
480
542
|
@op_notifier.notify(self)
|
@@ -499,8 +561,40 @@ module GRPC
|
|
499
561
|
end
|
500
562
|
end
|
501
563
|
|
564
|
+
def attach_peer_cert(peer_cert)
|
565
|
+
@peer_cert = peer_cert
|
566
|
+
end
|
567
|
+
|
502
568
|
private
|
503
569
|
|
570
|
+
# To be called once the "input stream" has been completelly
|
571
|
+
# read through (i.e, done reading from client or received status)
|
572
|
+
# note this is idempotent
|
573
|
+
def set_input_stream_done
|
574
|
+
@call_finished_mu.synchronize do
|
575
|
+
@input_stream_done = true
|
576
|
+
maybe_finish_and_close_call_locked
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
# To be called once the "output stream" has been completelly
|
581
|
+
# sent through (i.e, done sending from client or sent status)
|
582
|
+
# note this is idempotent
|
583
|
+
def set_output_stream_done
|
584
|
+
@call_finished_mu.synchronize do
|
585
|
+
@output_stream_done = true
|
586
|
+
maybe_finish_and_close_call_locked
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
def maybe_finish_and_close_call_locked
|
591
|
+
return unless @output_stream_done && @input_stream_done
|
592
|
+
return if @call_finished
|
593
|
+
@call_finished = true
|
594
|
+
op_is_done
|
595
|
+
@call.close
|
596
|
+
end
|
597
|
+
|
504
598
|
# Starts the call if not already started
|
505
599
|
# @param metadata [Hash] metadata to be sent to the server. If a value is
|
506
600
|
# a list, multiple metadata for its key are sent
|
@@ -508,6 +602,15 @@ module GRPC
|
|
508
602
|
merge_metadata_to_send(metadata) && send_initial_metadata
|
509
603
|
end
|
510
604
|
|
605
|
+
def raise_error_if_already_executed
|
606
|
+
@client_call_executed_mu.synchronize do
|
607
|
+
if @client_call_executed
|
608
|
+
fail GRPC::Core::CallError, 'attempting to re-run a call'
|
609
|
+
end
|
610
|
+
@client_call_executed = true
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
511
614
|
def self.view_class(*visible_methods)
|
512
615
|
Class.new do
|
513
616
|
extend ::Forwardable
|
@@ -533,6 +636,7 @@ module GRPC
|
|
533
636
|
# server client_streamer handlers.
|
534
637
|
MultiReqView = view_class(:cancelled?, :deadline, :each_queued_msg,
|
535
638
|
:each_remote_read, :metadata, :output_metadata,
|
639
|
+
:peer, :peer_cert,
|
536
640
|
:send_initial_metadata,
|
537
641
|
:metadata_to_send,
|
538
642
|
:merge_metadata_to_send,
|