grpc 0.13.0.pre1.1-universal-darwin

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/etc/roots.pem +5114 -0
  3. data/grpc_c.32.ruby +0 -0
  4. data/grpc_c.64.ruby +0 -0
  5. data/src/ruby/bin/apis/google/protobuf/empty.rb +44 -0
  6. data/src/ruby/bin/apis/pubsub_demo.rb +256 -0
  7. data/src/ruby/bin/apis/tech/pubsub/proto/pubsub.rb +174 -0
  8. data/src/ruby/bin/apis/tech/pubsub/proto/pubsub_services.rb +103 -0
  9. data/src/ruby/bin/grpc_ruby_interop_client +33 -0
  10. data/src/ruby/bin/grpc_ruby_interop_server +33 -0
  11. data/src/ruby/bin/interop/interop_client.rb +51 -0
  12. data/src/ruby/bin/interop/interop_server.rb +50 -0
  13. data/src/ruby/bin/math.rb +32 -0
  14. data/src/ruby/bin/math_client.rb +147 -0
  15. data/src/ruby/bin/math_server.rb +206 -0
  16. data/src/ruby/bin/math_services.rb +27 -0
  17. data/src/ruby/bin/noproto_client.rb +108 -0
  18. data/src/ruby/bin/noproto_server.rb +112 -0
  19. data/src/ruby/ext/grpc/extconf.rb +129 -0
  20. data/src/ruby/ext/grpc/rb_byte_buffer.c +70 -0
  21. data/src/ruby/ext/grpc/rb_byte_buffer.h +47 -0
  22. data/src/ruby/ext/grpc/rb_call.c +908 -0
  23. data/src/ruby/ext/grpc/rb_call.h +66 -0
  24. data/src/ruby/ext/grpc/rb_call_credentials.c +319 -0
  25. data/src/ruby/ext/grpc/rb_call_credentials.h +46 -0
  26. data/src/ruby/ext/grpc/rb_channel.c +432 -0
  27. data/src/ruby/ext/grpc/rb_channel.h +47 -0
  28. data/src/ruby/ext/grpc/rb_channel_args.c +169 -0
  29. data/src/ruby/ext/grpc/rb_channel_args.h +53 -0
  30. data/src/ruby/ext/grpc/rb_channel_credentials.c +268 -0
  31. data/src/ruby/ext/grpc/rb_channel_credentials.h +47 -0
  32. data/src/ruby/ext/grpc/rb_completion_queue.c +183 -0
  33. data/src/ruby/ext/grpc/rb_completion_queue.h +55 -0
  34. data/src/ruby/ext/grpc/rb_event_thread.c +158 -0
  35. data/src/ruby/ext/grpc/rb_event_thread.h +37 -0
  36. data/src/ruby/ext/grpc/rb_grpc.c +336 -0
  37. data/src/ruby/ext/grpc/rb_grpc.h +85 -0
  38. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +560 -0
  39. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +843 -0
  40. data/src/ruby/ext/grpc/rb_loader.c +72 -0
  41. data/src/ruby/ext/grpc/rb_loader.h +40 -0
  42. data/src/ruby/ext/grpc/rb_server.c +400 -0
  43. data/src/ruby/ext/grpc/rb_server.h +47 -0
  44. data/src/ruby/ext/grpc/rb_server_credentials.c +284 -0
  45. data/src/ruby/ext/grpc/rb_server_credentials.h +47 -0
  46. data/src/ruby/lib/grpc.rb +44 -0
  47. data/src/ruby/lib/grpc/2.0/grpc_c.bundle +0 -0
  48. data/src/ruby/lib/grpc/2.1/grpc_c.bundle +0 -0
  49. data/src/ruby/lib/grpc/2.2/grpc_c.bundle +0 -0
  50. data/src/ruby/lib/grpc/2.3/grpc_c.bundle +0 -0
  51. data/src/ruby/lib/grpc/core/time_consts.rb +71 -0
  52. data/src/ruby/lib/grpc/errors.rb +62 -0
  53. data/src/ruby/lib/grpc/generic/active_call.rb +488 -0
  54. data/src/ruby/lib/grpc/generic/bidi_call.rb +218 -0
  55. data/src/ruby/lib/grpc/generic/client_stub.rb +471 -0
  56. data/src/ruby/lib/grpc/generic/rpc_desc.rb +147 -0
  57. data/src/ruby/lib/grpc/generic/rpc_server.rb +504 -0
  58. data/src/ruby/lib/grpc/generic/service.rb +234 -0
  59. data/src/ruby/lib/grpc/grpc.rb +34 -0
  60. data/src/ruby/lib/grpc/logconfig.rb +59 -0
  61. data/src/ruby/lib/grpc/notifier.rb +60 -0
  62. data/src/ruby/lib/grpc/version.rb +33 -0
  63. data/src/ruby/pb/README.md +42 -0
  64. data/src/ruby/pb/generate_proto_ruby.sh +51 -0
  65. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  66. data/src/ruby/pb/grpc/health/v1alpha/health.rb +29 -0
  67. data/src/ruby/pb/grpc/health/v1alpha/health_services.rb +28 -0
  68. data/src/ruby/pb/test/client.rb +469 -0
  69. data/src/ruby/pb/test/proto/empty.rb +15 -0
  70. data/src/ruby/pb/test/proto/messages.rb +80 -0
  71. data/src/ruby/pb/test/proto/test.rb +14 -0
  72. data/src/ruby/pb/test/proto/test_services.rb +64 -0
  73. data/src/ruby/pb/test/server.rb +253 -0
  74. data/src/ruby/spec/call_credentials_spec.rb +57 -0
  75. data/src/ruby/spec/call_spec.rb +163 -0
  76. data/src/ruby/spec/channel_credentials_spec.rb +97 -0
  77. data/src/ruby/spec/channel_spec.rb +177 -0
  78. data/src/ruby/spec/client_server_spec.rb +475 -0
  79. data/src/ruby/spec/completion_queue_spec.rb +42 -0
  80. data/src/ruby/spec/generic/active_call_spec.rb +373 -0
  81. data/src/ruby/spec/generic/client_stub_spec.rb +476 -0
  82. data/src/ruby/spec/generic/rpc_desc_spec.rb +331 -0
  83. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +138 -0
  84. data/src/ruby/spec/generic/rpc_server_spec.rb +576 -0
  85. data/src/ruby/spec/generic/service_spec.rb +345 -0
  86. data/src/ruby/spec/pb/health/checker_spec.rb +232 -0
  87. data/src/ruby/spec/server_credentials_spec.rb +94 -0
  88. data/src/ruby/spec/server_spec.rb +209 -0
  89. data/src/ruby/spec/spec_helper.rb +69 -0
  90. data/src/ruby/spec/testdata/README +1 -0
  91. data/src/ruby/spec/testdata/ca.pem +15 -0
  92. data/src/ruby/spec/testdata/server1.key +16 -0
  93. data/src/ruby/spec/testdata/server1.pem +16 -0
  94. data/src/ruby/spec/time_consts_spec.rb +89 -0
  95. metadata +319 -0
