grpc 1.60.0-aarch64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/etc/roots.pem +4337 -0
  3. data/grpc_c.32-msvcrt.ruby +0 -0
  4. data/grpc_c.64-msvcrt.ruby +0 -0
  5. data/grpc_c.64-ucrt.ruby +0 -0
  6. data/src/ruby/bin/math_client.rb +140 -0
  7. data/src/ruby/bin/math_pb.rb +40 -0
  8. data/src/ruby/bin/math_server.rb +191 -0
  9. data/src/ruby/bin/math_services_pb.rb +51 -0
  10. data/src/ruby/bin/noproto_client.rb +93 -0
  11. data/src/ruby/bin/noproto_server.rb +97 -0
  12. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.clang +2 -0
  13. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.gcc +7 -0
  14. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.clang +2 -0
  15. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.gcc +7 -0
  16. data/src/ruby/ext/grpc/ext-export.clang +1 -0
  17. data/src/ruby/ext/grpc/ext-export.gcc +6 -0
  18. data/src/ruby/ext/grpc/extconf.rb +270 -0
  19. data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
  20. data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
  21. data/src/ruby/ext/grpc/rb_call.c +1075 -0
  22. data/src/ruby/ext/grpc/rb_call.h +57 -0
  23. data/src/ruby/ext/grpc/rb_call_credentials.c +340 -0
  24. data/src/ruby/ext/grpc/rb_call_credentials.h +31 -0
  25. data/src/ruby/ext/grpc/rb_channel.c +875 -0
  26. data/src/ruby/ext/grpc/rb_channel.h +35 -0
  27. data/src/ruby/ext/grpc/rb_channel_args.c +172 -0
  28. data/src/ruby/ext/grpc/rb_channel_args.h +42 -0
  29. data/src/ruby/ext/grpc/rb_channel_credentials.c +285 -0
  30. data/src/ruby/ext/grpc/rb_channel_credentials.h +37 -0
  31. data/src/ruby/ext/grpc/rb_completion_queue.c +101 -0
  32. data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
  33. data/src/ruby/ext/grpc/rb_compression_options.c +470 -0
  34. data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
  35. data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
  36. data/src/ruby/ext/grpc/rb_event_thread.c +161 -0
  37. data/src/ruby/ext/grpc/rb_event_thread.h +22 -0
  38. data/src/ruby/ext/grpc/rb_grpc.c +496 -0
  39. data/src/ruby/ext/grpc/rb_grpc.h +83 -0
  40. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +603 -0
  41. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +910 -0
  42. data/src/ruby/ext/grpc/rb_loader.c +61 -0
  43. data/src/ruby/ext/grpc/rb_loader.h +25 -0
  44. data/src/ruby/ext/grpc/rb_server.c +405 -0
  45. data/src/ruby/ext/grpc/rb_server.h +32 -0
  46. data/src/ruby/ext/grpc/rb_server_credentials.c +258 -0
  47. data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
  48. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +217 -0
  49. data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +37 -0
  50. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +169 -0
  51. data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
  52. data/src/ruby/lib/grpc/2.7/grpc_c.so +0 -0
  53. data/src/ruby/lib/grpc/3.0/grpc_c.so +0 -0
  54. data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
  55. data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
  56. data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
  57. data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
  58. data/src/ruby/lib/grpc/errors.rb +277 -0
  59. data/src/ruby/lib/grpc/generic/active_call.rb +670 -0
  60. data/src/ruby/lib/grpc/generic/bidi_call.rb +237 -0
  61. data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
  62. data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
  63. data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
  64. data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
  65. data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
  66. data/src/ruby/lib/grpc/generic/service.rb +211 -0
  67. data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
  68. data/src/ruby/lib/grpc/grpc.rb +24 -0
  69. data/src/ruby/lib/grpc/logconfig.rb +44 -0
  70. data/src/ruby/lib/grpc/notifier.rb +45 -0
  71. data/src/ruby/lib/grpc/structs.rb +15 -0
  72. data/src/ruby/lib/grpc/version.rb +18 -0
  73. data/src/ruby/lib/grpc.rb +37 -0
  74. data/src/ruby/pb/README.md +42 -0
  75. data/src/ruby/pb/generate_proto_ruby.sh +46 -0
  76. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  77. data/src/ruby/pb/grpc/health/v1/health_pb.rb +42 -0
  78. data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
  79. data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
  80. data/src/ruby/pb/grpc/testing/metrics_pb.rb +28 -0
  81. data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
  82. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +38 -0
  83. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +71 -0
  84. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +40 -0
  85. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +174 -0
  86. data/src/ruby/pb/test/client.rb +785 -0
  87. data/src/ruby/pb/test/server.rb +252 -0
  88. data/src/ruby/pb/test/xds_client.rb +415 -0
  89. data/src/ruby/spec/call_credentials_spec.rb +42 -0
  90. data/src/ruby/spec/call_spec.rb +180 -0
  91. data/src/ruby/spec/channel_connection_spec.rb +126 -0
  92. data/src/ruby/spec/channel_credentials_spec.rb +124 -0
  93. data/src/ruby/spec/channel_spec.rb +207 -0
  94. data/src/ruby/spec/client_auth_spec.rb +152 -0
  95. data/src/ruby/spec/client_server_spec.rb +676 -0
  96. data/src/ruby/spec/compression_options_spec.rb +149 -0
  97. data/src/ruby/spec/debug_message_spec.rb +134 -0
  98. data/src/ruby/spec/error_sanity_spec.rb +49 -0
  99. data/src/ruby/spec/errors_spec.rb +142 -0
  100. data/src/ruby/spec/generic/active_call_spec.rb +692 -0
  101. data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
  102. data/src/ruby/spec/generic/client_stub_spec.rb +1083 -0
  103. data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
  104. data/src/ruby/spec/generic/rpc_desc_spec.rb +374 -0
  105. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +127 -0
  106. data/src/ruby/spec/generic/rpc_server_spec.rb +748 -0
  107. data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
  108. data/src/ruby/spec/generic/service_spec.rb +263 -0
  109. data/src/ruby/spec/google_rpc_status_utils_spec.rb +282 -0
  110. data/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto +28 -0
  111. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
  112. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  113. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
  114. data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
  115. data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
  116. data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
  117. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
  118. data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
  119. data/src/ruby/spec/server_credentials_spec.rb +104 -0
  120. data/src/ruby/spec/server_spec.rb +231 -0
  121. data/src/ruby/spec/spec_helper.rb +61 -0
  122. data/src/ruby/spec/support/helpers.rb +107 -0
  123. data/src/ruby/spec/support/services.rb +160 -0
  124. data/src/ruby/spec/testdata/README +1 -0
  125. data/src/ruby/spec/testdata/ca.pem +20 -0
  126. data/src/ruby/spec/testdata/client.key +28 -0
  127. data/src/ruby/spec/testdata/client.pem +20 -0
  128. data/src/ruby/spec/testdata/server1.key +28 -0
  129. data/src/ruby/spec/testdata/server1.pem +22 -0
  130. data/src/ruby/spec/time_consts_spec.rb +74 -0
  131. data/src/ruby/spec/user_agent_spec.rb +74 -0
  132. metadata +405 -0
