grpc 0.5.0
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +1 -0
- data/.rubocop.yml +10 -0
- data/.rubocop_todo.yml +52 -0
- data/Gemfile +4 -0
- data/README.md +82 -0
- data/Rakefile +54 -0
- data/bin/apis/google/protobuf/empty.rb +44 -0
- data/bin/apis/pubsub_demo.rb +267 -0
- data/bin/apis/tech/pubsub/proto/pubsub.rb +174 -0
- data/bin/apis/tech/pubsub/proto/pubsub_services.rb +103 -0
- data/bin/interop/README.md +8 -0
- data/bin/interop/interop_client.rb +334 -0
- data/bin/interop/interop_server.rb +192 -0
- data/bin/interop/test/cpp/interop/empty.rb +44 -0
- data/bin/interop/test/cpp/interop/messages.rb +89 -0
- data/bin/interop/test/cpp/interop/test.rb +43 -0
- data/bin/interop/test/cpp/interop/test_services.rb +60 -0
- data/bin/math.proto +80 -0
- data/bin/math.rb +61 -0
- data/bin/math_client.rb +147 -0
- data/bin/math_server.rb +190 -0
- data/bin/math_services.rb +56 -0
- data/bin/noproto_client.rb +108 -0
- data/bin/noproto_server.rb +112 -0
- data/ext/grpc/extconf.rb +76 -0
- data/ext/grpc/rb_byte_buffer.c +241 -0
- data/ext/grpc/rb_byte_buffer.h +54 -0
- data/ext/grpc/rb_call.c +569 -0
- data/ext/grpc/rb_call.h +59 -0
- data/ext/grpc/rb_channel.c +264 -0
- data/ext/grpc/rb_channel.h +49 -0
- data/ext/grpc/rb_channel_args.c +154 -0
- data/ext/grpc/rb_channel_args.h +52 -0
- data/ext/grpc/rb_completion_queue.c +185 -0
- data/ext/grpc/rb_completion_queue.h +50 -0
- data/ext/grpc/rb_credentials.c +281 -0
- data/ext/grpc/rb_credentials.h +50 -0
- data/ext/grpc/rb_event.c +361 -0
- data/ext/grpc/rb_event.h +53 -0
- data/ext/grpc/rb_grpc.c +274 -0
- data/ext/grpc/rb_grpc.h +74 -0
- data/ext/grpc/rb_metadata.c +215 -0
- data/ext/grpc/rb_metadata.h +53 -0
- data/ext/grpc/rb_server.c +278 -0
- data/ext/grpc/rb_server.h +50 -0
- data/ext/grpc/rb_server_credentials.c +210 -0
- data/ext/grpc/rb_server_credentials.h +50 -0
- data/grpc.gemspec +41 -0
- data/lib/grpc.rb +39 -0
- data/lib/grpc/core/event.rb +44 -0
- data/lib/grpc/core/time_consts.rb +71 -0
- data/lib/grpc/errors.rb +61 -0
- data/lib/grpc/generic/active_call.rb +536 -0
- data/lib/grpc/generic/bidi_call.rb +221 -0
- data/lib/grpc/generic/client_stub.rb +413 -0
- data/lib/grpc/generic/rpc_desc.rb +150 -0
- data/lib/grpc/generic/rpc_server.rb +404 -0
- data/lib/grpc/generic/service.rb +235 -0
- data/lib/grpc/logconfig.rb +40 -0
- data/lib/grpc/version.rb +33 -0
- data/spec/alloc_spec.rb +44 -0
- data/spec/byte_buffer_spec.rb +67 -0
- data/spec/call_spec.rb +163 -0
- data/spec/channel_spec.rb +181 -0
- data/spec/client_server_spec.rb +372 -0
- data/spec/completion_queue_spec.rb +74 -0
- data/spec/credentials_spec.rb +71 -0
- data/spec/event_spec.rb +53 -0
- data/spec/generic/active_call_spec.rb +373 -0
- data/spec/generic/client_stub_spec.rb +519 -0
- data/spec/generic/rpc_desc_spec.rb +357 -0
- data/spec/generic/rpc_server_pool_spec.rb +139 -0
- data/spec/generic/rpc_server_spec.rb +404 -0
- data/spec/generic/service_spec.rb +342 -0
- data/spec/metadata_spec.rb +64 -0
- data/spec/server_credentials_spec.rb +69 -0
- data/spec/server_spec.rb +212 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/testdata/README +1 -0
- data/spec/testdata/ca.pem +15 -0
- data/spec/testdata/server1.key +16 -0
- data/spec/testdata/server1.pem +16 -0
- data/spec/time_consts_spec.rb +89 -0
- metadata +353 -0
@@ -0,0 +1,54 @@
|
|
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 <grpc/grpc.h>
|
38
|
+
#include <ruby.h>
|
39
|
+
|
40
|
+
/* rb_cByteBuffer is the ByteBuffer class whose instances proxy
|
41
|
+
grpc_byte_buffer. */
|
42
|
+
extern VALUE rb_cByteBuffer;
|
43
|
+
|
44
|
+
/* Initializes the ByteBuffer class. */
|
45
|
+
void Init_grpc_byte_buffer();
|
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);
|
53
|
+
|
54
|
+
#endif /* GRPC_RB_BYTE_BUFFER_H_ */
|
data/ext/grpc/rb_call.c
ADDED
@@ -0,0 +1,569 @@
|
|
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
|
+
#include "rb_call.h"
|
35
|
+
|
36
|
+
#include <ruby.h>
|
37
|
+
|
38
|
+
#include <grpc/grpc.h>
|
39
|
+
#include "rb_byte_buffer.h"
|
40
|
+
#include "rb_completion_queue.h"
|
41
|
+
#include "rb_metadata.h"
|
42
|
+
#include "rb_grpc.h"
|
43
|
+
|
44
|
+
/* id_cq is the name of the hidden ivar that preserves a reference to a
|
45
|
+
* completion queue */
|
46
|
+
static ID id_cq;
|
47
|
+
|
48
|
+
/* id_flags is the name of the hidden ivar that preserves the value of
|
49
|
+
* the flags used to create metadata from a Hash */
|
50
|
+
static ID id_flags;
|
51
|
+
|
52
|
+
/* id_input_md is the name of the hidden ivar that preserves the hash used to
|
53
|
+
* create metadata, so that references to the strings it contains last as long
|
54
|
+
* as the call the metadata is added to. */
|
55
|
+
static ID id_input_md;
|
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_status is name of the attribute used to access the status object
|
62
|
+
* received by the call and subsequently saved on it. */
|
63
|
+
static ID id_status;
|
64
|
+
|
65
|
+
/* hash_all_calls is a hash of Call address -> reference count that is used to
|
66
|
+
* track the creation and destruction of rb_call instances.
|
67
|
+
*/
|
68
|
+
static VALUE hash_all_calls;
|
69
|
+
|
70
|
+
/* Destroys a Call. */
|
71
|
+
void grpc_rb_call_destroy(void *p) {
|
72
|
+
grpc_call *call = NULL;
|
73
|
+
VALUE ref_count = Qnil;
|
74
|
+
if (p == NULL) {
|
75
|
+
return;
|
76
|
+
};
|
77
|
+
call = (grpc_call *)p;
|
78
|
+
|
79
|
+
ref_count = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)call));
|
80
|
+
if (ref_count == Qnil) {
|
81
|
+
return; /* No longer in the hash, so already deleted */
|
82
|
+
} else if (NUM2UINT(ref_count) == 1) {
|
83
|
+
rb_hash_delete(hash_all_calls, OFFT2NUM((VALUE)call));
|
84
|
+
grpc_call_destroy(call);
|
85
|
+
} else {
|
86
|
+
rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)call),
|
87
|
+
UINT2NUM(NUM2UINT(ref_count) - 1));
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
/* Error code details is a hash containing text strings describing errors */
|
92
|
+
VALUE rb_error_code_details;
|
93
|
+
|
94
|
+
/* Obtains the error detail string for given error code */
|
95
|
+
const char *grpc_call_error_detail_of(grpc_call_error err) {
|
96
|
+
VALUE detail_ref = rb_hash_aref(rb_error_code_details, UINT2NUM(err));
|
97
|
+
const char *detail = "unknown error code!";
|
98
|
+
if (detail_ref != Qnil) {
|
99
|
+
detail = StringValueCStr(detail_ref);
|
100
|
+
}
|
101
|
+
return detail;
|
102
|
+
}
|
103
|
+
|
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
|
+
/* Called by clients to cancel an RPC on the server.
|
183
|
+
Can be called multiple times, from any thread. */
|
184
|
+
static VALUE grpc_rb_call_cancel(VALUE self) {
|
185
|
+
grpc_call *call = NULL;
|
186
|
+
grpc_call_error err;
|
187
|
+
Data_Get_Struct(self, grpc_call, call);
|
188
|
+
err = grpc_call_cancel(call);
|
189
|
+
if (err != GRPC_CALL_OK) {
|
190
|
+
rb_raise(rb_eCallError, "cancel failed: %s (code=%d)",
|
191
|
+
grpc_call_error_detail_of(err), err);
|
192
|
+
}
|
193
|
+
|
194
|
+
return Qnil;
|
195
|
+
}
|
196
|
+
|
197
|
+
/*
|
198
|
+
call-seq:
|
199
|
+
call.invoke(completion_queue, tag, flags=nil)
|
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;
|
214
|
+
|
215
|
+
/* "31" == 3 mandatory args, 1 (flags) is optional */
|
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. */
|
259
|
+
static VALUE grpc_rb_call_get_status(VALUE self) {
|
260
|
+
return rb_ivar_get(self, id_status);
|
261
|
+
}
|
262
|
+
|
263
|
+
/*
|
264
|
+
call-seq:
|
265
|
+
call.status = status
|
266
|
+
|
267
|
+
Saves a status object on the call. */
|
268
|
+
static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
|
269
|
+
if (!NIL_P(status) && rb_obj_class(status) != rb_sStatus) {
|
270
|
+
rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Struct::Status>",
|
271
|
+
rb_obj_classname(status));
|
272
|
+
return Qnil;
|
273
|
+
}
|
274
|
+
|
275
|
+
return rb_ivar_set(self, id_status, status);
|
276
|
+
}
|
277
|
+
|
278
|
+
/*
|
279
|
+
call-seq:
|
280
|
+
metadata = call.metadata
|
281
|
+
|
282
|
+
Gets the metadata object saved the call. */
|
283
|
+
static VALUE grpc_rb_call_get_metadata(VALUE self) {
|
284
|
+
return rb_ivar_get(self, id_metadata);
|
285
|
+
}
|
286
|
+
|
287
|
+
/*
|
288
|
+
call-seq:
|
289
|
+
call.metadata = metadata
|
290
|
+
|
291
|
+
Saves the metadata hash on the call. */
|
292
|
+
static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
|
293
|
+
if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) {
|
294
|
+
rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: <Hash>",
|
295
|
+
rb_obj_classname(metadata));
|
296
|
+
return Qnil;
|
297
|
+
}
|
298
|
+
|
299
|
+
return rb_ivar_set(self, id_metadata, metadata);
|
300
|
+
}
|
301
|
+
|
302
|
+
/*
|
303
|
+
call-seq:
|
304
|
+
call.start_write(byte_buffer, tag, flags=nil)
|
305
|
+
|
306
|
+
Queue a byte buffer for writing.
|
307
|
+
flags is a bit-field combination of the write flags defined above.
|
308
|
+
A write with byte_buffer null is allowed, and will not send any bytes on the
|
309
|
+
wire. If this is performed without GRPC_WRITE_BUFFER_HINT flag it provides
|
310
|
+
a mechanism to flush any previously buffered writes to outgoing flow control.
|
311
|
+
REQUIRES: No other writes are pending on the call. It is only safe to
|
312
|
+
start the next write after the corresponding write_accepted event
|
313
|
+
is received.
|
314
|
+
GRPC_INVOKE_ACCEPTED must have been received by the application
|
315
|
+
prior to calling this on the client. On the server,
|
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;
|
325
|
+
|
326
|
+
/* "21" == 2 mandatory args, 1 (flags) is optional */
|
327
|
+
rb_scan_args(argc, argv, "21", &byte_buffer, &tag, &flags);
|
328
|
+
if (NIL_P(flags)) {
|
329
|
+
flags = UINT2NUM(0); /* Default to no flags */
|
330
|
+
}
|
331
|
+
bfr = grpc_rb_get_wrapped_byte_buffer(byte_buffer);
|
332
|
+
Data_Get_Struct(self, grpc_call, call);
|
333
|
+
err = grpc_call_start_write_old(call, bfr, ROBJECT(tag), NUM2UINT(flags));
|
334
|
+
if (err != GRPC_CALL_OK) {
|
335
|
+
rb_raise(rb_eCallError, "start write failed: %s (code=%d)",
|
336
|
+
grpc_call_error_detail_of(err), err);
|
337
|
+
}
|
338
|
+
|
339
|
+
return Qnil;
|
340
|
+
}
|
341
|
+
|
342
|
+
/* Queue a status for writing.
|
343
|
+
|
344
|
+
call-seq:
|
345
|
+
tag = Object.new
|
346
|
+
call.write_status(200, "OK", tag)
|
347
|
+
|
348
|
+
REQUIRES: No other writes are pending on the call. It is only safe to
|
349
|
+
start the next write after the corresponding write_accepted event
|
350
|
+
is received.
|
351
|
+
GRPC_INVOKE_ACCEPTED must have been received by the application
|
352
|
+
prior to calling this.
|
353
|
+
Only callable on the server.
|
354
|
+
Produces a GRPC_FINISHED event when the status is sent and the stream is
|
355
|
+
fully closed */
|
356
|
+
static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE code,
|
357
|
+
VALUE status, VALUE tag) {
|
358
|
+
grpc_call *call = NULL;
|
359
|
+
grpc_call_error err;
|
360
|
+
Data_Get_Struct(self, grpc_call, call);
|
361
|
+
err = grpc_call_start_write_status_old(call, NUM2UINT(code),
|
362
|
+
StringValueCStr(status), ROBJECT(tag));
|
363
|
+
if (err != GRPC_CALL_OK) {
|
364
|
+
rb_raise(rb_eCallError, "start write status: %s (code=%d)",
|
365
|
+
grpc_call_error_detail_of(err), err);
|
366
|
+
}
|
367
|
+
|
368
|
+
return Qnil;
|
369
|
+
}
|
370
|
+
|
371
|
+
/* No more messages to send.
|
372
|
+
REQUIRES: No other writes are pending on the call. */
|
373
|
+
static VALUE grpc_rb_call_writes_done(VALUE self, VALUE tag) {
|
374
|
+
grpc_call *call = NULL;
|
375
|
+
grpc_call_error err;
|
376
|
+
Data_Get_Struct(self, grpc_call, call);
|
377
|
+
err = grpc_call_writes_done_old(call, ROBJECT(tag));
|
378
|
+
if (err != GRPC_CALL_OK) {
|
379
|
+
rb_raise(rb_eCallError, "writes done: %s (code=%d)",
|
380
|
+
grpc_call_error_detail_of(err), err);
|
381
|
+
}
|
382
|
+
|
383
|
+
return Qnil;
|
384
|
+
}
|
385
|
+
|
386
|
+
/* call-seq:
|
387
|
+
call.server_end_initial_metadata(flag)
|
388
|
+
|
389
|
+
Only to be called on servers, before sending messages.
|
390
|
+
flags is a bit-field combination of the write flags defined above.
|
391
|
+
|
392
|
+
REQUIRES: Can be called at most once per call.
|
393
|
+
Can only be called on the server, must be called after
|
394
|
+
grpc_call_server_accept
|
395
|
+
Produces no events */
|
396
|
+
static VALUE grpc_rb_call_server_end_initial_metadata(int argc, VALUE *argv,
|
397
|
+
VALUE self) {
|
398
|
+
VALUE flags = Qnil;
|
399
|
+
grpc_call *call = NULL;
|
400
|
+
grpc_call_error err;
|
401
|
+
|
402
|
+
/* "01" == 1 (flags) is optional */
|
403
|
+
rb_scan_args(argc, argv, "01", &flags);
|
404
|
+
if (NIL_P(flags)) {
|
405
|
+
flags = UINT2NUM(0); /* Default to no flags */
|
406
|
+
}
|
407
|
+
Data_Get_Struct(self, grpc_call, call);
|
408
|
+
err = grpc_call_server_end_initial_metadata_old(call, NUM2UINT(flags));
|
409
|
+
if (err != GRPC_CALL_OK) {
|
410
|
+
rb_raise(rb_eCallError, "end_initial_metadata failed: %s (code=%d)",
|
411
|
+
grpc_call_error_detail_of(err), err);
|
412
|
+
}
|
413
|
+
return Qnil;
|
414
|
+
}
|
415
|
+
|
416
|
+
/* call-seq:
|
417
|
+
call.server_accept(completion_queue, finished_tag)
|
418
|
+
|
419
|
+
Accept an incoming RPC, binding a completion queue to it.
|
420
|
+
To be called before sending or receiving messages.
|
421
|
+
|
422
|
+
REQUIRES: Can be called at most once per call.
|
423
|
+
Can only be called on the server.
|
424
|
+
Produces a GRPC_FINISHED event with finished_tag when the call has been
|
425
|
+
completed (there may be other events for the call pending at this
|
426
|
+
time) */
|
427
|
+
static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue,
|
428
|
+
VALUE finished_tag) {
|
429
|
+
grpc_call *call = NULL;
|
430
|
+
grpc_completion_queue *cq = grpc_rb_get_wrapped_completion_queue(cqueue);
|
431
|
+
grpc_call_error err;
|
432
|
+
Data_Get_Struct(self, grpc_call, call);
|
433
|
+
err = grpc_call_server_accept_old(call, cq, ROBJECT(finished_tag));
|
434
|
+
if (err != GRPC_CALL_OK) {
|
435
|
+
rb_raise(rb_eCallError, "server_accept failed: %s (code=%d)",
|
436
|
+
grpc_call_error_detail_of(err), err);
|
437
|
+
}
|
438
|
+
|
439
|
+
/* Add the completion queue as an instance attribute, prevents it from being
|
440
|
+
* GCed until this call object is GCed */
|
441
|
+
rb_ivar_set(self, id_cq, cqueue);
|
442
|
+
return Qnil;
|
443
|
+
}
|
444
|
+
|
445
|
+
/* rb_cCall is the ruby class that proxies grpc_call. */
|
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() {
|
453
|
+
/* Constants representing the error codes of grpc_call_error in grpc.h */
|
454
|
+
VALUE rb_RpcErrors = rb_define_module_under(rb_mGrpcCore, "RpcErrors");
|
455
|
+
rb_define_const(rb_RpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
|
456
|
+
rb_define_const(rb_RpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
|
457
|
+
rb_define_const(rb_RpcErrors, "NOT_ON_SERVER",
|
458
|
+
UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER));
|
459
|
+
rb_define_const(rb_RpcErrors, "NOT_ON_CLIENT",
|
460
|
+
UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT));
|
461
|
+
rb_define_const(rb_RpcErrors, "ALREADY_ACCEPTED",
|
462
|
+
UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED));
|
463
|
+
rb_define_const(rb_RpcErrors, "ALREADY_INVOKED",
|
464
|
+
UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED));
|
465
|
+
rb_define_const(rb_RpcErrors, "NOT_INVOKED",
|
466
|
+
UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED));
|
467
|
+
rb_define_const(rb_RpcErrors, "ALREADY_FINISHED",
|
468
|
+
UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED));
|
469
|
+
rb_define_const(rb_RpcErrors, "TOO_MANY_OPERATIONS",
|
470
|
+
UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
|
471
|
+
rb_define_const(rb_RpcErrors, "INVALID_FLAGS",
|
472
|
+
UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS));
|
473
|
+
|
474
|
+
/* Add the detail strings to a Hash */
|
475
|
+
rb_error_code_details = rb_hash_new();
|
476
|
+
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_OK),
|
477
|
+
rb_str_new2("ok"));
|
478
|
+
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR),
|
479
|
+
rb_str_new2("unknown error"));
|
480
|
+
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER),
|
481
|
+
rb_str_new2("not available on a server"));
|
482
|
+
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT),
|
483
|
+
rb_str_new2("not available on a client"));
|
484
|
+
rb_hash_aset(rb_error_code_details,
|
485
|
+
UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED),
|
486
|
+
rb_str_new2("call is already accepted"));
|
487
|
+
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED),
|
488
|
+
rb_str_new2("call is already invoked"));
|
489
|
+
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED),
|
490
|
+
rb_str_new2("call is not yet invoked"));
|
491
|
+
rb_hash_aset(rb_error_code_details,
|
492
|
+
UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED),
|
493
|
+
rb_str_new2("call is already finished"));
|
494
|
+
rb_hash_aset(rb_error_code_details,
|
495
|
+
UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS),
|
496
|
+
rb_str_new2("outstanding read or write present"));
|
497
|
+
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS),
|
498
|
+
rb_str_new2("a bad flag was given"));
|
499
|
+
rb_define_const(rb_RpcErrors, "ErrorMessages", rb_error_code_details);
|
500
|
+
rb_obj_freeze(rb_error_code_details);
|
501
|
+
}
|
502
|
+
|
503
|
+
void Init_grpc_call() {
|
504
|
+
/* CallError inherits from Exception to signal that it is non-recoverable */
|
505
|
+
rb_eCallError =
|
506
|
+
rb_define_class_under(rb_mGrpcCore, "CallError", rb_eException);
|
507
|
+
rb_cCall = rb_define_class_under(rb_mGrpcCore, "Call", rb_cObject);
|
508
|
+
|
509
|
+
/* Prevent allocation or inialization of the Call class */
|
510
|
+
rb_define_alloc_func(rb_cCall, grpc_rb_cannot_alloc);
|
511
|
+
rb_define_method(rb_cCall, "initialize", grpc_rb_cannot_init, 0);
|
512
|
+
rb_define_method(rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy, 1);
|
513
|
+
|
514
|
+
/* Add ruby analogues of the Call methods. */
|
515
|
+
rb_define_method(rb_cCall, "server_accept", grpc_rb_call_server_accept, 2);
|
516
|
+
rb_define_method(rb_cCall, "server_end_initial_metadata",
|
517
|
+
grpc_rb_call_server_end_initial_metadata, -1);
|
518
|
+
rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata, -1);
|
519
|
+
rb_define_method(rb_cCall, "cancel", grpc_rb_call_cancel, 0);
|
520
|
+
rb_define_method(rb_cCall, "invoke", grpc_rb_call_invoke, -1);
|
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);
|
530
|
+
|
531
|
+
/* Ids used to support call attributes */
|
532
|
+
id_metadata = rb_intern("metadata");
|
533
|
+
id_status = rb_intern("status");
|
534
|
+
|
535
|
+
/* Ids used by the c wrapping internals. */
|
536
|
+
id_cq = rb_intern("__cq");
|
537
|
+
id_flags = rb_intern("__flags");
|
538
|
+
id_input_md = rb_intern("__input_md");
|
539
|
+
|
540
|
+
/* The hash for reference counting calls, to ensure they can't be destroyed
|
541
|
+
* more than once */
|
542
|
+
hash_all_calls = rb_hash_new();
|
543
|
+
rb_define_const(rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
|
544
|
+
|
545
|
+
Init_grpc_error_codes();
|
546
|
+
}
|
547
|
+
|
548
|
+
/* Gets the call from the ruby object */
|
549
|
+
grpc_call *grpc_rb_get_wrapped_call(VALUE v) {
|
550
|
+
grpc_call *c = NULL;
|
551
|
+
Data_Get_Struct(v, grpc_call, c);
|
552
|
+
return c;
|
553
|
+
}
|
554
|
+
|
555
|
+
/* Obtains the wrapped object for a given call */
|
556
|
+
VALUE grpc_rb_wrap_call(grpc_call *c) {
|
557
|
+
VALUE obj = Qnil;
|
558
|
+
if (c == NULL) {
|
559
|
+
return Qnil;
|
560
|
+
}
|
561
|
+
obj = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)c));
|
562
|
+
if (obj == Qnil) { /* Not in the hash add it */
|
563
|
+
rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c), UINT2NUM(1));
|
564
|
+
} else {
|
565
|
+
rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c),
|
566
|
+
UINT2NUM(NUM2UINT(obj) + 1));
|
567
|
+
}
|
568
|
+
return Data_Wrap_Struct(rb_cCall, GC_NOT_MARKED, grpc_rb_call_destroy, c);
|
569
|
+
}
|