@@ -0,0 +1,129 @@
1
+ # Copyright 2015-2016, Google Inc.
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are
6
+ # met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright
9
+ # notice, this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above
11
+ # copyright notice, this list of conditions and the following disclaimer
12
+ # in the documentation and/or other materials provided with the
13
+ # distribution.
14
+ # * Neither the name of Google Inc. nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'mkmf'
31
+
32
+ LIBDIR = RbConfig::CONFIG['libdir']
33
+ INCLUDEDIR = RbConfig::CONFIG['includedir']
34
+
35
+ HEADER_DIRS = [
36
+ # Search /opt/local (Mac source install)
37
+ '/opt/local/include',
38
+
39
+ # Search /usr/local (Source install)
40
+ '/usr/local/include',
41
+
42
+ # Check the ruby install locations
43
+ INCLUDEDIR
44
+ ]
45
+
46
+ LIB_DIRS = [
47
+ # Search /opt/local (Mac source install)
48
+ '/opt/local/lib',
49
+
50
+ # Search /usr/local (Source install)
51
+ '/usr/local/lib',
52
+
53
+ # Check the ruby install locations
54
+ LIBDIR
55
+ ]
56
+
57
+ windows = RUBY_PLATFORM =~ /mingw|mswin/
58
+
59
+ grpc_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
60
+
61
+ grpc_config = ENV['GRPC_CONFIG'] || 'opt'
62
+
63
+ if ENV.key?('GRPC_LIB_DIR')
64
+ grpc_lib_dir = File.join(grpc_root, ENV['GRPC_LIB_DIR'])
65
+ else
66
+ grpc_lib_dir = File.join(grpc_root, 'libs', grpc_config)
67
+ end
68
+
69
+ ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
70
+
71
+ unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a')) or windows
72
+ ENV['AR'] = RbConfig::CONFIG['AR'] + ' rcs'
73
+ ENV['CC'] = RbConfig::CONFIG['CC']
74
+ ENV['LD'] = ENV['CC']
75
+
76
+ ENV['AR'] = 'libtool -o' if RUBY_PLATFORM =~ /darwin/
77
+
78
+ ENV['EMBED_OPENSSL'] = 'true'
79
+ ENV['EMBED_ZLIB'] = 'true'
80
+ ENV['ARCH_FLAGS'] = RbConfig::CONFIG['ARCH_FLAG']
81
+ ENV['ARCH_FLAGS'] = '-arch i386 -arch x86_64' if RUBY_PLATFORM =~ /darwin/
82
+
83
+ output_dir = File.expand_path(RbConfig::CONFIG['topdir'])
84
+ grpc_lib_dir = File.join(output_dir, 'libs', grpc_config)
85
+ ENV['BUILDDIR'] = output_dir
86
+
87
+ puts 'Building internal gRPC into ' + grpc_lib_dir
88
+ system("make -j -C #{grpc_root} #{grpc_lib_dir}/libgrpc.a CONFIG=#{grpc_config}")
89
+ exit 1 unless $? == 0
90
+ end
91
+
92
+ $CFLAGS << ' -I' + File.join(grpc_root, 'include')
93
+ $LDFLAGS << ' ' + File.join(grpc_lib_dir, 'libgrpc.a') unless windows
94
+ if grpc_config == 'gcov'
95
+ $CFLAGS << ' -O0 -fprofile-arcs -ftest-coverage'
96
+ $LDFLAGS << ' -fprofile-arcs -ftest-coverage -rdynamic'
97
+ end
98
+
99
+ $LDFLAGS << ' -Wl,-wrap,memcpy' if RUBY_PLATFORM =~ /linux/
100
+ $LDFLAGS << ' -static' if windows
101
+
102
+ $CFLAGS << ' -std=c99 '
103
+ $CFLAGS << ' -Wall '
104
+ $CFLAGS << ' -Wextra '
105
+ $CFLAGS << ' -pedantic '
106
+ $CFLAGS << ' -Werror '
107
+ $CFLAGS << ' -Wno-format '
108
+
109
+ output = File.join('grpc', 'grpc_c')
110
+ puts 'Generating Makefile for ' + output
111
+ create_makefile(output)
112
+
113
+ strip_tool = RbConfig::CONFIG['STRIP']
114
+ strip_tool = 'strip -x' if RUBY_PLATFORM =~ /darwin/
115
+
116
+ if grpc_config == 'opt'
117
+ File.open('Makefile.new', 'w') do |o|
118
+ o.puts 'hijack: all strip'
119
+ o.puts
120
+ File.foreach('Makefile') do |i|
121
+ o.puts i
122
+ end
123
+ o.puts
124
+ o.puts 'strip:'
125
+ o.puts "\t$(ECHO) Stripping $(DLLIB)"
126
+ o.puts "\t$(Q) #{strip_tool} $(DLLIB)"
127
+ end
128
+ File.rename('Makefile.new', 'Makefile')
129
+ end
@@ -0,0 +1,70 @@
1
+ /*
2
+ *
3
+ * Copyright 2015-2016, Google Inc.
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are
8
+ * met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright
11
+ * notice, this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above
13
+ * copyright notice, this list of conditions and the following disclaimer
14
+ * in the documentation and/or other materials provided with the
15
+ * distribution.
16
+ * * Neither the name of Google Inc. nor the names of its
17
+ * contributors may be used to endorse or promote products derived from
18
+ * this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *
32
+ */
33
+
34
+ #include <ruby/ruby.h>
35
+ #include "rb_grpc_imports.generated.h"
36
+ #include "rb_byte_buffer.h"
37
+
38
+ #include <ruby/ruby.h>
39
+
40
+ #include <grpc/grpc.h>
41
+ #include <grpc/byte_buffer_reader.h>
42
+ #include <grpc/support/slice.h>
43
+ #include "rb_grpc.h"
44
+
45
+ grpc_byte_buffer* grpc_rb_s_to_byte_buffer(char *string, size_t length) {
46
+ gpr_slice slice = gpr_slice_from_copied_buffer(string, length);
47
+ grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1);
48
+ gpr_slice_unref(slice);
49
+ return buffer;
50
+ }
51
+
52
+ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
53
+ size_t length = 0;
54
+ char *string = NULL;
55
+ size_t offset = 0;
56
+ grpc_byte_buffer_reader reader;
57
+ gpr_slice next;
58
+ if (buffer == NULL) {
59
+ return Qnil;
60
+
61
+ }
62
+ length = grpc_byte_buffer_length(buffer);
63
+ string = xmalloc(length + 1);
64
+ grpc_byte_buffer_reader_init(&reader, buffer);
65
+ while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
66
+ memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
67
+ offset += GPR_SLICE_LENGTH(next);
68
+ }
69
+ return rb_str_new(string, length);
70
+ }
@@ -0,0 +1,47 @@
1
+ /*
2
+ *
3
+ * Copyright 2015, Google Inc.
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are
8
+ * met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright
11
+ * notice, this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above
13
+ * copyright notice, this list of conditions and the following disclaimer
14
+ * in the documentation and/or other materials provided with the
15
+ * distribution.
16
+ * * Neither the name of Google Inc. nor the names of its
17
+ * contributors may be used to endorse or promote products derived from
18
+ * this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *
32
+ */
33
+
34
+ #ifndef GRPC_RB_BYTE_BUFFER_H_
35
+ #define GRPC_RB_BYTE_BUFFER_H_
36
+
37
+ #include <ruby/ruby.h>
38
+
39
+ #include <grpc/grpc.h>
40
+
41
+ /* Converts a char* with a length to a grpc_byte_buffer */
42
+ grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length);
43
+
44
+ /* Converts a grpc_byte_buffer to a ruby string */
45
+ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer);
46
+
47
+ #endif /* GRPC_RB_BYTE_BUFFER_H_ */
@@ -0,0 +1,908 @@
1
+ /*
2
+ *
3
+ * Copyright 2015-2016, Google Inc.
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are
8
+ * met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright
11
+ * notice, this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above
13
+ * copyright notice, this list of conditions and the following disclaimer
14
+ * in the documentation and/or other materials provided with the
15
+ * distribution.
16
+ * * Neither the name of Google Inc. nor the names of its
17
+ * contributors may be used to endorse or promote products derived from
18
+ * this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *
32
+ */
33
+
34
+ #include <ruby/ruby.h>
35
+ #include "rb_grpc_imports.generated.h"
36
+ #include "rb_call.h"
37
+
38
+ #include <ruby/ruby.h>
39
+
40
+ #include <grpc/grpc.h>
41
+ #include <grpc/support/alloc.h>
42
+
43
+ #include "rb_byte_buffer.h"
44
+ #include "rb_call_credentials.h"
45
+ #include "rb_completion_queue.h"
46
+ #include "rb_grpc.h"
47
+
48
+ /* grpc_rb_cCall is the Call class whose instances proxy grpc_call. */
49
+ static VALUE grpc_rb_cCall;
50
+
51
+ /* grpc_rb_eCallError is the ruby class of the exception thrown during call
52
+ operations; */
53
+ VALUE grpc_rb_eCallError = Qnil;
54
+
55
+ /* grpc_rb_eOutOfTime is the ruby class of the exception thrown to indicate
56
+ a timeout. */
57
+ static VALUE grpc_rb_eOutOfTime = Qnil;
58
+
59
+ /* grpc_rb_sBatchResult is struct class used to hold the results of a batch
60
+ * call. */
61
+ static VALUE grpc_rb_sBatchResult;
62
+
63
+ /* grpc_rb_cMdAry is the MetadataArray class whose instances proxy
64
+ * grpc_metadata_array. */
65
+ static VALUE grpc_rb_cMdAry;
66
+
67
+ /* id_cq is the name of the hidden ivar that preserves a reference to a
68
+ * completion queue */
69
+ static ID id_cq;
70
+
71
+ /* id_flags is the name of the hidden ivar that preserves the value of
72
+ * the flags used to create metadata from a Hash */
73
+ static ID id_flags;
74
+
75
+ /* id_input_md is the name of the hidden ivar that preserves the hash used to
76
+ * create metadata, so that references to the strings it contains last as long
77
+ * as the call the metadata is added to. */
78
+ static ID id_input_md;
79
+
80
+ /* id_metadata is name of the attribute used to access the metadata hash
81
+ * received by the call and subsequently saved on it. */
82
+ static ID id_metadata;
83
+
84
+ /* id_status is name of the attribute used to access the status object
85
+ * received by the call and subsequently saved on it. */
86
+ static ID id_status;
87
+
88
+ /* id_write_flag is name of the attribute used to access the write_flag
89
+ * saved on the call. */
90
+ static ID id_write_flag;
91
+
92
+ /* sym_* are the symbol for attributes of grpc_rb_sBatchResult. */
93
+ static VALUE sym_send_message;
94
+ static VALUE sym_send_metadata;
95
+ static VALUE sym_send_close;
96
+ static VALUE sym_send_status;
97
+ static VALUE sym_message;
98
+ static VALUE sym_status;
99
+ static VALUE sym_cancelled;
100
+
101
+ /* hash_all_calls is a hash of Call address -> reference count that is used to
102
+ * track the creation and destruction of rb_call instances.
103
+ */
104
+ static VALUE hash_all_calls;
105
+
106
+ /* Destroys a Call. */
107
+ static void grpc_rb_call_destroy(void *p) {
108
+ grpc_call *call = NULL;
109
+ VALUE ref_count = Qnil;
110
+ if (p == NULL) {
111
+ return;
112
+ };
113
+ call = (grpc_call *)p;
114
+
115
+ ref_count = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)call));
116
+ if (ref_count == Qnil) {
117
+ return; /* No longer in the hash, so already deleted */
118
+ } else if (NUM2UINT(ref_count) == 1) {
119
+ rb_hash_delete(hash_all_calls, OFFT2NUM((VALUE)call));
120
+ grpc_call_destroy(call);
121
+ } else {
122
+ rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)call),
123
+ UINT2NUM(NUM2UINT(ref_count) - 1));
124
+ }
125
+ }
126
+
127
+ static size_t md_ary_datasize(const void *p) {
128
+ const grpc_metadata_array *const ary = (grpc_metadata_array *)p;
129
+ size_t i, datasize = sizeof(grpc_metadata_array);
130
+ for (i = 0; i < ary->count; ++i) {
131
+ const grpc_metadata *const md = &ary->metadata[i];
132
+ datasize += strlen(md->key);
133
+ datasize += md->value_length;
134
+ }
135
+ datasize += ary->capacity * sizeof(grpc_metadata);
136
+ return datasize;
137
+ }
138
+
139
+ static const rb_data_type_t grpc_rb_md_ary_data_type = {
140
+ "grpc_metadata_array",
141
+ {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize,
142
+ {NULL, NULL}},
143
+ NULL,
144
+ NULL,
145
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
146
+ /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
147
+ * grpc_rb_call_destroy
148
+ * touches a hash object.
149
+ * TODO(yugui) Directly use st_table and call the free function earlier?
150
+ */
151
+ 0,
152
+ #endif
153
+ };
154
+
155
+ /* Describes grpc_call struct for RTypedData */
156
+ static const rb_data_type_t grpc_call_data_type = {
157
+ "grpc_call",
158
+ {GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE,
159
+ {NULL, NULL}},
160
+ NULL,
161
+ NULL,
162
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
163
+ /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
164
+ * grpc_rb_call_destroy
165
+ * touches a hash object.
166
+ * TODO(yugui) Directly use st_table and call the free function earlier?
167
+ */
168
+ 0,
169
+ #endif
170
+ };
171
+
172
+ /* Error code details is a hash containing text strings describing errors */
173
+ VALUE rb_error_code_details;
174
+
175
+ /* Obtains the error detail string for given error code */
176
+ const char *grpc_call_error_detail_of(grpc_call_error err) {
177
+ VALUE detail_ref = rb_hash_aref(rb_error_code_details, UINT2NUM(err));
178
+ const char *detail = "unknown error code!";
179
+ if (detail_ref != Qnil) {
180
+ detail = StringValueCStr(detail_ref);
181
+ }
182
+ return detail;
183
+ }
184
+
185
+ /* Called by clients to cancel an RPC on the server.
186
+ Can be called multiple times, from any thread. */
187
+ static VALUE grpc_rb_call_cancel(VALUE self) {
188
+ grpc_call *call = NULL;
189
+ grpc_call_error err;
190
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
191
+ err = grpc_call_cancel(call, NULL);
192
+ if (err != GRPC_CALL_OK) {
193
+ rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)",
194
+ grpc_call_error_detail_of(err), err);
195
+ }
196
+
197
+ return Qnil;
198
+ }
199
+
200
+ /* Called to obtain the peer that this call is connected to. */
201
+ static VALUE grpc_rb_call_get_peer(VALUE self) {
202
+ VALUE res = Qnil;
203
+ grpc_call *call = NULL;
204
+ char *peer = NULL;
205
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
206
+ peer = grpc_call_get_peer(call);
207
+ res = rb_str_new2(peer);
208
+ gpr_free(peer);
209
+
210
+ return res;
211
+ }
212
+
213
+ /*
214
+ call-seq:
215
+ status = call.status
216
+
217
+ Gets the status object saved the call. */
218
+ static VALUE grpc_rb_call_get_status(VALUE self) {
219
+ return rb_ivar_get(self, id_status);
220
+ }
221
+
222
+ /*
223
+ call-seq:
224
+ call.status = status
225
+
226
+ Saves a status object on the call. */
227
+ static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
228
+ if (!NIL_P(status) && rb_obj_class(status) != grpc_rb_sStatus) {
229
+ rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Struct::Status>",
230
+ rb_obj_classname(status));
231
+ return Qnil;
232
+ }
233
+
234
+ return rb_ivar_set(self, id_status, status);
235
+ }
236
+
237
+ /*
238
+ call-seq:
239
+ metadata = call.metadata
240
+
241
+ Gets the metadata object saved the call. */
242
+ static VALUE grpc_rb_call_get_metadata(VALUE self) {
243
+ return rb_ivar_get(self, id_metadata);
244
+ }
245
+
246
+ /*
247
+ call-seq:
248
+ call.metadata = metadata
249
+
250
+ Saves the metadata hash on the call. */
251
+ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
252
+ if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) {
253
+ rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: <Hash>",
254
+ rb_obj_classname(metadata));
255
+ return Qnil;
256
+ }
257
+
258
+ return rb_ivar_set(self, id_metadata, metadata);
259
+ }
260
+
261
+ /*
262
+ call-seq:
263
+ write_flag = call.write_flag
264
+
265
+ Gets the write_flag value saved the call. */
266
+ static VALUE grpc_rb_call_get_write_flag(VALUE self) {
267
+ return rb_ivar_get(self, id_write_flag);
268
+ }
269
+
270
+ /*
271
+ call-seq:
272
+ call.write_flag = write_flag
273
+
274
+ Saves the write_flag on the call. */
275
+ static VALUE grpc_rb_call_set_write_flag(VALUE self, VALUE write_flag) {
276
+ if (!NIL_P(write_flag) && TYPE(write_flag) != T_FIXNUM) {
277
+ rb_raise(rb_eTypeError, "bad write_flag: got:<%s> want: <Fixnum>",
278
+ rb_obj_classname(write_flag));
279
+ return Qnil;
280
+ }
281
+
282
+ return rb_ivar_set(self, id_write_flag, write_flag);
283
+ }
284
+
285
+ /*
286
+ call-seq:
287
+ call.set_credentials call_credentials
288
+
289
+ Sets credentials on a call */
290
+ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
291
+ grpc_call *call = NULL;
292
+ grpc_call_credentials *creds;
293
+ grpc_call_error err;
294
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
295
+ creds = grpc_rb_get_wrapped_call_credentials(credentials);
296
+ err = grpc_call_set_credentials(call, creds);
297
+ if (err != GRPC_CALL_OK) {
298
+ rb_raise(grpc_rb_eCallError,
299
+ "grpc_call_set_credentials failed with %s (code=%d)",
300
+ grpc_call_error_detail_of(err), err);
301
+ }
302
+ return Qnil;
303
+ }
304
+
305
+ /* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used
306
+ to fill grpc_metadata_array.
307
+
308
+ it's capacity should have been computed via a prior call to
309
+ grpc_rb_md_ary_fill_hash_cb
310
+ */
311
+ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
312
+ grpc_metadata_array *md_ary = NULL;
313
+ long array_length;
314
+ long i;
315
+ char *key_str;
316
+ size_t key_len;
317
+ char *value_str;
318
+ size_t value_len;
319
+
320
+ if (TYPE(key) == T_SYMBOL) {
321
+ key_str = (char *)rb_id2name(SYM2ID(key));
322
+ key_len = strlen(key_str);
323
+ } else { /* StringValueCStr does all other type exclusions for us */
324
+ key_str = StringValueCStr(key);
325
+ key_len = RSTRING_LEN(key);
326
+ }
327
+
328
+ if (!grpc_header_key_is_legal(key_str, key_len)) {
329
+ rb_raise(rb_eArgError,
330
+ "'%s' is an invalid header key, must match [a-z0-9-_.]+",
331
+ key_str);
332
+ return ST_STOP;
333
+ }
334
+
335
+ /* Construct a metadata object from key and value and add it */
336
+ TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
337
+ &grpc_rb_md_ary_data_type, md_ary);
338
+
339
+ if (TYPE(val) == T_ARRAY) {
340
+ array_length = RARRAY_LEN(val);
341
+ /* If the value is an array, add capacity for each value in the array */
342
+ for (i = 0; i < array_length; i++) {
343
+ value_str = RSTRING_PTR(rb_ary_entry(val, i));
344
+ value_len = RSTRING_LEN(rb_ary_entry(val, i));
345
+ if (!grpc_is_binary_header(key_str, key_len) &&
346
+ !grpc_header_nonbin_value_is_legal(value_str, value_len)) {
347
+ // The value has invalid characters
348
+ rb_raise(rb_eArgError,
349
+ "Header value '%s' has invalid characters", value_str);
350
+ return ST_STOP;
351
+ }
352
+ md_ary->metadata[md_ary->count].key = key_str;
353
+ md_ary->metadata[md_ary->count].value = value_str;
354
+ md_ary->metadata[md_ary->count].value_length = value_len;
355
+ md_ary->count += 1;
356
+ }
357
+ } else {
358
+ value_str = RSTRING_PTR(val);
359
+ value_len = RSTRING_LEN(val);
360
+ if (!grpc_is_binary_header(key_str, key_len) &&
361
+ !grpc_header_nonbin_value_is_legal(value_str, value_len)) {
362
+ // The value has invalid characters
363
+ rb_raise(rb_eArgError,
364
+ "Header value '%s' has invalid characters", value_str);
365
+ return ST_STOP;
366
+ }
367
+ md_ary->metadata[md_ary->count].key = key_str;
368
+ md_ary->metadata[md_ary->count].value = value_str;
369
+ md_ary->metadata[md_ary->count].value_length = value_len;
370
+ md_ary->count += 1;
371
+ }
372
+
373
+ return ST_CONTINUE;
374
+ }
375
+
376
+ /* grpc_rb_md_ary_capacity_hash_cb is the hash iteration callback used
377
+ to pre-compute the capacity a grpc_metadata_array.
378
+ */
379
+ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val,
380
+ VALUE md_ary_obj) {
381
+ grpc_metadata_array *md_ary = NULL;
382
+
383
+ (void)key;
384
+
385
+ /* Construct a metadata object from key and value and add it */
386
+ TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
387
+ &grpc_rb_md_ary_data_type, md_ary);
388
+
389
+ if (TYPE(val) == T_ARRAY) {
390
+ /* If the value is an array, add capacity for each value in the array */
391
+ md_ary->capacity += RARRAY_LEN(val);
392
+ } else {
393
+ md_ary->capacity += 1;
394
+ }
395
+ return ST_CONTINUE;
396
+ }
397
+
398
+ /* grpc_rb_md_ary_convert converts a ruby metadata hash into
399
+ a grpc_metadata_array.
400
+ */
401
+ void grpc_rb_md_ary_convert(VALUE md_ary_hash,
402
+ grpc_metadata_array *md_ary) {
403
+ VALUE md_ary_obj = Qnil;
404
+ if (md_ary_hash == Qnil) {
405
+ return; /* Do nothing if the expected has value is nil */
406
+ }
407
+ if (TYPE(md_ary_hash) != T_HASH) {
408
+ rb_raise(rb_eTypeError, "md_ary_convert: got <%s>, want <Hash>",
409
+ rb_obj_classname(md_ary_hash));
410
+ return;
411
+ }
412
+
413
+ /* Initialize the array, compute it's capacity, then fill it. */
414
+ grpc_metadata_array_init(md_ary);
415
+ md_ary_obj =
416
+ TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary);
417
+ rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj);
418
+ md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata));
419
+ rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj);
420
+ }
421
+
422
+ /* Converts a metadata array to a hash. */
423
+ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary) {
424
+ VALUE key = Qnil;
425
+ VALUE new_ary = Qnil;
426
+ VALUE value = Qnil;
427
+ VALUE result = rb_hash_new();
428
+ size_t i;
429
+
430
+ for (i = 0; i < md_ary->count; i++) {
431
+ key = rb_str_new2(md_ary->metadata[i].key);
432
+ value = rb_hash_aref(result, key);
433
+ if (value == Qnil) {
434
+ value = rb_str_new(md_ary->metadata[i].value,
435
+ md_ary->metadata[i].value_length);
436
+ rb_hash_aset(result, key, value);
437
+ } else if (TYPE(value) == T_ARRAY) {
438
+ /* Add the string to the returned array */
439
+ rb_ary_push(value, rb_str_new(md_ary->metadata[i].value,
440
+ md_ary->metadata[i].value_length));
441
+ } else {
442
+ /* Add the current value with this key and the new one to an array */
443
+ new_ary = rb_ary_new();
444
+ rb_ary_push(new_ary, value);
445
+ rb_ary_push(new_ary, rb_str_new(md_ary->metadata[i].value,
446
+ md_ary->metadata[i].value_length));
447
+ rb_hash_aset(result, key, new_ary);
448
+ }
449
+ }
450
+ return result;
451
+ }
452
+
453
+ /* grpc_rb_call_check_op_keys_hash_cb is a hash iteration func that checks
454
+ each key of an ops hash is valid.
455
+ */
456
+ static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val,
457
+ VALUE ops_ary) {
458
+ (void)val;
459
+ /* Update the capacity; the value is an array, add capacity for each value in
460
+ * the array */
461
+ if (TYPE(key) != T_FIXNUM) {
462
+ rb_raise(rb_eTypeError, "invalid operation : got <%s>, want <Fixnum>",
463
+ rb_obj_classname(key));
464
+ return ST_STOP;
465
+ }
466
+ switch (NUM2INT(key)) {
467
+ case GRPC_OP_SEND_INITIAL_METADATA:
468
+ case GRPC_OP_SEND_MESSAGE:
469
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
470
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
471
+ case GRPC_OP_RECV_INITIAL_METADATA:
472
+ case GRPC_OP_RECV_MESSAGE:
473
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
474
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
475
+ rb_ary_push(ops_ary, key);
476
+ return ST_CONTINUE;
477
+ default:
478
+ rb_raise(rb_eTypeError, "invalid operation : bad value %d", NUM2INT(key));
479
+ };
480
+ return ST_STOP;
481
+ }
482
+
483
+ /* grpc_rb_op_update_status_from_server adds the values in a ruby status
484
+ struct to the 'send_status_from_server' portion of an op.
485
+ */
486
+ static void grpc_rb_op_update_status_from_server(grpc_op *op,
487
+ grpc_metadata_array *md_ary,
488
+ VALUE status) {
489
+ VALUE code = rb_struct_aref(status, sym_code);
490
+ VALUE details = rb_struct_aref(status, sym_details);
491
+ VALUE metadata_hash = rb_struct_aref(status, sym_metadata);
492
+
493
+ /* TODO: add check to ensure status is the correct struct type */
494
+ if (TYPE(code) != T_FIXNUM) {
495
+ rb_raise(rb_eTypeError, "invalid code : got <%s>, want <Fixnum>",
496
+ rb_obj_classname(code));
497
+ return;
498
+ }
499
+ if (TYPE(details) != T_STRING) {
500
+ rb_raise(rb_eTypeError, "invalid details : got <%s>, want <String>",
501
+ rb_obj_classname(code));
502
+ return;
503
+ }
504
+ op->data.send_status_from_server.status = NUM2INT(code);
505
+ op->data.send_status_from_server.status_details = StringValueCStr(details);
506
+ grpc_rb_md_ary_convert(metadata_hash, md_ary);
507
+ op->data.send_status_from_server.trailing_metadata_count = md_ary->count;
508
+ op->data.send_status_from_server.trailing_metadata = md_ary->metadata;
509
+ }
510
+
511
+ /* run_batch_stack holds various values used by the
512
+ * grpc_rb_call_run_batch function */
513
+ typedef struct run_batch_stack {
514
+ /* The batch ops */
515
+ grpc_op ops[8]; /* 8 is the maximum number of operations */
516
+ size_t op_num; /* tracks the last added operation */
517
+
518
+ /* Data being sent */
519
+ grpc_metadata_array send_metadata;
520
+ grpc_metadata_array send_trailing_metadata;
521
+
522
+ /* Data being received */
523
+ grpc_byte_buffer *recv_message;
524
+ grpc_metadata_array recv_metadata;
525
+ grpc_metadata_array recv_trailing_metadata;
526
+ int recv_cancelled;
527
+ grpc_status_code recv_status;
528
+ char *recv_status_details;
529
+ size_t recv_status_details_capacity;
530
+ unsigned write_flag;
531
+ } run_batch_stack;
532
+
533
+ /* grpc_run_batch_stack_init ensures the run_batch_stack is properly
534
+ * initialized */
535
+ static void grpc_run_batch_stack_init(run_batch_stack *st,
536
+ unsigned write_flag) {
537
+ MEMZERO(st, run_batch_stack, 1);
538
+ grpc_metadata_array_init(&st->send_metadata);
539
+ grpc_metadata_array_init(&st->send_trailing_metadata);
540
+ grpc_metadata_array_init(&st->recv_metadata);
541
+ grpc_metadata_array_init(&st->recv_trailing_metadata);
542
+ st->op_num = 0;
543
+ st->write_flag = write_flag;
544
+ }
545
+
546
+ /* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
547
+ * cleaned up */
548
+ static void grpc_run_batch_stack_cleanup(run_batch_stack *st) {
549
+ grpc_metadata_array_destroy(&st->send_metadata);
550
+ grpc_metadata_array_destroy(&st->send_trailing_metadata);
551
+ grpc_metadata_array_destroy(&st->recv_metadata);
552
+ grpc_metadata_array_destroy(&st->recv_trailing_metadata);
553
+ if (st->recv_status_details != NULL) {
554
+ gpr_free(st->recv_status_details);
555
+ }
556
+ }
557
+
558
+ /* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from
559
+ * ops_hash */
560
+ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
561
+ VALUE this_op = Qnil;
562
+ VALUE this_value = Qnil;
563
+ VALUE ops_ary = rb_ary_new();
564
+ size_t i = 0;
565
+
566
+ /* Create a ruby array with just the operation keys */
567
+ rb_hash_foreach(ops_hash, grpc_rb_call_check_op_keys_hash_cb, ops_ary);
568
+
569
+ /* Fill the ops array */
570
+ for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) {
571
+ this_op = rb_ary_entry(ops_ary, i);
572
+ this_value = rb_hash_aref(ops_hash, this_op);
573
+ st->ops[st->op_num].flags = 0;
574
+ switch (NUM2INT(this_op)) {
575
+ case GRPC_OP_SEND_INITIAL_METADATA:
576
+ /* N.B. later there is no need to explicitly delete the metadata keys
577
+ * and values, they are references to data in ruby objects. */
578
+ grpc_rb_md_ary_convert(this_value, &st->send_metadata);
579
+ st->ops[st->op_num].data.send_initial_metadata.count =
580
+ st->send_metadata.count;
581
+ st->ops[st->op_num].data.send_initial_metadata.metadata =
582
+ st->send_metadata.metadata;
583
+ break;
584
+ case GRPC_OP_SEND_MESSAGE:
585
+ st->ops[st->op_num].data.send_message = grpc_rb_s_to_byte_buffer(
586
+ RSTRING_PTR(this_value), RSTRING_LEN(this_value));
587
+ st->ops[st->op_num].flags = st->write_flag;
588
+ break;
589
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
590
+ break;
591
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
592
+ /* N.B. later there is no need to explicitly delete the metadata keys
593
+ * and values, they are references to data in ruby objects. */
594
+ grpc_rb_op_update_status_from_server(
595
+ &st->ops[st->op_num], &st->send_trailing_metadata, this_value);
596
+ break;
597
+ case GRPC_OP_RECV_INITIAL_METADATA:
598
+ st->ops[st->op_num].data.recv_initial_metadata = &st->recv_metadata;
599
+ break;
600
+ case GRPC_OP_RECV_MESSAGE:
601
+ st->ops[st->op_num].data.recv_message = &st->recv_message;
602
+ break;
603
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
604
+ st->ops[st->op_num].data.recv_status_on_client.trailing_metadata =
605
+ &st->recv_trailing_metadata;
606
+ st->ops[st->op_num].data.recv_status_on_client.status =
607
+ &st->recv_status;
608
+ st->ops[st->op_num].data.recv_status_on_client.status_details =
609
+ &st->recv_status_details;
610
+ st->ops[st->op_num].data.recv_status_on_client.status_details_capacity =
611
+ &st->recv_status_details_capacity;
612
+ break;
613
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
614
+ st->ops[st->op_num].data.recv_close_on_server.cancelled =
615
+ &st->recv_cancelled;
616
+ break;
617
+ default:
618
+ grpc_run_batch_stack_cleanup(st);
619
+ rb_raise(rb_eTypeError, "invalid operation : bad value %d",
620
+ NUM2INT(this_op));
621
+ };
622
+ st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op);
623
+ st->ops[st->op_num].reserved = NULL;
624
+ st->op_num++;
625
+ }
626
+ }
627
+
628
+ /* grpc_run_batch_stack_build_result fills constructs a ruby BatchResult struct
629
+ after the results have run */
630
+ static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) {
631
+ size_t i = 0;
632
+ VALUE result = rb_struct_new(grpc_rb_sBatchResult, Qnil, Qnil, Qnil, Qnil,
633
+ Qnil, Qnil, Qnil, Qnil, NULL);
634
+ for (i = 0; i < st->op_num; i++) {
635
+ switch (st->ops[i].op) {
636
+ case GRPC_OP_SEND_INITIAL_METADATA:
637
+ rb_struct_aset(result, sym_send_metadata, Qtrue);
638
+ break;
639
+ case GRPC_OP_SEND_MESSAGE:
640
+ rb_struct_aset(result, sym_send_message, Qtrue);
641
+ grpc_byte_buffer_destroy(st->ops[i].data.send_message);
642
+ break;
643
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
644
+ rb_struct_aset(result, sym_send_close, Qtrue);
645
+ break;
646
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
647
+ rb_struct_aset(result, sym_send_status, Qtrue);
648
+ break;
649
+ case GRPC_OP_RECV_INITIAL_METADATA:
650
+ rb_struct_aset(result, sym_metadata,
651
+ grpc_rb_md_ary_to_h(&st->recv_metadata));
652
+ case GRPC_OP_RECV_MESSAGE:
653
+ rb_struct_aset(result, sym_message,
654
+ grpc_rb_byte_buffer_to_s(st->recv_message));
655
+ break;
656
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
657
+ rb_struct_aset(
658
+ result, sym_status,
659
+ rb_struct_new(grpc_rb_sStatus, UINT2NUM(st->recv_status),
660
+ (st->recv_status_details == NULL
661
+ ? Qnil
662
+ : rb_str_new2(st->recv_status_details)),
663
+ grpc_rb_md_ary_to_h(&st->recv_trailing_metadata),
664
+ NULL));
665
+ break;
666
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
667
+ rb_struct_aset(result, sym_send_close, Qtrue);
668
+ break;
669
+ default:
670
+ break;
671
+ }
672
+ }
673
+ return result;
674
+ }
675
+
676
+ /* call-seq:
677
+ cq = CompletionQueue.new
678
+ ops = {
679
+ GRPC::Core::CallOps::SEND_INITIAL_METADATA => <op_value>,
680
+ GRPC::Core::CallOps::SEND_MESSAGE => <op_value>,
681
+ ...
682
+ }
683
+ tag = Object.new
684
+ timeout = 10
685
+ call.start_batch(cqueue, tag, timeout, ops)
686
+
687
+ Start a batch of operations defined in the array ops; when complete, post a
688
+ completion of type 'tag' to the completion queue bound to the call.
689
+
690
+ Also waits for the batch to complete, until timeout is reached.
691
+ The order of ops specified in the batch has no significance.
692
+ Only one operation of each type can be active at once in any given
693
+ batch */
694
+ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
695
+ VALUE timeout, VALUE ops_hash) {
696
+ run_batch_stack st;
697
+ grpc_call *call = NULL;
698
+ grpc_event ev;
699
+ grpc_call_error err;
700
+ VALUE result = Qnil;
701
+ VALUE rb_write_flag = rb_ivar_get(self, id_write_flag);
702
+ unsigned write_flag = 0;
703
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
704
+
705
+ /* Validate the ops args, adding them to a ruby array */
706
+ if (TYPE(ops_hash) != T_HASH) {
707
+ rb_raise(rb_eTypeError, "call#run_batch: ops hash should be a hash");
708
+ return Qnil;
709
+ }
710
+ if (rb_write_flag != Qnil) {
711
+ write_flag = NUM2UINT(rb_write_flag);
712
+ }
713
+ grpc_run_batch_stack_init(&st, write_flag);
714
+ grpc_run_batch_stack_fill_ops(&st, ops_hash);
715
+
716
+ /* call grpc_call_start_batch, then wait for it to complete using
717
+ * pluck_event */
718
+ err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag), NULL);
719
+ if (err != GRPC_CALL_OK) {
720
+ grpc_run_batch_stack_cleanup(&st);
721
+ rb_raise(grpc_rb_eCallError,
722
+ "grpc_call_start_batch failed with %s (code=%d)",
723
+ grpc_call_error_detail_of(err), err);
724
+ return Qnil;
725
+ }
726
+ ev = grpc_rb_completion_queue_pluck_event(cqueue, tag, timeout);
727
+ if (ev.type == GRPC_QUEUE_TIMEOUT) {
728
+ grpc_run_batch_stack_cleanup(&st);
729
+ rb_raise(grpc_rb_eOutOfTime, "grpc_call_start_batch timed out");
730
+ return Qnil;
731
+ }
732
+
733
+ /* Build and return the BatchResult struct result,
734
+ if there is an error, it's reflected in the status */
735
+ result = grpc_run_batch_stack_build_result(&st);
736
+ grpc_run_batch_stack_cleanup(&st);
737
+ return result;
738
+ }
739
+
740
+ static void Init_grpc_write_flags() {
741
+ /* Constants representing the write flags in grpc.h */
742
+ VALUE grpc_rb_mWriteFlags =
743
+ rb_define_module_under(grpc_rb_mGrpcCore, "WriteFlags");
744
+ rb_define_const(grpc_rb_mWriteFlags, "BUFFER_HINT",
745
+ UINT2NUM(GRPC_WRITE_BUFFER_HINT));
746
+ rb_define_const(grpc_rb_mWriteFlags, "NO_COMPRESS",
747
+ UINT2NUM(GRPC_WRITE_NO_COMPRESS));
748
+ }
749
+
750
+ static void Init_grpc_error_codes() {
751
+ /* Constants representing the error codes of grpc_call_error in grpc.h */
752
+ VALUE grpc_rb_mRpcErrors =
753
+ rb_define_module_under(grpc_rb_mGrpcCore, "RpcErrors");
754
+ rb_define_const(grpc_rb_mRpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
755
+ rb_define_const(grpc_rb_mRpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
756
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_SERVER",
757
+ UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER));
758
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_CLIENT",
759
+ UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT));
760
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_ACCEPTED",
761
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED));
762
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_INVOKED",
763
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED));
764
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_INVOKED",
765
+ UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED));
766
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_FINISHED",
767
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED));
768
+ rb_define_const(grpc_rb_mRpcErrors, "TOO_MANY_OPERATIONS",
769
+ UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
770
+ rb_define_const(grpc_rb_mRpcErrors, "INVALID_FLAGS",
771
+ UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS));
772
+
773
+ /* Add the detail strings to a Hash */
774
+ rb_error_code_details = rb_hash_new();
775
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_OK),
776
+ rb_str_new2("ok"));
777
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR),
778
+ rb_str_new2("unknown error"));
779
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER),
780
+ rb_str_new2("not available on a server"));
781
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT),
782
+ rb_str_new2("not available on a client"));
783
+ rb_hash_aset(rb_error_code_details,
784
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED),
785
+ rb_str_new2("call is already accepted"));
786
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED),
787
+ rb_str_new2("call is already invoked"));
788
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED),
789
+ rb_str_new2("call is not yet invoked"));
790
+ rb_hash_aset(rb_error_code_details,
791
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED),
792
+ rb_str_new2("call is already finished"));
793
+ rb_hash_aset(rb_error_code_details,
794
+ UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS),
795
+ rb_str_new2("outstanding read or write present"));
796
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS),
797
+ rb_str_new2("a bad flag was given"));
798
+ rb_define_const(grpc_rb_mRpcErrors, "ErrorMessages", rb_error_code_details);
799
+ rb_obj_freeze(rb_error_code_details);
800
+ }
801
+
802
+ static void Init_grpc_op_codes() {
803
+ /* Constants representing operation type codes in grpc.h */
804
+ VALUE grpc_rb_mCallOps = rb_define_module_under(grpc_rb_mGrpcCore, "CallOps");
805
+ rb_define_const(grpc_rb_mCallOps, "SEND_INITIAL_METADATA",
806
+ UINT2NUM(GRPC_OP_SEND_INITIAL_METADATA));
807
+ rb_define_const(grpc_rb_mCallOps, "SEND_MESSAGE",
808
+ UINT2NUM(GRPC_OP_SEND_MESSAGE));
809
+ rb_define_const(grpc_rb_mCallOps, "SEND_CLOSE_FROM_CLIENT",
810
+ UINT2NUM(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
811
+ rb_define_const(grpc_rb_mCallOps, "SEND_STATUS_FROM_SERVER",
812
+ UINT2NUM(GRPC_OP_SEND_STATUS_FROM_SERVER));
813
+ rb_define_const(grpc_rb_mCallOps, "RECV_INITIAL_METADATA",
814
+ UINT2NUM(GRPC_OP_RECV_INITIAL_METADATA));
815
+ rb_define_const(grpc_rb_mCallOps, "RECV_MESSAGE",
816
+ UINT2NUM(GRPC_OP_RECV_MESSAGE));
817
+ rb_define_const(grpc_rb_mCallOps, "RECV_STATUS_ON_CLIENT",
818
+ UINT2NUM(GRPC_OP_RECV_STATUS_ON_CLIENT));
819
+ rb_define_const(grpc_rb_mCallOps, "RECV_CLOSE_ON_SERVER",
820
+ UINT2NUM(GRPC_OP_RECV_CLOSE_ON_SERVER));
821
+ }
822
+
823
+ void Init_grpc_call() {
824
+ /* CallError inherits from Exception to signal that it is non-recoverable */
825
+ grpc_rb_eCallError =
826
+ rb_define_class_under(grpc_rb_mGrpcCore, "CallError", rb_eException);
827
+ grpc_rb_eOutOfTime =
828
+ rb_define_class_under(grpc_rb_mGrpcCore, "OutOfTime", rb_eException);
829
+ grpc_rb_cCall = rb_define_class_under(grpc_rb_mGrpcCore, "Call", rb_cObject);
830
+ grpc_rb_cMdAry =
831
+ rb_define_class_under(grpc_rb_mGrpcCore, "MetadataArray", rb_cObject);
832
+
833
+ /* Prevent allocation or inialization of the Call class */
834
+ rb_define_alloc_func(grpc_rb_cCall, grpc_rb_cannot_alloc);
835
+ rb_define_method(grpc_rb_cCall, "initialize", grpc_rb_cannot_init, 0);
836
+ rb_define_method(grpc_rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy,
837
+ 1);
838
+
839
+ /* Add ruby analogues of the Call methods. */
840
+ rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4);
841
+ rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0);
842
+ rb_define_method(grpc_rb_cCall, "peer", grpc_rb_call_get_peer, 0);
843
+ rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0);
844
+ rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1);
845
+ rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
846
+ rb_define_method(grpc_rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
847
+ rb_define_method(grpc_rb_cCall, "write_flag", grpc_rb_call_get_write_flag, 0);
848
+ rb_define_method(grpc_rb_cCall, "write_flag=", grpc_rb_call_set_write_flag,
849
+ 1);
850
+ rb_define_method(grpc_rb_cCall, "set_credentials!",
851
+ grpc_rb_call_set_credentials, 1);
852
+
853
+ /* Ids used to support call attributes */
854
+ id_metadata = rb_intern("metadata");
855
+ id_status = rb_intern("status");
856
+ id_write_flag = rb_intern("write_flag");
857
+
858
+ /* Ids used by the c wrapping internals. */
859
+ id_cq = rb_intern("__cq");
860
+ id_flags = rb_intern("__flags");
861
+ id_input_md = rb_intern("__input_md");
862
+
863
+ /* Ids used in constructing the batch result. */
864
+ sym_send_message = ID2SYM(rb_intern("send_message"));
865
+ sym_send_metadata = ID2SYM(rb_intern("send_metadata"));
866
+ sym_send_close = ID2SYM(rb_intern("send_close"));
867
+ sym_send_status = ID2SYM(rb_intern("send_status"));
868
+ sym_message = ID2SYM(rb_intern("message"));
869
+ sym_status = ID2SYM(rb_intern("status"));
870
+ sym_cancelled = ID2SYM(rb_intern("cancelled"));
871
+
872
+ /* The Struct used to return the run_batch result. */
873
+ grpc_rb_sBatchResult = rb_struct_define(
874
+ "BatchResult", "send_message", "send_metadata", "send_close",
875
+ "send_status", "message", "metadata", "status", "cancelled", NULL);
876
+
877
+ /* The hash for reference counting calls, to ensure they can't be destroyed
878
+ * more than once */
879
+ hash_all_calls = rb_hash_new();
880
+ rb_define_const(grpc_rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
881
+
882
+ Init_grpc_error_codes();
883
+ Init_grpc_op_codes();
884
+ Init_grpc_write_flags();
885
+ }
886
+
887
+ /* Gets the call from the ruby object */
888
+ grpc_call *grpc_rb_get_wrapped_call(VALUE v) {
889
+ grpc_call *c = NULL;
890
+ TypedData_Get_Struct(v, grpc_call, &grpc_call_data_type, c);
891
+ return c;
892
+ }
893
+
894
+ /* Obtains the wrapped object for a given call */
895
+ VALUE grpc_rb_wrap_call(grpc_call *c) {
896
+ VALUE obj = Qnil;
897
+ if (c == NULL) {
898
+ return Qnil;
899
+ }
900
+ obj = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)c));
901
+ if (obj == Qnil) { /* Not in the hash add it */
902
+ rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c), UINT2NUM(1));
903
+ } else {
904
+ rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c),
905
+ UINT2NUM(NUM2UINT(obj) + 1));
906
+ }
907
+ return TypedData_Wrap_Struct(grpc_rb_cCall, &grpc_call_data_type, c);
908
+ }