@@ -0,0 +1,1075 @@
1
+ /*
2
+ *
3
+ * Copyright 2015 gRPC authors.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ *
17
+ */
18
+
19
+ #include <ruby/ruby.h>
20
+
21
+ #include "rb_call.h"
22
+
23
+ #include "rb_byte_buffer.h"
24
+ #include "rb_call_credentials.h"
25
+ #include "rb_completion_queue.h"
26
+ #include "rb_grpc.h"
27
+ #include "rb_grpc_imports.generated.h"
28
+
29
+ #include <grpc/grpc.h>
30
+ #include <grpc/impl/codegen/compression_types.h>
31
+ #include <grpc/support/alloc.h>
32
+ #include <grpc/support/log.h>
33
+
34
+ /* grpc_rb_cCall is the Call class whose instances proxy grpc_call. */
35
+ static VALUE grpc_rb_cCall;
36
+
37
+ /* grpc_rb_eCallError is the ruby class of the exception thrown during call
38
+ operations; */
39
+ VALUE grpc_rb_eCallError = Qnil;
40
+
41
+ /* grpc_rb_eOutOfTime is the ruby class of the exception thrown to indicate
42
+ a timeout. */
43
+ static VALUE grpc_rb_eOutOfTime = Qnil;
44
+
45
+ /* grpc_rb_sBatchResult is struct class used to hold the results of a batch
46
+ * call. */
47
+ static VALUE grpc_rb_sBatchResult;
48
+
49
+ /* grpc_rb_cMdAry is the MetadataArray class whose instances proxy
50
+ * grpc_metadata_array. */
51
+ VALUE grpc_rb_cMdAry;
52
+
53
+ /* id_credentials is the name of the hidden ivar that preserves the value
54
+ * of the credentials added to the call */
55
+ static ID id_credentials;
56
+
57
+ /* id_metadata is name of the attribute used to access the metadata hash
58
+ * received by the call and subsequently saved on it. */
59
+ static ID id_metadata;
60
+
61
+ /* id_trailing_metadata is the name of the attribute used to access the trailing
62
+ * metadata hash received by the call and subsequently saved on it. */
63
+ static ID id_trailing_metadata;
64
+
65
+ /* id_status is name of the attribute used to access the status object
66
+ * received by the call and subsequently saved on it. */
67
+ static ID id_status;
68
+
69
+ /* id_write_flag is name of the attribute used to access the write_flag
70
+ * saved on the call. */
71
+ static ID id_write_flag;
72
+
73
+ /* sym_* are the symbol for attributes of grpc_rb_sBatchResult. */
74
+ static VALUE sym_send_message;
75
+ static VALUE sym_send_metadata;
76
+ static VALUE sym_send_close;
77
+ static VALUE sym_send_status;
78
+ static VALUE sym_message;
79
+ static VALUE sym_status;
80
+ static VALUE sym_cancelled;
81
+
82
+ typedef struct grpc_rb_call {
83
+ grpc_call* wrapped;
84
+ grpc_completion_queue* queue;
85
+ } grpc_rb_call;
86
+
87
+ static void destroy_call(grpc_rb_call* call) {
88
+ /* Ensure that we only try to destroy the call once */
89
+ if (call->wrapped != NULL) {
90
+ grpc_call_unref(call->wrapped);
91
+ call->wrapped = NULL;
92
+ grpc_rb_completion_queue_destroy(call->queue);
93
+ call->queue = NULL;
94
+ }
95
+ }
96
+
97
+ /* Destroys a Call. */
98
+ static void grpc_rb_call_destroy(void* p) {
99
+ if (p == NULL) {
100
+ return;
101
+ }
102
+ destroy_call((grpc_rb_call*)p);
103
+ xfree(p);
104
+ }
105
+
106
+ const rb_data_type_t grpc_rb_md_ary_data_type = {
107
+ "grpc_metadata_array",
108
+ {GRPC_RB_GC_NOT_MARKED,
109
+ GRPC_RB_GC_DONT_FREE,
110
+ GRPC_RB_MEMSIZE_UNAVAILABLE,
111
+ {NULL, NULL}},
112
+ NULL,
113
+ NULL,
114
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
115
+ /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
116
+ * grpc_rb_call_destroy
117
+ * touches a hash object.
118
+ * TODO(yugui) Directly use st_table and call the free function earlier?
119
+ */
120
+ 0,
121
+ #endif
122
+ };
123
+
124
+ /* Describes grpc_call struct for RTypedData */
125
+ static const rb_data_type_t grpc_call_data_type = {"grpc_call",
126
+ {GRPC_RB_GC_NOT_MARKED,
127
+ grpc_rb_call_destroy,
128
+ GRPC_RB_MEMSIZE_UNAVAILABLE,
129
+ {NULL, NULL}},
130
+ NULL,
131
+ NULL,
132
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
133
+ RUBY_TYPED_FREE_IMMEDIATELY
134
+ #endif
135
+ };
136
+
137
+ /* Error code details is a hash containing text strings describing errors */
138
+ VALUE rb_error_code_details;
139
+
140
+ /* Obtains the error detail string for given error code */
141
+ const char* grpc_call_error_detail_of(grpc_call_error err) {
142
+ VALUE detail_ref = rb_hash_aref(rb_error_code_details, UINT2NUM(err));
143
+ const char* detail = "unknown error code!";
144
+ if (detail_ref != Qnil) {
145
+ detail = StringValueCStr(detail_ref);
146
+ }
147
+ return detail;
148
+ }
149
+
150
+ /* Called by clients to cancel an RPC on the server.
151
+ Can be called multiple times, from any thread. */
152
+ static VALUE grpc_rb_call_cancel(VALUE self) {
153
+ grpc_rb_call* call = NULL;
154
+ grpc_call_error err;
155
+ if (RTYPEDDATA_DATA(self) == NULL) {
156
+ // This call has been closed
157
+ return Qnil;
158
+ }
159
+
160
+ TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
161
+ err = grpc_call_cancel(call->wrapped, NULL);
162
+ if (err != GRPC_CALL_OK) {
163
+ rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)",
164
+ grpc_call_error_detail_of(err), err);
165
+ }
166
+
167
+ return Qnil;
168
+ }
169
+
170
+ /* TODO: expose this as part of the surface API if needed.
171
+ * This is meant for internal usage by the "write thread" of grpc-ruby
172
+ * client-side bidi calls. It provides a way for the background write-thread
173
+ * to propagate failures to the main read-thread and give the user an error
174
+ * message. */
175
+ static VALUE grpc_rb_call_cancel_with_status(VALUE self, VALUE status_code,
176
+ VALUE details) {
177
+ grpc_rb_call* call = NULL;
178
+ grpc_call_error err;
179
+ if (RTYPEDDATA_DATA(self) == NULL) {
180
+ // This call has been closed
181
+ return Qnil;
182
+ }
183
+
184
+ if (TYPE(details) != T_STRING || TYPE(status_code) != T_FIXNUM) {
185
+ rb_raise(rb_eTypeError,
186
+ "Bad parameter type error for cancel with status. Want Fixnum, "
187
+ "String.");
188
+ return Qnil;
189
+ }
190
+
191
+ TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
192
+ err = grpc_call_cancel_with_status(call->wrapped, NUM2LONG(status_code),
193
+ StringValueCStr(details), NULL);
194
+ if (err != GRPC_CALL_OK) {
195
+ rb_raise(grpc_rb_eCallError, "cancel with status failed: %s (code=%d)",
196
+ grpc_call_error_detail_of(err), err);
197
+ }
198
+
199
+ return Qnil;
200
+ }
201
+
202
+ /* Releases the c-level resources associated with a call
203
+ Once a call has been closed, no further requests can be
204
+ processed.
205
+ */
206
+ static VALUE grpc_rb_call_close(VALUE self) {
207
+ grpc_rb_call* call = NULL;
208
+ TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
209
+ if (call != NULL) {
210
+ destroy_call(call);
211
+ xfree(RTYPEDDATA_DATA(self));
212
+ RTYPEDDATA_DATA(self) = NULL;
213
+ }
214
+ return Qnil;
215
+ }
216
+
217
+ /* Called to obtain the peer that this call is connected to. */
218
+ static VALUE grpc_rb_call_get_peer(VALUE self) {
219
+ VALUE res = Qnil;
220
+ grpc_rb_call* call = NULL;
221
+ char* peer = NULL;
222
+ if (RTYPEDDATA_DATA(self) == NULL) {
223
+ rb_raise(grpc_rb_eCallError, "Cannot get peer value on closed call");
224
+ return Qnil;
225
+ }
226
+ TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
227
+ peer = grpc_call_get_peer(call->wrapped);
228
+ res = rb_str_new2(peer);
229
+ gpr_free(peer);
230
+
231
+ return res;
232
+ }
233
+
234
+ /* Called to obtain the x509 cert of an authenticated peer. */
235
+ static VALUE grpc_rb_call_get_peer_cert(VALUE self) {
236
+ grpc_rb_call* call = NULL;
237
+ VALUE res = Qnil;
238
+ grpc_auth_context* ctx = NULL;
239
+ if (RTYPEDDATA_DATA(self) == NULL) {
240
+ rb_raise(grpc_rb_eCallError, "Cannot get peer cert on closed call");
241
+ return Qnil;
242
+ }
243
+ TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
244
+
245
+ ctx = grpc_call_auth_context(call->wrapped);
246
+
247
+ if (!ctx || !grpc_auth_context_peer_is_authenticated(ctx)) {
248
+ return Qnil;
249
+ }
250
+
251
+ {
252
+ grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
253
+ ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME);
254
+ const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
255
+ if (prop == NULL) {
256
+ return Qnil;
257
+ }
258
+
259
+ res = rb_str_new2(prop->value);
260
+ }
261
+
262
+ grpc_auth_context_release(ctx);
263
+
264
+ return res;
265
+ }
266
+
267
+ /*
268
+ call-seq:
269
+ status = call.status
270
+
271
+ Gets the status object saved the call. */
272
+ static VALUE grpc_rb_call_get_status(VALUE self) {
273
+ return rb_ivar_get(self, id_status);
274
+ }
275
+
276
+ /*
277
+ call-seq:
278
+ call.status = status
279
+
280
+ Saves a status object on the call. */
281
+ static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
282
+ if (!NIL_P(status) && rb_obj_class(status) != grpc_rb_sStatus) {
283
+ rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Struct::Status>",
284
+ rb_obj_classname(status));
285
+ return Qnil;
286
+ }
287
+
288
+ return rb_ivar_set(self, id_status, status);
289
+ }
290
+
291
+ /*
292
+ call-seq:
293
+ metadata = call.metadata
294
+
295
+ Gets the metadata object saved the call. */
296
+ static VALUE grpc_rb_call_get_metadata(VALUE self) {
297
+ return rb_ivar_get(self, id_metadata);
298
+ }
299
+
300
+ /*
301
+ call-seq:
302
+ call.metadata = metadata
303
+
304
+ Saves the metadata hash on the call. */
305
+ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
306
+ if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) {
307
+ rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: <Hash>",
308
+ rb_obj_classname(metadata));
309
+ return Qnil;
310
+ }
311
+
312
+ return rb_ivar_set(self, id_metadata, metadata);
313
+ }
314
+
315
+ /*
316
+ call-seq:
317
+ trailing_metadata = call.trailing_metadata
318
+
319
+ Gets the trailing metadata object saved on the call */
320
+ static VALUE grpc_rb_call_get_trailing_metadata(VALUE self) {
321
+ return rb_ivar_get(self, id_trailing_metadata);
322
+ }
323
+
324
+ /*
325
+ call-seq:
326
+ call.trailing_metadata = trailing_metadata
327
+
328
+ Saves the trailing metadata hash on the call. */
329
+ static VALUE grpc_rb_call_set_trailing_metadata(VALUE self, VALUE metadata) {
330
+ if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) {
331
+ rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: <Hash>",
332
+ rb_obj_classname(metadata));
333
+ return Qnil;
334
+ }
335
+
336
+ return rb_ivar_set(self, id_trailing_metadata, metadata);
337
+ }
338
+
339
+ /*
340
+ call-seq:
341
+ write_flag = call.write_flag
342
+
343
+ Gets the write_flag value saved the call. */
344
+ static VALUE grpc_rb_call_get_write_flag(VALUE self) {
345
+ return rb_ivar_get(self, id_write_flag);
346
+ }
347
+
348
+ /*
349
+ call-seq:
350
+ call.write_flag = write_flag
351
+
352
+ Saves the write_flag on the call. */
353
+ static VALUE grpc_rb_call_set_write_flag(VALUE self, VALUE write_flag) {
354
+ if (!NIL_P(write_flag) && TYPE(write_flag) != T_FIXNUM) {
355
+ rb_raise(rb_eTypeError, "bad write_flag: got:<%s> want: <Fixnum>",
356
+ rb_obj_classname(write_flag));
357
+ return Qnil;
358
+ }
359
+
360
+ return rb_ivar_set(self, id_write_flag, write_flag);
361
+ }
362
+
363
+ /*
364
+ call-seq:
365
+ call.set_credentials call_credentials
366
+
367
+ Sets credentials on a call */
368
+ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
369
+ grpc_rb_call* call = NULL;
370
+ grpc_call_credentials* creds;
371
+ grpc_call_error err;
372
+ if (RTYPEDDATA_DATA(self) == NULL) {
373
+ rb_raise(grpc_rb_eCallError, "Cannot set credentials of closed call");
374
+ return Qnil;
375
+ }
376
+ TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
377
+ creds = grpc_rb_get_wrapped_call_credentials(credentials);
378
+ err = grpc_call_set_credentials(call->wrapped, creds);
379
+ if (err != GRPC_CALL_OK) {
380
+ rb_raise(grpc_rb_eCallError,
381
+ "grpc_call_set_credentials failed with %s (code=%d)",
382
+ grpc_call_error_detail_of(err), err);
383
+ }
384
+ /* We need the credentials to be alive for as long as the call is alive,
385
+ but we don't care about destruction order. */
386
+ rb_ivar_set(self, id_credentials, credentials);
387
+ return Qnil;
388
+ }
389
+
390
+ /* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used
391
+ to fill grpc_metadata_array.
392
+
393
+ it's capacity should have been computed via a prior call to
394
+ grpc_rb_md_ary_capacity_hash_cb
395
+ */
396
+ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
397
+ grpc_metadata_array* md_ary = NULL;
398
+ long array_length;
399
+ long i;
400
+ grpc_slice key_slice;
401
+ grpc_slice value_slice;
402
+ char* tmp_str = NULL;
403
+
404
+ if (TYPE(key) == T_SYMBOL) {
405
+ key_slice = grpc_slice_from_static_string(rb_id2name(SYM2ID(key)));
406
+ } else if (TYPE(key) == T_STRING) {
407
+ key_slice =
408
+ grpc_slice_from_copied_buffer(RSTRING_PTR(key), RSTRING_LEN(key));
409
+ } else {
410
+ rb_raise(rb_eTypeError,
411
+ "grpc_rb_md_ary_fill_hash_cb: bad type for key parameter");
412
+ return ST_STOP;
413
+ }
414
+
415
+ if (!grpc_header_key_is_legal(key_slice)) {
416
+ tmp_str = grpc_slice_to_c_string(key_slice);
417
+ rb_raise(rb_eArgError,
418
+ "'%s' is an invalid header key, must match [a-z0-9-_.]+", tmp_str);
419
+ return ST_STOP;
420
+ }
421
+
422
+ /* Construct a metadata object from key and value and add it */
423
+ TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
424
+ &grpc_rb_md_ary_data_type, md_ary);
425
+
426
+ if (TYPE(val) == T_ARRAY) {
427
+ array_length = RARRAY_LEN(val);
428
+ /* If the value is an array, add capacity for each value in the array */
429
+ for (i = 0; i < array_length; i++) {
430
+ value_slice = grpc_slice_from_copied_buffer(
431
+ RSTRING_PTR(rb_ary_entry(val, i)), RSTRING_LEN(rb_ary_entry(val, i)));
432
+ if (!grpc_is_binary_header(key_slice) &&
433
+ !grpc_header_nonbin_value_is_legal(value_slice)) {
434
+ // The value has invalid characters
435
+ tmp_str = grpc_slice_to_c_string(value_slice);
436
+ rb_raise(rb_eArgError, "Header value '%s' has invalid characters",
437
+ tmp_str);
438
+ return ST_STOP;
439
+ }
440
+ GPR_ASSERT(md_ary->count < md_ary->capacity);
441
+ md_ary->metadata[md_ary->count].key = key_slice;
442
+ md_ary->metadata[md_ary->count].value = value_slice;
443
+ md_ary->count += 1;
444
+ }
445
+ } else if (TYPE(val) == T_STRING) {
446
+ value_slice =
447
+ grpc_slice_from_copied_buffer(RSTRING_PTR(val), RSTRING_LEN(val));
448
+ if (!grpc_is_binary_header(key_slice) &&
449
+ !grpc_header_nonbin_value_is_legal(value_slice)) {
450
+ // The value has invalid characters
451
+ tmp_str = grpc_slice_to_c_string(value_slice);
452
+ rb_raise(rb_eArgError, "Header value '%s' has invalid characters",
453
+ tmp_str);
454
+ return ST_STOP;
455
+ }
456
+ GPR_ASSERT(md_ary->count < md_ary->capacity);
457
+ md_ary->metadata[md_ary->count].key = key_slice;
458
+ md_ary->metadata[md_ary->count].value = value_slice;
459
+ md_ary->count += 1;
460
+ } else {
461
+ rb_raise(rb_eArgError, "Header values must be of type string or array");
462
+ return ST_STOP;
463
+ }
464
+ return ST_CONTINUE;
465
+ }
466
+
467
+ /* grpc_rb_md_ary_capacity_hash_cb is the hash iteration callback used
468
+ to pre-compute the capacity a grpc_metadata_array.
469
+ */
470
+ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val,
471
+ VALUE md_ary_obj) {
472
+ grpc_metadata_array* md_ary = NULL;
473
+
474
+ (void)key;
475
+
476
+ /* Construct a metadata object from key and value and add it */
477
+ TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
478
+ &grpc_rb_md_ary_data_type, md_ary);
479
+
480
+ if (TYPE(val) == T_ARRAY) {
481
+ /* If the value is an array, add capacity for each value in the array */
482
+ md_ary->capacity += RARRAY_LEN(val);
483
+ } else {
484
+ md_ary->capacity += 1;
485
+ }
486
+
487
+ return ST_CONTINUE;
488
+ }
489
+
490
+ /* grpc_rb_md_ary_convert converts a ruby metadata hash into
491
+ a grpc_metadata_array.
492
+ Note that this function may throw exceptions.
493
+ */
494
+ void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array* md_ary) {
495
+ VALUE md_ary_obj = Qnil;
496
+ if (md_ary_hash == Qnil) {
497
+ return; /* Do nothing if the expected has value is nil */
498
+ }
499
+ if (TYPE(md_ary_hash) != T_HASH) {
500
+ rb_raise(rb_eTypeError, "md_ary_convert: got <%s>, want <Hash>",
501
+ rb_obj_classname(md_ary_hash));
502
+ return;
503
+ }
504
+
505
+ /* Initialize the array, compute it's capacity, then fill it. */
506
+ grpc_metadata_array_init(md_ary);
507
+ md_ary_obj =
508
+ TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary);
509
+ rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj);
510
+ md_ary->metadata = gpr_zalloc(md_ary->capacity * sizeof(grpc_metadata));
511
+ rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj);
512
+ }
513
+
514
+ /* Converts a metadata array to a hash. */
515
+ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array* md_ary) {
516
+ VALUE key = Qnil;
517
+ VALUE new_ary = Qnil;
518
+ VALUE value = Qnil;
519
+ VALUE result = rb_hash_new();
520
+ size_t i;
521
+
522
+ for (i = 0; i < md_ary->count; i++) {
523
+ key = grpc_rb_slice_to_ruby_string(md_ary->metadata[i].key);
524
+ value = rb_hash_aref(result, key);
525
+ if (value == Qnil) {
526
+ value = grpc_rb_slice_to_ruby_string(md_ary->metadata[i].value);
527
+ rb_hash_aset(result, key, value);
528
+ } else if (TYPE(value) == T_ARRAY) {
529
+ /* Add the string to the returned array */
530
+ rb_ary_push(value,
531
+ grpc_rb_slice_to_ruby_string(md_ary->metadata[i].value));
532
+ } else {
533
+ /* Add the current value with this key and the new one to an array */
534
+ new_ary = rb_ary_new();
535
+ rb_ary_push(new_ary, value);
536
+ rb_ary_push(new_ary,
537
+ grpc_rb_slice_to_ruby_string(md_ary->metadata[i].value));
538
+ rb_hash_aset(result, key, new_ary);
539
+ }
540
+ }
541
+ return result;
542
+ }
543
+
544
+ /* grpc_rb_call_check_op_keys_hash_cb is a hash iteration func that checks
545
+ each key of an ops hash is valid.
546
+ */
547
+ static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val,
548
+ VALUE ops_ary) {
549
+ (void)val;
550
+ /* Update the capacity; the value is an array, add capacity for each value in
551
+ * the array */
552
+ if (TYPE(key) != T_FIXNUM) {
553
+ rb_raise(rb_eTypeError, "invalid operation : got <%s>, want <Fixnum>",
554
+ rb_obj_classname(key));
555
+ return ST_STOP;
556
+ }
557
+ switch (NUM2INT(key)) {
558
+ case GRPC_OP_SEND_INITIAL_METADATA:
559
+ case GRPC_OP_SEND_MESSAGE:
560
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
561
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
562
+ case GRPC_OP_RECV_INITIAL_METADATA:
563
+ case GRPC_OP_RECV_MESSAGE:
564
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
565
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
566
+ rb_ary_push(ops_ary, key);
567
+ return ST_CONTINUE;
568
+ default:
569
+ rb_raise(rb_eTypeError, "invalid operation : bad value %d", NUM2INT(key));
570
+ };
571
+ return ST_STOP;
572
+ }
573
+
574
+ /* grpc_rb_op_update_status_from_server adds the values in a ruby status
575
+ struct to the 'send_status_from_server' portion of an op.
576
+ */
577
+ static void grpc_rb_op_update_status_from_server(
578
+ grpc_op* op, grpc_metadata_array* md_ary, grpc_slice* send_status_details,
579
+ VALUE status) {
580
+ VALUE code = rb_struct_aref(status, sym_code);
581
+ VALUE details = rb_struct_aref(status, sym_details);
582
+ VALUE metadata_hash = rb_struct_aref(status, sym_metadata);
583
+
584
+ /* TODO: add check to ensure status is the correct struct type */
585
+ if (TYPE(code) != T_FIXNUM) {
586
+ rb_raise(rb_eTypeError, "invalid code : got <%s>, want <Fixnum>",
587
+ rb_obj_classname(code));
588
+ return;
589
+ }
590
+ if (TYPE(details) != T_STRING) {
591
+ rb_raise(rb_eTypeError, "invalid details : got <%s>, want <String>",
592
+ rb_obj_classname(code));
593
+ return;
594
+ }
595
+
596
+ *send_status_details =
597
+ grpc_slice_from_copied_buffer(RSTRING_PTR(details), RSTRING_LEN(details));
598
+
599
+ op->data.send_status_from_server.status = NUM2INT(code);
600
+ op->data.send_status_from_server.status_details = send_status_details;
601
+ grpc_rb_md_ary_convert(metadata_hash, md_ary);
602
+ op->data.send_status_from_server.trailing_metadata_count = md_ary->count;
603
+ op->data.send_status_from_server.trailing_metadata = md_ary->metadata;
604
+ }
605
+
606
+ /* run_batch_stack holds various values used by the
607
+ * grpc_rb_call_run_batch function */
608
+ typedef struct run_batch_stack {
609
+ /* The batch ops */
610
+ grpc_op ops[8]; /* 8 is the maximum number of operations */
611
+ size_t op_num; /* tracks the last added operation */
612
+
613
+ /* Data being sent */
614
+ grpc_metadata_array send_metadata;
615
+ grpc_metadata_array send_trailing_metadata;
616
+
617
+ /* Data being received */
618
+ grpc_byte_buffer* recv_message;
619
+ grpc_metadata_array recv_metadata;
620
+ grpc_metadata_array recv_trailing_metadata;
621
+ int recv_cancelled;
622
+ grpc_status_code recv_status;
623
+ grpc_slice recv_status_details;
624
+ const char* recv_status_debug_error_string;
625
+ unsigned write_flag;
626
+ grpc_slice send_status_details;
627
+ } run_batch_stack;
628
+
629
+ /* grpc_run_batch_stack_init ensures the run_batch_stack is properly
630
+ * initialized */
631
+ static void grpc_run_batch_stack_init(run_batch_stack* st,
632
+ unsigned write_flag) {
633
+ MEMZERO(st, run_batch_stack, 1);
634
+ grpc_metadata_array_init(&st->send_metadata);
635
+ grpc_metadata_array_init(&st->send_trailing_metadata);
636
+ grpc_metadata_array_init(&st->recv_metadata);
637
+ grpc_metadata_array_init(&st->recv_trailing_metadata);
638
+ st->op_num = 0;
639
+ st->write_flag = write_flag;
640
+ }
641
+
642
+ void grpc_rb_metadata_array_destroy_including_entries(
643
+ grpc_metadata_array* array) {
644
+ size_t i;
645
+ if (array->metadata) {
646
+ for (i = 0; i < array->count; i++) {
647
+ grpc_slice_unref(array->metadata[i].key);
648
+ grpc_slice_unref(array->metadata[i].value);
649
+ }
650
+ }
651
+ grpc_metadata_array_destroy(array);
652
+ }
653
+
654
+ /* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
655
+ * cleaned up */
656
+ static void grpc_run_batch_stack_cleanup(run_batch_stack* st) {
657
+ size_t i = 0;
658
+
659
+ grpc_rb_metadata_array_destroy_including_entries(&st->send_metadata);
660
+ grpc_rb_metadata_array_destroy_including_entries(&st->send_trailing_metadata);
661
+ grpc_metadata_array_destroy(&st->recv_metadata);
662
+ grpc_metadata_array_destroy(&st->recv_trailing_metadata);
663
+
664
+ if (GRPC_SLICE_START_PTR(st->send_status_details) != NULL) {
665
+ grpc_slice_unref(st->send_status_details);
666
+ }
667
+
668
+ if (GRPC_SLICE_START_PTR(st->recv_status_details) != NULL) {
669
+ grpc_slice_unref(st->recv_status_details);
670
+ }
671
+
672
+ if (st->recv_message != NULL) {
673
+ grpc_byte_buffer_destroy(st->recv_message);
674
+ }
675
+
676
+ for (i = 0; i < st->op_num; i++) {
677
+ if (st->ops[i].op == GRPC_OP_SEND_MESSAGE) {
678
+ grpc_byte_buffer_destroy(st->ops[i].data.send_message.send_message);
679
+ }
680
+ }
681
+ }
682
+
683
+ /* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from
684
+ * ops_hash */
685
+ static void grpc_run_batch_stack_fill_ops(run_batch_stack* st, VALUE ops_hash) {
686
+ VALUE this_op = Qnil;
687
+ VALUE this_value = Qnil;
688
+ VALUE ops_ary = rb_ary_new();
689
+ size_t i = 0;
690
+
691
+ /* Create a ruby array with just the operation keys */
692
+ rb_hash_foreach(ops_hash, grpc_rb_call_check_op_keys_hash_cb, ops_ary);
693
+
694
+ /* Fill the ops array */
695
+ for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) {
696
+ this_op = rb_ary_entry(ops_ary, i);
697
+ this_value = rb_hash_aref(ops_hash, this_op);
698
+ st->ops[st->op_num].flags = 0;
699
+ switch (NUM2INT(this_op)) {
700
+ case GRPC_OP_SEND_INITIAL_METADATA:
701
+ grpc_rb_md_ary_convert(this_value, &st->send_metadata);
702
+ st->ops[st->op_num].data.send_initial_metadata.count =
703
+ st->send_metadata.count;
704
+ st->ops[st->op_num].data.send_initial_metadata.metadata =
705
+ st->send_metadata.metadata;
706
+ break;
707
+ case GRPC_OP_SEND_MESSAGE:
708
+ st->ops[st->op_num].data.send_message.send_message =
709
+ grpc_rb_s_to_byte_buffer(RSTRING_PTR(this_value),
710
+ RSTRING_LEN(this_value));
711
+ st->ops[st->op_num].flags = st->write_flag;
712
+ break;
713
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
714
+ break;
715
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
716
+ grpc_rb_op_update_status_from_server(
717
+ &st->ops[st->op_num], &st->send_trailing_metadata,
718
+ &st->send_status_details, this_value);
719
+ break;
720
+ case GRPC_OP_RECV_INITIAL_METADATA:
721
+ st->ops[st->op_num].data.recv_initial_metadata.recv_initial_metadata =
722
+ &st->recv_metadata;
723
+ break;
724
+ case GRPC_OP_RECV_MESSAGE:
725
+ st->ops[st->op_num].data.recv_message.recv_message = &st->recv_message;
726
+ break;
727
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
728
+ st->ops[st->op_num].data.recv_status_on_client.trailing_metadata =
729
+ &st->recv_trailing_metadata;
730
+ st->ops[st->op_num].data.recv_status_on_client.status =
731
+ &st->recv_status;
732
+ st->ops[st->op_num].data.recv_status_on_client.status_details =
733
+ &st->recv_status_details;
734
+ st->ops[st->op_num].data.recv_status_on_client.error_string =
735
+ &st->recv_status_debug_error_string;
736
+ break;
737
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
738
+ st->ops[st->op_num].data.recv_close_on_server.cancelled =
739
+ &st->recv_cancelled;
740
+ break;
741
+ default:
742
+ grpc_run_batch_stack_cleanup(st);
743
+ rb_raise(rb_eTypeError, "invalid operation : bad value %d",
744
+ NUM2INT(this_op));
745
+ };
746
+ st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op);
747
+ st->ops[st->op_num].reserved = NULL;
748
+ st->op_num++;
749
+ }
750
+ }
751
+
752
+ /* grpc_run_batch_stack_build_result fills constructs a ruby BatchResult struct
753
+ after the results have run */
754
+ static VALUE grpc_run_batch_stack_build_result(run_batch_stack* st) {
755
+ size_t i = 0;
756
+ VALUE result = rb_struct_new(grpc_rb_sBatchResult, Qnil, Qnil, Qnil, Qnil,
757
+ Qnil, Qnil, Qnil, Qnil, NULL);
758
+ for (i = 0; i < st->op_num; i++) {
759
+ switch (st->ops[i].op) {
760
+ case GRPC_OP_SEND_INITIAL_METADATA:
761
+ rb_struct_aset(result, sym_send_metadata, Qtrue);
762
+ break;
763
+ case GRPC_OP_SEND_MESSAGE:
764
+ rb_struct_aset(result, sym_send_message, Qtrue);
765
+ break;
766
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
767
+ rb_struct_aset(result, sym_send_close, Qtrue);
768
+ break;
769
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
770
+ rb_struct_aset(result, sym_send_status, Qtrue);
771
+ break;
772
+ case GRPC_OP_RECV_INITIAL_METADATA:
773
+ rb_struct_aset(result, sym_metadata,
774
+ grpc_rb_md_ary_to_h(&st->recv_metadata));
775
+ case GRPC_OP_RECV_MESSAGE:
776
+ rb_struct_aset(result, sym_message,
777
+ grpc_rb_byte_buffer_to_s(st->recv_message));
778
+ break;
779
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
780
+ rb_struct_aset(
781
+ result, sym_status,
782
+ rb_struct_new(
783
+ grpc_rb_sStatus, UINT2NUM(st->recv_status),
784
+ (GRPC_SLICE_START_PTR(st->recv_status_details) == NULL
785
+ ? Qnil
786
+ : grpc_rb_slice_to_ruby_string(st->recv_status_details)),
787
+ grpc_rb_md_ary_to_h(&st->recv_trailing_metadata),
788
+ st->recv_status_debug_error_string == NULL
789
+ ? Qnil
790
+ : rb_str_new_cstr(st->recv_status_debug_error_string),
791
+ NULL));
792
+ gpr_free((void*)st->recv_status_debug_error_string);
793
+ break;
794
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
795
+ rb_struct_aset(result, sym_send_close, Qtrue);
796
+ break;
797
+ default:
798
+ break;
799
+ }
800
+ }
801
+ return result;
802
+ }
803
+
804
+ struct call_run_batch_args {
805
+ grpc_rb_call* call;
806
+ unsigned write_flag;
807
+ VALUE ops_hash;
808
+ run_batch_stack* st;
809
+ };
810
+
811
+ static VALUE grpc_rb_call_run_batch_try(VALUE value_args) {
812
+ grpc_rb_fork_unsafe_begin();
813
+ struct call_run_batch_args* args = (struct call_run_batch_args*)value_args;
814
+ void* tag = (void*)&args->st;
815
+
816
+ grpc_event ev;
817
+ grpc_call_error err;
818
+
819
+ args->st = gpr_malloc(sizeof(run_batch_stack));
820
+ grpc_run_batch_stack_init(args->st, args->write_flag);
821
+ grpc_run_batch_stack_fill_ops(args->st, args->ops_hash);
822
+
823
+ /* call grpc_call_start_batch, then wait for it to complete using
824
+ * pluck_event */
825
+ err = grpc_call_start_batch(args->call->wrapped, args->st->ops,
826
+ args->st->op_num, tag, NULL);
827
+ if (err != GRPC_CALL_OK) {
828
+ rb_raise(grpc_rb_eCallError,
829
+ "grpc_call_start_batch failed with %s (code=%d)",
830
+ grpc_call_error_detail_of(err), err);
831
+ }
832
+ ev = rb_completion_queue_pluck(args->call->queue, tag,
833
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
834
+ if (!ev.success) {
835
+ rb_raise(grpc_rb_eCallError, "call#run_batch failed somehow");
836
+ }
837
+ /* Build and return the BatchResult struct result,
838
+ if there is an error, it's reflected in the status */
839
+ return grpc_run_batch_stack_build_result(args->st);
840
+ }
841
+
842
+ static VALUE grpc_rb_call_run_batch_ensure(VALUE value_args) {
843
+ grpc_rb_fork_unsafe_end();
844
+ struct call_run_batch_args* args = (struct call_run_batch_args*)value_args;
845
+
846
+ if (args->st) {
847
+ grpc_run_batch_stack_cleanup(args->st);
848
+ gpr_free(args->st);
849
+ }
850
+
851
+ return Qnil;
852
+ }
853
+
854
+ /* call-seq:
855
+ ops = {
856
+ GRPC::Core::CallOps::SEND_INITIAL_METADATA => <op_value>,
857
+ GRPC::Core::CallOps::SEND_MESSAGE => <op_value>,
858
+ ...
859
+ }
860
+ tag = Object.new
861
+ timeout = 10
862
+ call.start_batch(tag, timeout, ops)
863
+
864
+ Start a batch of operations defined in the array ops; when complete, post a
865
+ completion of type 'tag' to the completion queue bound to the call.
866
+
867
+ Also waits for the batch to complete, until timeout is reached.
868
+ The order of ops specified in the batch has no significance.
869
+ Only one operation of each type can be active at once in any given
870
+ batch */
871
+ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
872
+ grpc_ruby_fork_guard();
873
+ if (RTYPEDDATA_DATA(self) == NULL) {
874
+ rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call");
875
+ }
876
+
877
+ grpc_rb_call* call = NULL;
878
+ TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
879
+
880
+ /* Validate the ops args, adding them to a ruby array */
881
+ if (TYPE(ops_hash) != T_HASH) {
882
+ rb_raise(rb_eTypeError, "call#run_batch: ops hash should be a hash");
883
+ }
884
+
885
+ VALUE rb_write_flag = rb_ivar_get(self, id_write_flag);
886
+
887
+ struct call_run_batch_args args = {
888
+ .call = call,
889
+ .write_flag = rb_write_flag == Qnil ? 0 : NUM2UINT(rb_write_flag),
890
+ .ops_hash = ops_hash,
891
+ .st = NULL};
892
+
893
+ return rb_ensure(grpc_rb_call_run_batch_try, (VALUE)&args,
894
+ grpc_rb_call_run_batch_ensure, (VALUE)&args);
895
+ }
896
+
897
+ static void Init_grpc_write_flags() {
898
+ /* Constants representing the write flags in grpc.h */
899
+ VALUE grpc_rb_mWriteFlags =
900
+ rb_define_module_under(grpc_rb_mGrpcCore, "WriteFlags");
901
+ rb_define_const(grpc_rb_mWriteFlags, "BUFFER_HINT",
902
+ UINT2NUM(GRPC_WRITE_BUFFER_HINT));
903
+ rb_define_const(grpc_rb_mWriteFlags, "NO_COMPRESS",
904
+ UINT2NUM(GRPC_WRITE_NO_COMPRESS));
905
+ }
906
+
907
+ static void Init_grpc_error_codes() {
908
+ /* Constants representing the error codes of grpc_call_error in grpc.h */
909
+ VALUE grpc_rb_mRpcErrors =
910
+ rb_define_module_under(grpc_rb_mGrpcCore, "RpcErrors");
911
+ rb_define_const(grpc_rb_mRpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
912
+ rb_define_const(grpc_rb_mRpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
913
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_SERVER",
914
+ UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER));
915
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_CLIENT",
916
+ UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT));
917
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_ACCEPTED",
918
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED));
919
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_INVOKED",
920
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED));
921
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_INVOKED",
922
+ UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED));
923
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_FINISHED",
924
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED));
925
+ rb_define_const(grpc_rb_mRpcErrors, "TOO_MANY_OPERATIONS",
926
+ UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
927
+ rb_define_const(grpc_rb_mRpcErrors, "INVALID_FLAGS",
928
+ UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS));
929
+
930
+ /* Hint the GC that this is a global and shouldn't be sweeped. */
931
+ rb_global_variable(&rb_error_code_details);
932
+
933
+ /* Add the detail strings to a Hash */
934
+ rb_error_code_details = rb_hash_new();
935
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_OK),
936
+ rb_str_new2("ok"));
937
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR),
938
+ rb_str_new2("unknown error"));
939
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER),
940
+ rb_str_new2("not available on a server"));
941
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT),
942
+ rb_str_new2("not available on a client"));
943
+ rb_hash_aset(rb_error_code_details,
944
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED),
945
+ rb_str_new2("call is already accepted"));
946
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED),
947
+ rb_str_new2("call is already invoked"));
948
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED),
949
+ rb_str_new2("call is not yet invoked"));
950
+ rb_hash_aset(rb_error_code_details,
951
+ UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED),
952
+ rb_str_new2("call is already finished"));
953
+ rb_hash_aset(rb_error_code_details,
954
+ UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS),
955
+ rb_str_new2("outstanding read or write present"));
956
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS),
957
+ rb_str_new2("a bad flag was given"));
958
+ rb_define_const(grpc_rb_mRpcErrors, "ErrorMessages", rb_error_code_details);
959
+ rb_obj_freeze(rb_error_code_details);
960
+ }
961
+
962
+ static void Init_grpc_op_codes() {
963
+ /* Constants representing operation type codes in grpc.h */
964
+ VALUE grpc_rb_mCallOps = rb_define_module_under(grpc_rb_mGrpcCore, "CallOps");
965
+ rb_define_const(grpc_rb_mCallOps, "SEND_INITIAL_METADATA",
966
+ UINT2NUM(GRPC_OP_SEND_INITIAL_METADATA));
967
+ rb_define_const(grpc_rb_mCallOps, "SEND_MESSAGE",
968
+ UINT2NUM(GRPC_OP_SEND_MESSAGE));
969
+ rb_define_const(grpc_rb_mCallOps, "SEND_CLOSE_FROM_CLIENT",
970
+ UINT2NUM(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
971
+ rb_define_const(grpc_rb_mCallOps, "SEND_STATUS_FROM_SERVER",
972
+ UINT2NUM(GRPC_OP_SEND_STATUS_FROM_SERVER));
973
+ rb_define_const(grpc_rb_mCallOps, "RECV_INITIAL_METADATA",
974
+ UINT2NUM(GRPC_OP_RECV_INITIAL_METADATA));
975
+ rb_define_const(grpc_rb_mCallOps, "RECV_MESSAGE",
976
+ UINT2NUM(GRPC_OP_RECV_MESSAGE));
977
+ rb_define_const(grpc_rb_mCallOps, "RECV_STATUS_ON_CLIENT",
978
+ UINT2NUM(GRPC_OP_RECV_STATUS_ON_CLIENT));
979
+ rb_define_const(grpc_rb_mCallOps, "RECV_CLOSE_ON_SERVER",
980
+ UINT2NUM(GRPC_OP_RECV_CLOSE_ON_SERVER));
981
+ }
982
+
983
+ static void Init_grpc_metadata_keys() {
984
+ VALUE grpc_rb_mMetadataKeys =
985
+ rb_define_module_under(grpc_rb_mGrpcCore, "MetadataKeys");
986
+ rb_define_const(grpc_rb_mMetadataKeys, "COMPRESSION_REQUEST_ALGORITHM",
987
+ rb_str_new2(GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY));
988
+ }
989
+
990
+ void Init_grpc_call() {
991
+ /* CallError inherits from Exception to signal that it is non-recoverable */
992
+ grpc_rb_eCallError =
993
+ rb_define_class_under(grpc_rb_mGrpcCore, "CallError", rb_eException);
994
+ grpc_rb_eOutOfTime =
995
+ rb_define_class_under(grpc_rb_mGrpcCore, "OutOfTime", rb_eException);
996
+ grpc_rb_cCall = rb_define_class_under(grpc_rb_mGrpcCore, "Call", rb_cObject);
997
+ grpc_rb_cMdAry =
998
+ rb_define_class_under(grpc_rb_mGrpcCore, "MetadataArray", rb_cObject);
999
+ rb_undef_alloc_func(grpc_rb_cMdAry);
1000
+
1001
+ /* Prevent allocation or inialization of the Call class */
1002
+ rb_define_alloc_func(grpc_rb_cCall, grpc_rb_cannot_alloc);
1003
+ rb_define_method(grpc_rb_cCall, "initialize", grpc_rb_cannot_init, 0);
1004
+ rb_define_method(grpc_rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy,
1005
+ 1);
1006
+
1007
+ /* Add ruby analogues of the Call methods. */
1008
+ rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 1);
1009
+ rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0);
1010
+ rb_define_method(grpc_rb_cCall, "cancel_with_status",
1011
+ grpc_rb_call_cancel_with_status, 2);
1012
+ rb_define_method(grpc_rb_cCall, "close", grpc_rb_call_close, 0);
1013
+ rb_define_method(grpc_rb_cCall, "peer", grpc_rb_call_get_peer, 0);
1014
+ rb_define_method(grpc_rb_cCall, "peer_cert", grpc_rb_call_get_peer_cert, 0);
1015
+ rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0);
1016
+ rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1);
1017
+ rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
1018
+ rb_define_method(grpc_rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
1019
+ rb_define_method(grpc_rb_cCall, "trailing_metadata",
1020
+ grpc_rb_call_get_trailing_metadata, 0);
1021
+ rb_define_method(grpc_rb_cCall,
1022
+ "trailing_metadata=", grpc_rb_call_set_trailing_metadata, 1);
1023
+ rb_define_method(grpc_rb_cCall, "write_flag", grpc_rb_call_get_write_flag, 0);
1024
+ rb_define_method(grpc_rb_cCall, "write_flag=", grpc_rb_call_set_write_flag,
1025
+ 1);
1026
+ rb_define_method(grpc_rb_cCall, "set_credentials!",
1027
+ grpc_rb_call_set_credentials, 1);
1028
+
1029
+ /* Ids used to support call attributes */
1030
+ id_metadata = rb_intern("metadata");
1031
+ id_trailing_metadata = rb_intern("trailing_metadata");
1032
+ id_status = rb_intern("status");
1033
+ id_write_flag = rb_intern("write_flag");
1034
+
1035
+ /* Ids used by the c wrapping internals. */
1036
+ id_credentials = rb_intern("__credentials");
1037
+
1038
+ /* Ids used in constructing the batch result. */
1039
+ sym_send_message = ID2SYM(rb_intern("send_message"));
1040
+ sym_send_metadata = ID2SYM(rb_intern("send_metadata"));
1041
+ sym_send_close = ID2SYM(rb_intern("send_close"));
1042
+ sym_send_status = ID2SYM(rb_intern("send_status"));
1043
+ sym_message = ID2SYM(rb_intern("message"));
1044
+ sym_status = ID2SYM(rb_intern("status"));
1045
+ sym_cancelled = ID2SYM(rb_intern("cancelled"));
1046
+
1047
+ /* The Struct used to return the run_batch result. */
1048
+ grpc_rb_sBatchResult = rb_struct_define(
1049
+ "BatchResult", "send_message", "send_metadata", "send_close",
1050
+ "send_status", "message", "metadata", "status", "cancelled", NULL);
1051
+
1052
+ Init_grpc_error_codes();
1053
+ Init_grpc_op_codes();
1054
+ Init_grpc_write_flags();
1055
+ Init_grpc_metadata_keys();
1056
+ }
1057
+
1058
+ /* Gets the call from the ruby object */
1059
+ grpc_call* grpc_rb_get_wrapped_call(VALUE v) {
1060
+ grpc_rb_call* call = NULL;
1061
+ TypedData_Get_Struct(v, grpc_rb_call, &grpc_call_data_type, call);
1062
+ return call->wrapped;
1063
+ }
1064
+
1065
+ /* Obtains the wrapped object for a given call */
1066
+ VALUE grpc_rb_wrap_call(grpc_call* c, grpc_completion_queue* q) {
1067
+ grpc_rb_call* wrapper;
1068
+ if (c == NULL || q == NULL) {
1069
+ return Qnil;
1070
+ }
1071
+ wrapper = ALLOC(grpc_rb_call);
1072
+ wrapper->wrapped = c;
1073
+ wrapper->queue = q;
1074
+ return TypedData_Wrap_Struct(grpc_rb_cCall, &grpc_call_data_type, wrapper);
1075
+ }