grpc 1.4.1 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,
         |