grpc 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grpc might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.rubocop_todo.yml +12 -20
- data/CHANGELOG.md +11 -0
- data/Rakefile +1 -0
- data/bin/apis/pubsub_demo.rb +3 -6
- data/bin/interop/interop_client.rb +43 -3
- data/bin/interop/interop_server.rb +1 -1
- data/bin/math_server.rb +1 -1
- data/bin/noproto_server.rb +1 -1
- data/ext/grpc/rb_byte_buffer.c +15 -189
- data/ext/grpc/rb_byte_buffer.h +4 -12
- data/ext/grpc/rb_call.c +514 -307
- data/ext/grpc/rb_call.h +4 -4
- data/ext/grpc/rb_channel.c +58 -34
- data/ext/grpc/rb_channel.h +0 -3
- data/ext/grpc/rb_channel_args.c +13 -4
- data/ext/grpc/rb_completion_queue.c +50 -23
- data/ext/grpc/rb_completion_queue.h +7 -3
- data/ext/grpc/rb_credentials.c +40 -28
- data/ext/grpc/rb_credentials.h +0 -4
- data/ext/grpc/rb_grpc.c +86 -67
- data/ext/grpc/rb_grpc.h +20 -10
- data/ext/grpc/rb_server.c +119 -26
- data/ext/grpc/rb_server.h +0 -4
- data/ext/grpc/rb_server_credentials.c +29 -16
- data/ext/grpc/rb_server_credentials.h +0 -4
- data/grpc.gemspec +11 -8
- data/lib/grpc.rb +1 -1
- data/lib/grpc/errors.rb +8 -7
- data/lib/grpc/generic/active_call.rb +104 -171
- data/lib/grpc/generic/bidi_call.rb +32 -60
- data/lib/grpc/generic/client_stub.rb +42 -31
- data/lib/grpc/generic/rpc_desc.rb +7 -12
- data/lib/grpc/generic/rpc_server.rb +253 -170
- data/lib/grpc/{core/event.rb → notifier.rb} +25 -9
- data/lib/grpc/version.rb +1 -1
- data/spec/call_spec.rb +23 -40
- data/spec/channel_spec.rb +11 -20
- data/spec/client_server_spec.rb +193 -175
- data/spec/credentials_spec.rb +2 -2
- data/spec/generic/active_call_spec.rb +59 -85
- data/spec/generic/client_stub_spec.rb +46 -64
- data/spec/generic/rpc_desc_spec.rb +50 -80
- data/spec/generic/rpc_server_pool_spec.rb +2 -3
- data/spec/generic/rpc_server_spec.rb +158 -29
- data/spec/server_spec.rb +1 -1
- data/spec/spec_helper.rb +8 -4
- metadata +27 -37
- data/ext/grpc/rb_event.c +0 -361
- data/ext/grpc/rb_event.h +0 -53
- data/ext/grpc/rb_metadata.c +0 -215
- data/ext/grpc/rb_metadata.h +0 -53
- data/spec/alloc_spec.rb +0 -44
- data/spec/byte_buffer_spec.rb +0 -67
- data/spec/event_spec.rb +0 -53
- data/spec/metadata_spec.rb +0 -64
data/ext/grpc/rb_byte_buffer.h
CHANGED
@@ -37,18 +37,10 @@
|
|
37
37
|
#include <grpc/grpc.h>
|
38
38
|
#include <ruby.h>
|
39
39
|
|
40
|
-
/*
|
41
|
-
|
42
|
-
extern VALUE rb_cByteBuffer;
|
40
|
+
/* Converts a char* with a length to a grpc_byte_buffer */
|
41
|
+
grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length);
|
43
42
|
|
44
|
-
/*
|
45
|
-
|
46
|
-
|
47
|
-
/* grpc_rb_byte_buffer_create_with_mark creates a grpc_rb_byte_buffer with a
|
48
|
-
* ruby mark object that will be kept alive while the byte_buffer is alive. */
|
49
|
-
VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb);
|
50
|
-
|
51
|
-
/* Gets the wrapped byte_buffer from its ruby object. */
|
52
|
-
grpc_byte_buffer* grpc_rb_get_wrapped_byte_buffer(VALUE v);
|
43
|
+
/* Converts a grpc_byte_buffer to a ruby string */
|
44
|
+
VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer);
|
53
45
|
|
54
46
|
#endif /* GRPC_RB_BYTE_BUFFER_H_ */
|
data/ext/grpc/rb_call.c
CHANGED
@@ -36,11 +36,31 @@
|
|
36
36
|
#include <ruby.h>
|
37
37
|
|
38
38
|
#include <grpc/grpc.h>
|
39
|
+
#include <grpc/support/alloc.h>
|
40
|
+
|
39
41
|
#include "rb_byte_buffer.h"
|
40
42
|
#include "rb_completion_queue.h"
|
41
|
-
#include "rb_metadata.h"
|
42
43
|
#include "rb_grpc.h"
|
43
44
|
|
45
|
+
/* grpc_rb_cCall is the Call class whose instances proxy grpc_call. */
|
46
|
+
static VALUE grpc_rb_cCall;
|
47
|
+
|
48
|
+
/* grpc_rb_eCallError is the ruby class of the exception thrown during call
|
49
|
+
operations; */
|
50
|
+
VALUE grpc_rb_eCallError = Qnil;
|
51
|
+
|
52
|
+
/* grpc_rb_eOutOfTime is the ruby class of the exception thrown to indicate
|
53
|
+
a timeout. */
|
54
|
+
static VALUE grpc_rb_eOutOfTime = Qnil;
|
55
|
+
|
56
|
+
/* grpc_rb_sBatchResult is struct class used to hold the results of a batch
|
57
|
+
* call. */
|
58
|
+
static VALUE grpc_rb_sBatchResult;
|
59
|
+
|
60
|
+
/* grpc_rb_cMdAry is the MetadataArray class whose instances proxy
|
61
|
+
* grpc_metadata_array. */
|
62
|
+
static VALUE grpc_rb_cMdAry;
|
63
|
+
|
44
64
|
/* id_cq is the name of the hidden ivar that preserves a reference to a
|
45
65
|
* completion queue */
|
46
66
|
static ID id_cq;
|
@@ -62,13 +82,22 @@ static ID id_metadata;
|
|
62
82
|
* received by the call and subsequently saved on it. */
|
63
83
|
static ID id_status;
|
64
84
|
|
85
|
+
/* sym_* are the symbol for attributes of grpc_rb_sBatchResult. */
|
86
|
+
static VALUE sym_send_message;
|
87
|
+
static VALUE sym_send_metadata;
|
88
|
+
static VALUE sym_send_close;
|
89
|
+
static VALUE sym_send_status;
|
90
|
+
static VALUE sym_message;
|
91
|
+
static VALUE sym_status;
|
92
|
+
static VALUE sym_cancelled;
|
93
|
+
|
65
94
|
/* hash_all_calls is a hash of Call address -> reference count that is used to
|
66
95
|
* track the creation and destruction of rb_call instances.
|
67
96
|
*/
|
68
97
|
static VALUE hash_all_calls;
|
69
98
|
|
70
99
|
/* Destroys a Call. */
|
71
|
-
void grpc_rb_call_destroy(void *p) {
|
100
|
+
static void grpc_rb_call_destroy(void *p) {
|
72
101
|
grpc_call *call = NULL;
|
73
102
|
VALUE ref_count = Qnil;
|
74
103
|
if (p == NULL) {
|
@@ -88,6 +117,38 @@ void grpc_rb_call_destroy(void *p) {
|
|
88
117
|
}
|
89
118
|
}
|
90
119
|
|
120
|
+
static size_t md_ary_datasize(const void *p) {
|
121
|
+
const grpc_metadata_array *const ary = (grpc_metadata_array *)p;
|
122
|
+
size_t i, datasize = sizeof(grpc_metadata_array);
|
123
|
+
for (i = 0; i < ary->count; ++i) {
|
124
|
+
const grpc_metadata *const md = &ary->metadata[i];
|
125
|
+
datasize += strlen(md->key);
|
126
|
+
datasize += md->value_length;
|
127
|
+
}
|
128
|
+
datasize += ary->capacity * sizeof(grpc_metadata);
|
129
|
+
return datasize;
|
130
|
+
}
|
131
|
+
|
132
|
+
static const rb_data_type_t grpc_rb_md_ary_data_type = {
|
133
|
+
"grpc_metadata_array",
|
134
|
+
{GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize},
|
135
|
+
NULL,
|
136
|
+
NULL,
|
137
|
+
0};
|
138
|
+
|
139
|
+
/* Describes grpc_call struct for RTypedData */
|
140
|
+
static const rb_data_type_t grpc_call_data_type = {
|
141
|
+
"grpc_call",
|
142
|
+
{GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE},
|
143
|
+
NULL,
|
144
|
+
NULL,
|
145
|
+
/* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
|
146
|
+
* grpc_rb_call_destroy
|
147
|
+
* touches a hash object.
|
148
|
+
* TODO(yugui) Directly use st_table and call the free function earlier?
|
149
|
+
*/
|
150
|
+
0};
|
151
|
+
|
91
152
|
/* Error code details is a hash containing text strings describing errors */
|
92
153
|
VALUE rb_error_code_details;
|
93
154
|
|
@@ -101,93 +162,15 @@ const char *grpc_call_error_detail_of(grpc_call_error err) {
|
|
101
162
|
return detail;
|
102
163
|
}
|
103
164
|
|
104
|
-
/* grpc_rb_call_add_metadata_hash_cb is the hash iteration callback used by
|
105
|
-
grpc_rb_call_add_metadata.
|
106
|
-
*/
|
107
|
-
int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) {
|
108
|
-
grpc_call *call = NULL;
|
109
|
-
grpc_metadata *md = NULL;
|
110
|
-
VALUE md_obj = Qnil;
|
111
|
-
VALUE md_obj_args[2];
|
112
|
-
VALUE flags = rb_ivar_get(call_obj, id_flags);
|
113
|
-
grpc_call_error err;
|
114
|
-
int array_length;
|
115
|
-
int i;
|
116
|
-
|
117
|
-
/* Construct a metadata object from key and value and add it */
|
118
|
-
Data_Get_Struct(call_obj, grpc_call, call);
|
119
|
-
md_obj_args[0] = key;
|
120
|
-
|
121
|
-
if (TYPE(val) == T_ARRAY) {
|
122
|
-
/* If the value is an array, add each value in the array separately */
|
123
|
-
array_length = RARRAY_LEN(val);
|
124
|
-
for (i = 0; i < array_length; i++) {
|
125
|
-
md_obj_args[1] = rb_ary_entry(val, i);
|
126
|
-
md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
|
127
|
-
md = grpc_rb_get_wrapped_metadata(md_obj);
|
128
|
-
err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
|
129
|
-
if (err != GRPC_CALL_OK) {
|
130
|
-
rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
|
131
|
-
grpc_call_error_detail_of(err), err);
|
132
|
-
return ST_STOP;
|
133
|
-
}
|
134
|
-
}
|
135
|
-
} else {
|
136
|
-
md_obj_args[1] = val;
|
137
|
-
md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
|
138
|
-
md = grpc_rb_get_wrapped_metadata(md_obj);
|
139
|
-
err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
|
140
|
-
if (err != GRPC_CALL_OK) {
|
141
|
-
rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
|
142
|
-
grpc_call_error_detail_of(err), err);
|
143
|
-
return ST_STOP;
|
144
|
-
}
|
145
|
-
}
|
146
|
-
|
147
|
-
return ST_CONTINUE;
|
148
|
-
}
|
149
|
-
|
150
|
-
/*
|
151
|
-
call-seq:
|
152
|
-
call.add_metadata(completion_queue, hash_elements, flags=nil)
|
153
|
-
|
154
|
-
Add metadata elements to the call from a ruby hash, to be sent upon
|
155
|
-
invocation. flags is a bit-field combination of the write flags defined
|
156
|
-
above. REQUIRES: grpc_call_invoke/grpc_call_accept have not been
|
157
|
-
called on this call. Produces no events. */
|
158
|
-
|
159
|
-
static VALUE grpc_rb_call_add_metadata(int argc, VALUE *argv, VALUE self) {
|
160
|
-
VALUE metadata;
|
161
|
-
VALUE flags = Qnil;
|
162
|
-
ID id_size = rb_intern("size");
|
163
|
-
|
164
|
-
/* "11" == 1 mandatory args, 1 (flags) is optional */
|
165
|
-
rb_scan_args(argc, argv, "11", &metadata, &flags);
|
166
|
-
if (NIL_P(flags)) {
|
167
|
-
flags = UINT2NUM(0); /* Default to no flags */
|
168
|
-
}
|
169
|
-
if (TYPE(metadata) != T_HASH) {
|
170
|
-
rb_raise(rb_eTypeError, "add metadata failed: metadata should be a hash");
|
171
|
-
return Qnil;
|
172
|
-
}
|
173
|
-
if (NUM2UINT(rb_funcall(metadata, id_size, 0)) == 0) {
|
174
|
-
return Qnil;
|
175
|
-
}
|
176
|
-
rb_ivar_set(self, id_flags, flags);
|
177
|
-
rb_ivar_set(self, id_input_md, metadata);
|
178
|
-
rb_hash_foreach(metadata, grpc_rb_call_add_metadata_hash_cb, self);
|
179
|
-
return Qnil;
|
180
|
-
}
|
181
|
-
|
182
165
|
/* Called by clients to cancel an RPC on the server.
|
183
166
|
Can be called multiple times, from any thread. */
|
184
167
|
static VALUE grpc_rb_call_cancel(VALUE self) {
|
185
168
|
grpc_call *call = NULL;
|
186
169
|
grpc_call_error err;
|
187
|
-
|
170
|
+
TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
|
188
171
|
err = grpc_call_cancel(call);
|
189
172
|
if (err != GRPC_CALL_OK) {
|
190
|
-
rb_raise(
|
173
|
+
rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)",
|
191
174
|
grpc_call_error_detail_of(err), err);
|
192
175
|
}
|
193
176
|
|
@@ -196,77 +179,20 @@ static VALUE grpc_rb_call_cancel(VALUE self) {
|
|
196
179
|
|
197
180
|
/*
|
198
181
|
call-seq:
|
199
|
-
|
200
|
-
|
201
|
-
Invoke the RPC. Starts sending metadata and request headers on the wire.
|
202
|
-
flags is a bit-field combination of the write flags defined above.
|
203
|
-
REQUIRES: Can be called at most once per call.
|
204
|
-
Can only be called on the client.
|
205
|
-
Produces a GRPC_INVOKE_ACCEPTED event on completion. */
|
206
|
-
static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) {
|
207
|
-
VALUE cqueue = Qnil;
|
208
|
-
VALUE metadata_read_tag = Qnil;
|
209
|
-
VALUE finished_tag = Qnil;
|
210
|
-
VALUE flags = Qnil;
|
211
|
-
grpc_call *call = NULL;
|
212
|
-
grpc_completion_queue *cq = NULL;
|
213
|
-
grpc_call_error err;
|
182
|
+
status = call.status
|
214
183
|
|
215
|
-
|
216
|
-
rb_scan_args(argc, argv, "31", &cqueue, &metadata_read_tag, &finished_tag,
|
217
|
-
&flags);
|
218
|
-
if (NIL_P(flags)) {
|
219
|
-
flags = UINT2NUM(0); /* Default to no flags */
|
220
|
-
}
|
221
|
-
cq = grpc_rb_get_wrapped_completion_queue(cqueue);
|
222
|
-
Data_Get_Struct(self, grpc_call, call);
|
223
|
-
err = grpc_call_invoke_old(call, cq, ROBJECT(metadata_read_tag),
|
224
|
-
ROBJECT(finished_tag), NUM2UINT(flags));
|
225
|
-
if (err != GRPC_CALL_OK) {
|
226
|
-
rb_raise(rb_eCallError, "invoke failed: %s (code=%d)",
|
227
|
-
grpc_call_error_detail_of(err), err);
|
228
|
-
}
|
229
|
-
|
230
|
-
/* Add the completion queue as an instance attribute, prevents it from being
|
231
|
-
* GCed until this call object is GCed */
|
232
|
-
rb_ivar_set(self, id_cq, cqueue);
|
233
|
-
|
234
|
-
return Qnil;
|
235
|
-
}
|
236
|
-
|
237
|
-
/* Initiate a read on a call. Output event contains a byte buffer with the
|
238
|
-
result of the read.
|
239
|
-
REQUIRES: No other reads are pending on the call. It is only safe to start
|
240
|
-
the next read after the corresponding read event is received. */
|
241
|
-
static VALUE grpc_rb_call_start_read(VALUE self, VALUE tag) {
|
242
|
-
grpc_call *call = NULL;
|
243
|
-
grpc_call_error err;
|
244
|
-
Data_Get_Struct(self, grpc_call, call);
|
245
|
-
err = grpc_call_start_read_old(call, ROBJECT(tag));
|
246
|
-
if (err != GRPC_CALL_OK) {
|
247
|
-
rb_raise(rb_eCallError, "start read failed: %s (code=%d)",
|
248
|
-
grpc_call_error_detail_of(err), err);
|
249
|
-
}
|
250
|
-
|
251
|
-
return Qnil;
|
252
|
-
}
|
253
|
-
|
254
|
-
/*
|
255
|
-
call-seq:
|
256
|
-
status = call.status
|
257
|
-
|
258
|
-
Gets the status object saved the call. */
|
184
|
+
Gets the status object saved the call. */
|
259
185
|
static VALUE grpc_rb_call_get_status(VALUE self) {
|
260
186
|
return rb_ivar_get(self, id_status);
|
261
187
|
}
|
262
188
|
|
263
189
|
/*
|
264
190
|
call-seq:
|
265
|
-
|
191
|
+
call.status = status
|
266
192
|
|
267
|
-
|
193
|
+
Saves a status object on the call. */
|
268
194
|
static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
|
269
|
-
if (!NIL_P(status) && rb_obj_class(status) !=
|
195
|
+
if (!NIL_P(status) && rb_obj_class(status) != grpc_rb_sStatus) {
|
270
196
|
rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Struct::Status>",
|
271
197
|
rb_obj_classname(status));
|
272
198
|
return Qnil;
|
@@ -277,18 +203,18 @@ static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
|
|
277
203
|
|
278
204
|
/*
|
279
205
|
call-seq:
|
280
|
-
|
206
|
+
metadata = call.metadata
|
281
207
|
|
282
|
-
|
208
|
+
Gets the metadata object saved the call. */
|
283
209
|
static VALUE grpc_rb_call_get_metadata(VALUE self) {
|
284
210
|
return rb_ivar_get(self, id_metadata);
|
285
211
|
}
|
286
212
|
|
287
213
|
/*
|
288
214
|
call-seq:
|
289
|
-
|
215
|
+
call.metadata = metadata
|
290
216
|
|
291
|
-
|
217
|
+
Saves the metadata hash on the call. */
|
292
218
|
static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
|
293
219
|
if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) {
|
294
220
|
rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: <Hash>",
|
@@ -299,176 +225,425 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
|
|
299
225
|
return rb_ivar_set(self, id_metadata, metadata);
|
300
226
|
}
|
301
227
|
|
302
|
-
/*
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
grpc_call_accept must have been called successfully.
|
317
|
-
Produces a GRPC_WRITE_ACCEPTED event. */
|
318
|
-
static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
|
319
|
-
VALUE byte_buffer = Qnil;
|
320
|
-
VALUE tag = Qnil;
|
321
|
-
VALUE flags = Qnil;
|
322
|
-
grpc_call *call = NULL;
|
323
|
-
grpc_byte_buffer *bfr = NULL;
|
324
|
-
grpc_call_error err;
|
228
|
+
/* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used
|
229
|
+
to fill grpc_metadata_array.
|
230
|
+
|
231
|
+
it's capacity should have been computed via a prior call to
|
232
|
+
grpc_rb_md_ary_fill_hash_cb
|
233
|
+
*/
|
234
|
+
static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
|
235
|
+
grpc_metadata_array *md_ary = NULL;
|
236
|
+
int array_length;
|
237
|
+
int i;
|
238
|
+
|
239
|
+
/* Construct a metadata object from key and value and add it */
|
240
|
+
TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
|
241
|
+
&grpc_rb_md_ary_data_type, md_ary);
|
325
242
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
243
|
+
if (TYPE(val) == T_ARRAY) {
|
244
|
+
/* If the value is an array, add capacity for each value in the array */
|
245
|
+
array_length = RARRAY_LEN(val);
|
246
|
+
for (i = 0; i < array_length; i++) {
|
247
|
+
if (TYPE(key) == T_SYMBOL) {
|
248
|
+
md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key));
|
249
|
+
} else { /* StringValueCStr does all other type exclusions for us */
|
250
|
+
md_ary->metadata[md_ary->count].key = StringValueCStr(key);
|
251
|
+
}
|
252
|
+
md_ary->metadata[md_ary->count].value = RSTRING_PTR(rb_ary_entry(val, i));
|
253
|
+
md_ary->metadata[md_ary->count].value_length =
|
254
|
+
RSTRING_LEN(rb_ary_entry(val, i));
|
255
|
+
md_ary->count += 1;
|
256
|
+
}
|
257
|
+
} else {
|
258
|
+
if (TYPE(key) == T_SYMBOL) {
|
259
|
+
md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key));
|
260
|
+
} else { /* StringValueCStr does all other type exclusions for us */
|
261
|
+
md_ary->metadata[md_ary->count].key = StringValueCStr(key);
|
262
|
+
}
|
263
|
+
md_ary->metadata[md_ary->count].value = RSTRING_PTR(val);
|
264
|
+
md_ary->metadata[md_ary->count].value_length = RSTRING_LEN(val);
|
265
|
+
md_ary->count += 1;
|
330
266
|
}
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
267
|
+
|
268
|
+
return ST_CONTINUE;
|
269
|
+
}
|
270
|
+
|
271
|
+
/* grpc_rb_md_ary_capacity_hash_cb is the hash iteration callback used
|
272
|
+
to pre-compute the capacity a grpc_metadata_array.
|
273
|
+
*/
|
274
|
+
static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val,
|
275
|
+
VALUE md_ary_obj) {
|
276
|
+
grpc_metadata_array *md_ary = NULL;
|
277
|
+
|
278
|
+
/* Construct a metadata object from key and value and add it */
|
279
|
+
TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
|
280
|
+
&grpc_rb_md_ary_data_type, md_ary);
|
281
|
+
|
282
|
+
if (TYPE(val) == T_ARRAY) {
|
283
|
+
/* If the value is an array, add capacity for each value in the array */
|
284
|
+
md_ary->capacity += RARRAY_LEN(val);
|
285
|
+
} else {
|
286
|
+
md_ary->capacity += 1;
|
337
287
|
}
|
288
|
+
return ST_CONTINUE;
|
289
|
+
}
|
338
290
|
|
339
|
-
|
291
|
+
/* grpc_rb_md_ary_convert converts a ruby metadata hash into
|
292
|
+
a grpc_metadata_array.
|
293
|
+
*/
|
294
|
+
static void grpc_rb_md_ary_convert(VALUE md_ary_hash,
|
295
|
+
grpc_metadata_array *md_ary) {
|
296
|
+
VALUE md_ary_obj = Qnil;
|
297
|
+
if (md_ary_hash == Qnil) {
|
298
|
+
return; /* Do nothing if the expected has value is nil */
|
299
|
+
}
|
300
|
+
if (TYPE(md_ary_hash) != T_HASH) {
|
301
|
+
rb_raise(rb_eTypeError, "md_ary_convert: got <%s>, want <Hash>",
|
302
|
+
rb_obj_classname(md_ary_hash));
|
303
|
+
return;
|
304
|
+
}
|
305
|
+
|
306
|
+
/* Initialize the array, compute it's capacity, then fill it. */
|
307
|
+
grpc_metadata_array_init(md_ary);
|
308
|
+
md_ary_obj =
|
309
|
+
TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary);
|
310
|
+
rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj);
|
311
|
+
md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata));
|
312
|
+
rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj);
|
340
313
|
}
|
341
314
|
|
342
|
-
/*
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
315
|
+
/* Converts a metadata array to a hash. */
|
316
|
+
VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary) {
|
317
|
+
VALUE key = Qnil;
|
318
|
+
VALUE new_ary = Qnil;
|
319
|
+
VALUE value = Qnil;
|
320
|
+
VALUE result = rb_hash_new();
|
321
|
+
size_t i;
|
322
|
+
|
323
|
+
for (i = 0; i < md_ary->count; i++) {
|
324
|
+
key = rb_str_new2(md_ary->metadata[i].key);
|
325
|
+
value = rb_hash_aref(result, key);
|
326
|
+
if (value == Qnil) {
|
327
|
+
value = rb_str_new(md_ary->metadata[i].value,
|
328
|
+
md_ary->metadata[i].value_length);
|
329
|
+
rb_hash_aset(result, key, value);
|
330
|
+
} else if (TYPE(value) == T_ARRAY) {
|
331
|
+
/* Add the string to the returned array */
|
332
|
+
rb_ary_push(value, rb_str_new(md_ary->metadata[i].value,
|
333
|
+
md_ary->metadata[i].value_length));
|
334
|
+
} else {
|
335
|
+
/* Add the current value with this key and the new one to an array */
|
336
|
+
new_ary = rb_ary_new();
|
337
|
+
rb_ary_push(new_ary, value);
|
338
|
+
rb_ary_push(new_ary, rb_str_new(md_ary->metadata[i].value,
|
339
|
+
md_ary->metadata[i].value_length));
|
340
|
+
rb_hash_aset(result, key, new_ary);
|
341
|
+
}
|
366
342
|
}
|
343
|
+
return result;
|
344
|
+
}
|
367
345
|
|
368
|
-
|
346
|
+
/* grpc_rb_call_check_op_keys_hash_cb is a hash iteration func that checks
|
347
|
+
each key of an ops hash is valid.
|
348
|
+
*/
|
349
|
+
static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val,
|
350
|
+
VALUE ops_ary) {
|
351
|
+
/* Update the capacity; the value is an array, add capacity for each value in
|
352
|
+
* the array */
|
353
|
+
if (TYPE(key) != T_FIXNUM) {
|
354
|
+
rb_raise(rb_eTypeError, "invalid operation : got <%s>, want <Fixnum>",
|
355
|
+
rb_obj_classname(key));
|
356
|
+
return ST_STOP;
|
357
|
+
}
|
358
|
+
switch (NUM2INT(key)) {
|
359
|
+
case GRPC_OP_SEND_INITIAL_METADATA:
|
360
|
+
case GRPC_OP_SEND_MESSAGE:
|
361
|
+
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
|
362
|
+
case GRPC_OP_SEND_STATUS_FROM_SERVER:
|
363
|
+
case GRPC_OP_RECV_INITIAL_METADATA:
|
364
|
+
case GRPC_OP_RECV_MESSAGE:
|
365
|
+
case GRPC_OP_RECV_STATUS_ON_CLIENT:
|
366
|
+
case GRPC_OP_RECV_CLOSE_ON_SERVER:
|
367
|
+
rb_ary_push(ops_ary, key);
|
368
|
+
return ST_CONTINUE;
|
369
|
+
default:
|
370
|
+
rb_raise(rb_eTypeError, "invalid operation : bad value %d", NUM2INT(key));
|
371
|
+
};
|
372
|
+
return ST_STOP;
|
369
373
|
}
|
370
374
|
|
371
|
-
/*
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
375
|
+
/* grpc_rb_op_update_status_from_server adds the values in a ruby status
|
376
|
+
struct to the 'send_status_from_server' portion of an op.
|
377
|
+
*/
|
378
|
+
static void grpc_rb_op_update_status_from_server(grpc_op *op,
|
379
|
+
grpc_metadata_array *md_ary,
|
380
|
+
VALUE status) {
|
381
|
+
VALUE code = rb_struct_aref(status, sym_code);
|
382
|
+
VALUE details = rb_struct_aref(status, sym_details);
|
383
|
+
VALUE metadata_hash = rb_struct_aref(status, sym_metadata);
|
384
|
+
|
385
|
+
/* TODO: add check to ensure status is the correct struct type */
|
386
|
+
if (TYPE(code) != T_FIXNUM) {
|
387
|
+
rb_raise(rb_eTypeError, "invalid code : got <%s>, want <Fixnum>",
|
388
|
+
rb_obj_classname(code));
|
389
|
+
return;
|
381
390
|
}
|
391
|
+
if (TYPE(details) != T_STRING) {
|
392
|
+
rb_raise(rb_eTypeError, "invalid details : got <%s>, want <String>",
|
393
|
+
rb_obj_classname(code));
|
394
|
+
return;
|
395
|
+
}
|
396
|
+
op->data.send_status_from_server.status = NUM2INT(code);
|
397
|
+
op->data.send_status_from_server.status_details = StringValueCStr(details);
|
398
|
+
grpc_rb_md_ary_convert(metadata_hash, md_ary);
|
399
|
+
op->data.send_status_from_server.trailing_metadata_count = md_ary->count;
|
400
|
+
op->data.send_status_from_server.trailing_metadata = md_ary->metadata;
|
401
|
+
}
|
382
402
|
|
383
|
-
|
403
|
+
/* run_batch_stack holds various values used by the
|
404
|
+
* grpc_rb_call_run_batch function */
|
405
|
+
typedef struct run_batch_stack {
|
406
|
+
/* The batch ops */
|
407
|
+
grpc_op ops[8]; /* 8 is the maximum number of operations */
|
408
|
+
size_t op_num; /* tracks the last added operation */
|
409
|
+
|
410
|
+
/* Data being sent */
|
411
|
+
grpc_metadata_array send_metadata;
|
412
|
+
grpc_metadata_array send_trailing_metadata;
|
413
|
+
|
414
|
+
/* Data being received */
|
415
|
+
grpc_byte_buffer *recv_message;
|
416
|
+
grpc_metadata_array recv_metadata;
|
417
|
+
grpc_metadata_array recv_trailing_metadata;
|
418
|
+
int recv_cancelled;
|
419
|
+
grpc_status_code recv_status;
|
420
|
+
char *recv_status_details;
|
421
|
+
size_t recv_status_details_capacity;
|
422
|
+
} run_batch_stack;
|
423
|
+
|
424
|
+
/* grpc_run_batch_stack_init ensures the run_batch_stack is properly
|
425
|
+
* initialized */
|
426
|
+
static void grpc_run_batch_stack_init(run_batch_stack *st) {
|
427
|
+
MEMZERO(st, run_batch_stack, 1);
|
428
|
+
grpc_metadata_array_init(&st->send_metadata);
|
429
|
+
grpc_metadata_array_init(&st->send_trailing_metadata);
|
430
|
+
grpc_metadata_array_init(&st->recv_metadata);
|
431
|
+
grpc_metadata_array_init(&st->recv_trailing_metadata);
|
432
|
+
st->op_num = 0;
|
384
433
|
}
|
385
434
|
|
386
|
-
/*
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
VALUE self) {
|
398
|
-
VALUE flags = Qnil;
|
399
|
-
grpc_call *call = NULL;
|
400
|
-
grpc_call_error err;
|
435
|
+
/* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
|
436
|
+
* cleaned up */
|
437
|
+
static void grpc_run_batch_stack_cleanup(run_batch_stack *st) {
|
438
|
+
grpc_metadata_array_destroy(&st->send_metadata);
|
439
|
+
grpc_metadata_array_destroy(&st->send_trailing_metadata);
|
440
|
+
grpc_metadata_array_destroy(&st->recv_metadata);
|
441
|
+
grpc_metadata_array_destroy(&st->recv_trailing_metadata);
|
442
|
+
if (st->recv_status_details != NULL) {
|
443
|
+
gpr_free(st->recv_status_details);
|
444
|
+
}
|
445
|
+
}
|
401
446
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
447
|
+
/* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from
|
448
|
+
* ops_hash */
|
449
|
+
static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
|
450
|
+
VALUE this_op = Qnil;
|
451
|
+
VALUE this_value = Qnil;
|
452
|
+
VALUE ops_ary = rb_ary_new();
|
453
|
+
size_t i = 0;
|
454
|
+
|
455
|
+
/* Create a ruby array with just the operation keys */
|
456
|
+
rb_hash_foreach(ops_hash, grpc_rb_call_check_op_keys_hash_cb, ops_ary);
|
457
|
+
|
458
|
+
/* Fill the ops array */
|
459
|
+
for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) {
|
460
|
+
this_op = rb_ary_entry(ops_ary, i);
|
461
|
+
this_value = rb_hash_aref(ops_hash, this_op);
|
462
|
+
switch (NUM2INT(this_op)) {
|
463
|
+
case GRPC_OP_SEND_INITIAL_METADATA:
|
464
|
+
/* N.B. later there is no need to explicitly delete the metadata keys
|
465
|
+
* and values, they are references to data in ruby objects. */
|
466
|
+
grpc_rb_md_ary_convert(this_value, &st->send_metadata);
|
467
|
+
st->ops[st->op_num].data.send_initial_metadata.count =
|
468
|
+
st->send_metadata.count;
|
469
|
+
st->ops[st->op_num].data.send_initial_metadata.metadata =
|
470
|
+
st->send_metadata.metadata;
|
471
|
+
break;
|
472
|
+
case GRPC_OP_SEND_MESSAGE:
|
473
|
+
st->ops[st->op_num].data.send_message = grpc_rb_s_to_byte_buffer(
|
474
|
+
RSTRING_PTR(this_value), RSTRING_LEN(this_value));
|
475
|
+
break;
|
476
|
+
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
|
477
|
+
break;
|
478
|
+
case GRPC_OP_SEND_STATUS_FROM_SERVER:
|
479
|
+
/* N.B. later there is no need to explicitly delete the metadata keys
|
480
|
+
* and values, they are references to data in ruby objects. */
|
481
|
+
grpc_rb_op_update_status_from_server(
|
482
|
+
&st->ops[st->op_num], &st->send_trailing_metadata, this_value);
|
483
|
+
break;
|
484
|
+
case GRPC_OP_RECV_INITIAL_METADATA:
|
485
|
+
st->ops[st->op_num].data.recv_initial_metadata = &st->recv_metadata;
|
486
|
+
break;
|
487
|
+
case GRPC_OP_RECV_MESSAGE:
|
488
|
+
st->ops[st->op_num].data.recv_message = &st->recv_message;
|
489
|
+
break;
|
490
|
+
case GRPC_OP_RECV_STATUS_ON_CLIENT:
|
491
|
+
st->ops[st->op_num].data.recv_status_on_client.trailing_metadata =
|
492
|
+
&st->recv_trailing_metadata;
|
493
|
+
st->ops[st->op_num].data.recv_status_on_client.status =
|
494
|
+
&st->recv_status;
|
495
|
+
st->ops[st->op_num].data.recv_status_on_client.status_details =
|
496
|
+
&st->recv_status_details;
|
497
|
+
st->ops[st->op_num].data.recv_status_on_client.status_details_capacity =
|
498
|
+
&st->recv_status_details_capacity;
|
499
|
+
break;
|
500
|
+
case GRPC_OP_RECV_CLOSE_ON_SERVER:
|
501
|
+
st->ops[st->op_num].data.recv_close_on_server.cancelled =
|
502
|
+
&st->recv_cancelled;
|
503
|
+
break;
|
504
|
+
default:
|
505
|
+
grpc_run_batch_stack_cleanup(st);
|
506
|
+
rb_raise(rb_eTypeError, "invalid operation : bad value %d",
|
507
|
+
NUM2INT(this_op));
|
508
|
+
};
|
509
|
+
st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op);
|
510
|
+
st->op_num++;
|
406
511
|
}
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
512
|
+
}
|
513
|
+
|
514
|
+
/* grpc_run_batch_stack_build_result fills constructs a ruby BatchResult struct
|
515
|
+
after the results have run */
|
516
|
+
static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) {
|
517
|
+
size_t i = 0;
|
518
|
+
VALUE result = rb_struct_new(grpc_rb_sBatchResult, Qnil, Qnil, Qnil, Qnil,
|
519
|
+
Qnil, Qnil, Qnil, Qnil, NULL);
|
520
|
+
for (i = 0; i < st->op_num; i++) {
|
521
|
+
switch (st->ops[i].op) {
|
522
|
+
case GRPC_OP_SEND_INITIAL_METADATA:
|
523
|
+
rb_struct_aset(result, sym_send_metadata, Qtrue);
|
524
|
+
break;
|
525
|
+
case GRPC_OP_SEND_MESSAGE:
|
526
|
+
rb_struct_aset(result, sym_send_message, Qtrue);
|
527
|
+
grpc_byte_buffer_destroy(st->ops[i].data.send_message);
|
528
|
+
break;
|
529
|
+
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
|
530
|
+
rb_struct_aset(result, sym_send_close, Qtrue);
|
531
|
+
break;
|
532
|
+
case GRPC_OP_SEND_STATUS_FROM_SERVER:
|
533
|
+
rb_struct_aset(result, sym_send_status, Qtrue);
|
534
|
+
break;
|
535
|
+
case GRPC_OP_RECV_INITIAL_METADATA:
|
536
|
+
rb_struct_aset(result, sym_metadata,
|
537
|
+
grpc_rb_md_ary_to_h(&st->recv_metadata));
|
538
|
+
case GRPC_OP_RECV_MESSAGE:
|
539
|
+
rb_struct_aset(result, sym_message,
|
540
|
+
grpc_rb_byte_buffer_to_s(st->recv_message));
|
541
|
+
break;
|
542
|
+
case GRPC_OP_RECV_STATUS_ON_CLIENT:
|
543
|
+
rb_struct_aset(
|
544
|
+
result, sym_status,
|
545
|
+
rb_struct_new(grpc_rb_sStatus, UINT2NUM(st->recv_status),
|
546
|
+
(st->recv_status_details == NULL
|
547
|
+
? Qnil
|
548
|
+
: rb_str_new2(st->recv_status_details)),
|
549
|
+
grpc_rb_md_ary_to_h(&st->recv_trailing_metadata),
|
550
|
+
NULL));
|
551
|
+
break;
|
552
|
+
case GRPC_OP_RECV_CLOSE_ON_SERVER:
|
553
|
+
rb_struct_aset(result, sym_send_close, Qtrue);
|
554
|
+
break;
|
555
|
+
default:
|
556
|
+
break;
|
557
|
+
}
|
412
558
|
}
|
413
|
-
return
|
559
|
+
return result;
|
414
560
|
}
|
415
561
|
|
416
562
|
/* call-seq:
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
563
|
+
cq = CompletionQueue.new
|
564
|
+
ops = {
|
565
|
+
GRPC::Core::CallOps::SEND_INITIAL_METADATA => <op_value>,
|
566
|
+
GRPC::Core::CallOps::SEND_MESSAGE => <op_value>,
|
567
|
+
...
|
568
|
+
}
|
569
|
+
tag = Object.new
|
570
|
+
timeout = 10
|
571
|
+
call.start_batch(cqueue, tag, timeout, ops)
|
572
|
+
|
573
|
+
Start a batch of operations defined in the array ops; when complete, post a
|
574
|
+
completion of type 'tag' to the completion queue bound to the call.
|
575
|
+
|
576
|
+
Also waits for the batch to complete, until timeout is reached.
|
577
|
+
The order of ops specified in the batch has no significance.
|
578
|
+
Only one operation of each type can be active at once in any given
|
579
|
+
batch */
|
580
|
+
static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
|
581
|
+
VALUE timeout, VALUE ops_hash) {
|
582
|
+
run_batch_stack st;
|
429
583
|
grpc_call *call = NULL;
|
430
|
-
|
584
|
+
grpc_event *ev = NULL;
|
431
585
|
grpc_call_error err;
|
432
|
-
|
433
|
-
|
586
|
+
VALUE result = Qnil;
|
587
|
+
TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
|
588
|
+
|
589
|
+
/* Validate the ops args, adding them to a ruby array */
|
590
|
+
if (TYPE(ops_hash) != T_HASH) {
|
591
|
+
rb_raise(rb_eTypeError, "call#run_batch: ops hash should be a hash");
|
592
|
+
return Qnil;
|
593
|
+
}
|
594
|
+
grpc_run_batch_stack_init(&st);
|
595
|
+
grpc_run_batch_stack_fill_ops(&st, ops_hash);
|
596
|
+
|
597
|
+
/* call grpc_call_start_batch, then wait for it to complete using
|
598
|
+
* pluck_event */
|
599
|
+
err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag));
|
434
600
|
if (err != GRPC_CALL_OK) {
|
435
|
-
|
601
|
+
grpc_run_batch_stack_cleanup(&st);
|
602
|
+
rb_raise(grpc_rb_eCallError,
|
603
|
+
"grpc_call_start_batch failed with %s (code=%d)",
|
436
604
|
grpc_call_error_detail_of(err), err);
|
605
|
+
return Qnil;
|
606
|
+
}
|
607
|
+
ev = grpc_rb_completion_queue_pluck_event(cqueue, tag, timeout);
|
608
|
+
if (ev == NULL) {
|
609
|
+
grpc_run_batch_stack_cleanup(&st);
|
610
|
+
rb_raise(grpc_rb_eOutOfTime, "grpc_call_start_batch timed out");
|
611
|
+
return Qnil;
|
612
|
+
}
|
613
|
+
if (ev->data.op_complete != GRPC_OP_OK) {
|
614
|
+
grpc_run_batch_stack_cleanup(&st);
|
615
|
+
rb_raise(grpc_rb_eCallError, "start_batch completion failed, (code=%d)",
|
616
|
+
ev->data.op_complete);
|
617
|
+
return Qnil;
|
437
618
|
}
|
438
619
|
|
439
|
-
/*
|
440
|
-
|
441
|
-
|
442
|
-
return
|
620
|
+
/* Build and return the BatchResult struct result */
|
621
|
+
result = grpc_run_batch_stack_build_result(&st);
|
622
|
+
grpc_run_batch_stack_cleanup(&st);
|
623
|
+
return result;
|
443
624
|
}
|
444
625
|
|
445
|
-
|
446
|
-
VALUE rb_cCall = Qnil;
|
447
|
-
|
448
|
-
/* rb_eCallError is the ruby class of the exception thrown during call
|
449
|
-
operations; */
|
450
|
-
VALUE rb_eCallError = Qnil;
|
451
|
-
|
452
|
-
void Init_grpc_error_codes() {
|
626
|
+
static void Init_grpc_error_codes() {
|
453
627
|
/* Constants representing the error codes of grpc_call_error in grpc.h */
|
454
|
-
VALUE
|
455
|
-
|
456
|
-
rb_define_const(
|
457
|
-
rb_define_const(
|
628
|
+
VALUE grpc_rb_mRpcErrors =
|
629
|
+
rb_define_module_under(grpc_rb_mGrpcCore, "RpcErrors");
|
630
|
+
rb_define_const(grpc_rb_mRpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
|
631
|
+
rb_define_const(grpc_rb_mRpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
|
632
|
+
rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_SERVER",
|
458
633
|
UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER));
|
459
|
-
rb_define_const(
|
634
|
+
rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_CLIENT",
|
460
635
|
UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT));
|
461
|
-
rb_define_const(
|
636
|
+
rb_define_const(grpc_rb_mRpcErrors, "ALREADY_ACCEPTED",
|
462
637
|
UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED));
|
463
|
-
rb_define_const(
|
638
|
+
rb_define_const(grpc_rb_mRpcErrors, "ALREADY_INVOKED",
|
464
639
|
UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED));
|
465
|
-
rb_define_const(
|
640
|
+
rb_define_const(grpc_rb_mRpcErrors, "NOT_INVOKED",
|
466
641
|
UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED));
|
467
|
-
rb_define_const(
|
642
|
+
rb_define_const(grpc_rb_mRpcErrors, "ALREADY_FINISHED",
|
468
643
|
UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED));
|
469
|
-
rb_define_const(
|
644
|
+
rb_define_const(grpc_rb_mRpcErrors, "TOO_MANY_OPERATIONS",
|
470
645
|
UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
|
471
|
-
rb_define_const(
|
646
|
+
rb_define_const(grpc_rb_mRpcErrors, "INVALID_FLAGS",
|
472
647
|
UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS));
|
473
648
|
|
474
649
|
/* Add the detail strings to a Hash */
|
@@ -496,37 +671,54 @@ void Init_grpc_error_codes() {
|
|
496
671
|
rb_str_new2("outstanding read or write present"));
|
497
672
|
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS),
|
498
673
|
rb_str_new2("a bad flag was given"));
|
499
|
-
rb_define_const(
|
674
|
+
rb_define_const(grpc_rb_mRpcErrors, "ErrorMessages", rb_error_code_details);
|
500
675
|
rb_obj_freeze(rb_error_code_details);
|
501
676
|
}
|
502
677
|
|
678
|
+
static void Init_grpc_op_codes() {
|
679
|
+
/* Constants representing operation type codes in grpc.h */
|
680
|
+
VALUE grpc_rb_mCallOps = rb_define_module_under(grpc_rb_mGrpcCore, "CallOps");
|
681
|
+
rb_define_const(grpc_rb_mCallOps, "SEND_INITIAL_METADATA",
|
682
|
+
UINT2NUM(GRPC_OP_SEND_INITIAL_METADATA));
|
683
|
+
rb_define_const(grpc_rb_mCallOps, "SEND_MESSAGE",
|
684
|
+
UINT2NUM(GRPC_OP_SEND_MESSAGE));
|
685
|
+
rb_define_const(grpc_rb_mCallOps, "SEND_CLOSE_FROM_CLIENT",
|
686
|
+
UINT2NUM(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
|
687
|
+
rb_define_const(grpc_rb_mCallOps, "SEND_STATUS_FROM_SERVER",
|
688
|
+
UINT2NUM(GRPC_OP_SEND_STATUS_FROM_SERVER));
|
689
|
+
rb_define_const(grpc_rb_mCallOps, "RECV_INITIAL_METADATA",
|
690
|
+
UINT2NUM(GRPC_OP_RECV_INITIAL_METADATA));
|
691
|
+
rb_define_const(grpc_rb_mCallOps, "RECV_MESSAGE",
|
692
|
+
UINT2NUM(GRPC_OP_RECV_MESSAGE));
|
693
|
+
rb_define_const(grpc_rb_mCallOps, "RECV_STATUS_ON_CLIENT",
|
694
|
+
UINT2NUM(GRPC_OP_RECV_STATUS_ON_CLIENT));
|
695
|
+
rb_define_const(grpc_rb_mCallOps, "RECV_CLOSE_ON_SERVER",
|
696
|
+
UINT2NUM(GRPC_OP_RECV_CLOSE_ON_SERVER));
|
697
|
+
}
|
698
|
+
|
503
699
|
void Init_grpc_call() {
|
504
700
|
/* CallError inherits from Exception to signal that it is non-recoverable */
|
505
|
-
|
506
|
-
rb_define_class_under(
|
507
|
-
|
701
|
+
grpc_rb_eCallError =
|
702
|
+
rb_define_class_under(grpc_rb_mGrpcCore, "CallError", rb_eException);
|
703
|
+
grpc_rb_eOutOfTime =
|
704
|
+
rb_define_class_under(grpc_rb_mGrpcCore, "OutOfTime", rb_eException);
|
705
|
+
grpc_rb_cCall = rb_define_class_under(grpc_rb_mGrpcCore, "Call", rb_cObject);
|
706
|
+
grpc_rb_cMdAry =
|
707
|
+
rb_define_class_under(grpc_rb_mGrpcCore, "MetadataArray", rb_cObject);
|
508
708
|
|
509
709
|
/* Prevent allocation or inialization of the Call class */
|
510
|
-
rb_define_alloc_func(
|
511
|
-
rb_define_method(
|
512
|
-
rb_define_method(
|
710
|
+
rb_define_alloc_func(grpc_rb_cCall, grpc_rb_cannot_alloc);
|
711
|
+
rb_define_method(grpc_rb_cCall, "initialize", grpc_rb_cannot_init, 0);
|
712
|
+
rb_define_method(grpc_rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy,
|
713
|
+
1);
|
513
714
|
|
514
715
|
/* Add ruby analogues of the Call methods. */
|
515
|
-
rb_define_method(
|
516
|
-
rb_define_method(
|
517
|
-
|
518
|
-
rb_define_method(
|
519
|
-
rb_define_method(
|
520
|
-
rb_define_method(
|
521
|
-
rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1);
|
522
|
-
rb_define_method(rb_cCall, "start_write", grpc_rb_call_start_write, -1);
|
523
|
-
rb_define_method(rb_cCall, "start_write_status",
|
524
|
-
grpc_rb_call_start_write_status, 3);
|
525
|
-
rb_define_method(rb_cCall, "writes_done", grpc_rb_call_writes_done, 1);
|
526
|
-
rb_define_method(rb_cCall, "status", grpc_rb_call_get_status, 0);
|
527
|
-
rb_define_method(rb_cCall, "status=", grpc_rb_call_set_status, 1);
|
528
|
-
rb_define_method(rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
|
529
|
-
rb_define_method(rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
|
716
|
+
rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4);
|
717
|
+
rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0);
|
718
|
+
rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0);
|
719
|
+
rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1);
|
720
|
+
rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
|
721
|
+
rb_define_method(grpc_rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
|
530
722
|
|
531
723
|
/* Ids used to support call attributes */
|
532
724
|
id_metadata = rb_intern("metadata");
|
@@ -537,18 +729,33 @@ void Init_grpc_call() {
|
|
537
729
|
id_flags = rb_intern("__flags");
|
538
730
|
id_input_md = rb_intern("__input_md");
|
539
731
|
|
732
|
+
/* Ids used in constructing the batch result. */
|
733
|
+
sym_send_message = ID2SYM(rb_intern("send_message"));
|
734
|
+
sym_send_metadata = ID2SYM(rb_intern("send_metadata"));
|
735
|
+
sym_send_close = ID2SYM(rb_intern("send_close"));
|
736
|
+
sym_send_status = ID2SYM(rb_intern("send_status"));
|
737
|
+
sym_message = ID2SYM(rb_intern("message"));
|
738
|
+
sym_status = ID2SYM(rb_intern("status"));
|
739
|
+
sym_cancelled = ID2SYM(rb_intern("cancelled"));
|
740
|
+
|
741
|
+
/* The Struct used to return the run_batch result. */
|
742
|
+
grpc_rb_sBatchResult = rb_struct_define(
|
743
|
+
"BatchResult", "send_message", "send_metadata", "send_close",
|
744
|
+
"send_status", "message", "metadata", "status", "cancelled", NULL);
|
745
|
+
|
540
746
|
/* The hash for reference counting calls, to ensure they can't be destroyed
|
541
747
|
* more than once */
|
542
748
|
hash_all_calls = rb_hash_new();
|
543
|
-
rb_define_const(
|
749
|
+
rb_define_const(grpc_rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
|
544
750
|
|
545
751
|
Init_grpc_error_codes();
|
752
|
+
Init_grpc_op_codes();
|
546
753
|
}
|
547
754
|
|
548
755
|
/* Gets the call from the ruby object */
|
549
756
|
grpc_call *grpc_rb_get_wrapped_call(VALUE v) {
|
550
757
|
grpc_call *c = NULL;
|
551
|
-
|
758
|
+
TypedData_Get_Struct(v, grpc_call, &grpc_call_data_type, c);
|
552
759
|
return c;
|
553
760
|
}
|
554
761
|
|
@@ -565,5 +772,5 @@ VALUE grpc_rb_wrap_call(grpc_call *c) {
|
|
565
772
|
rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c),
|
566
773
|
UINT2NUM(NUM2UINT(obj) + 1));
|
567
774
|
}
|
568
|
-
return
|
775
|
+
return TypedData_Wrap_Struct(grpc_rb_cCall, &grpc_call_data_type, c);
|
569
776
|
}
|