blob: be89db884653807462a3604a6e8dc0efd558aca1 [file] [log] [blame]
Masood Malekghassemi743c10c2015-06-16 18:05:27 -07001# Copyright 2015, Google Inc.
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met:
7#
8# * Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# * Redistributions in binary form must reproduce the above
11# copyright notice, this list of conditions and the following disclaimer
12# in the documentation and/or other materials provided with the
13# distribution.
14# * Neither the name of Google Inc. nor the names of its
15# contributors may be used to endorse or promote products derived from
16# this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30from grpc._cython._cygrpc cimport grpc
31from grpc._cython._cygrpc cimport call
32from grpc._cython._cygrpc cimport server
33
34
Masood Malekghassemiaed42a82015-12-07 16:35:40 -080035class ConnectivityState:
36 idle = grpc.GRPC_CHANNEL_IDLE
37 connecting = grpc.GRPC_CHANNEL_CONNECTING
38 ready = grpc.GRPC_CHANNEL_READY
39 transient_failure = grpc.GRPC_CHANNEL_TRANSIENT_FAILURE
40 fatal_failure = grpc.GRPC_CHANNEL_FATAL_FAILURE
41
42
43class ChannelArgKey:
44 enable_census = grpc.GRPC_ARG_ENABLE_CENSUS
45 max_concurrent_streams = grpc.GRPC_ARG_MAX_CONCURRENT_STREAMS
46 max_message_length = grpc.GRPC_ARG_MAX_MESSAGE_LENGTH
47 http2_initial_sequence_number = grpc.GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
48 http2_hpack_table_size_decoder = grpc.GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER
49 http2_hpack_table_size_encoder = grpc.GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER
50 default_authority = grpc.GRPC_ARG_DEFAULT_AUTHORITY
51 primary_user_agent_string = grpc.GRPC_ARG_PRIMARY_USER_AGENT_STRING
52 secondary_user_agent_string = grpc.GRPC_ARG_SECONDARY_USER_AGENT_STRING
53 ssl_target_name_override = grpc.GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
54
55
56class WriteFlag:
57 buffer_hint = grpc.GRPC_WRITE_BUFFER_HINT
58 no_compress = grpc.GRPC_WRITE_NO_COMPRESS
59
60
Masood Malekghassemi743c10c2015-06-16 18:05:27 -070061class StatusCode:
62 ok = grpc.GRPC_STATUS_OK
63 cancelled = grpc.GRPC_STATUS_CANCELLED
64 unknown = grpc.GRPC_STATUS_UNKNOWN
65 invalid_argument = grpc.GRPC_STATUS_INVALID_ARGUMENT
66 deadline_exceeded = grpc.GRPC_STATUS_DEADLINE_EXCEEDED
67 not_found = grpc.GRPC_STATUS_NOT_FOUND
68 already_exists = grpc.GRPC_STATUS_ALREADY_EXISTS
69 permission_denied = grpc.GRPC_STATUS_PERMISSION_DENIED
70 unauthenticated = grpc.GRPC_STATUS_UNAUTHENTICATED
71 resource_exhausted = grpc.GRPC_STATUS_RESOURCE_EXHAUSTED
72 failed_precondition = grpc.GRPC_STATUS_FAILED_PRECONDITION
73 aborted = grpc.GRPC_STATUS_ABORTED
74 out_of_range = grpc.GRPC_STATUS_OUT_OF_RANGE
75 unimplemented = grpc.GRPC_STATUS_UNIMPLEMENTED
76 internal = grpc.GRPC_STATUS_INTERNAL
77 unavailable = grpc.GRPC_STATUS_UNAVAILABLE
78 data_loss = grpc.GRPC_STATUS_DATA_LOSS
79
80
81class CallError:
82 ok = grpc.GRPC_CALL_OK
83 error = grpc.GRPC_CALL_ERROR
84 not_on_server = grpc.GRPC_CALL_ERROR_NOT_ON_SERVER
85 not_on_client = grpc.GRPC_CALL_ERROR_NOT_ON_CLIENT
86 already_accepted = grpc.GRPC_CALL_ERROR_ALREADY_ACCEPTED
87 already_invoked = grpc.GRPC_CALL_ERROR_ALREADY_INVOKED
88 not_invoked = grpc.GRPC_CALL_ERROR_NOT_INVOKED
89 already_finished = grpc.GRPC_CALL_ERROR_ALREADY_FINISHED
90 too_many_operations = grpc.GRPC_CALL_ERROR_TOO_MANY_OPERATIONS
91 invalid_flags = grpc.GRPC_CALL_ERROR_INVALID_FLAGS
92 invalid_metadata = grpc.GRPC_CALL_ERROR_INVALID_METADATA
93
94
95class CompletionType:
96 queue_shutdown = grpc.GRPC_QUEUE_SHUTDOWN
97 queue_timeout = grpc.GRPC_QUEUE_TIMEOUT
98 operation_complete = grpc.GRPC_OP_COMPLETE
99
100
101class OperationType:
102 send_initial_metadata = grpc.GRPC_OP_SEND_INITIAL_METADATA
103 send_message = grpc.GRPC_OP_SEND_MESSAGE
104 send_close_from_client = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT
105 send_status_from_server = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER
106 receive_initial_metadata = grpc.GRPC_OP_RECV_INITIAL_METADATA
107 receive_message = grpc.GRPC_OP_RECV_MESSAGE
108 receive_status_on_client = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
109 receive_close_on_server = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER
110
111
112cdef class Timespec:
113
114 def __cinit__(self, time):
115 if time is None:
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700116 self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME)
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800117 return
118 if isinstance(time, int):
119 time = float(time)
120 if isinstance(time, float):
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700121 if time == float("+inf"):
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700122 self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME)
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700123 elif time == float("-inf"):
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700124 self.c_time = grpc.gpr_inf_past(grpc.GPR_CLOCK_REALTIME)
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700125 else:
126 self.c_time.seconds = time
127 self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700128 self.c_time.clock_type = grpc.GPR_CLOCK_REALTIME
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800129 elif isinstance(time, Timespec):
130 self.c_time = (<Timespec>time).c_time
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700131 else:
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800132 raise TypeError("expected time to be float, int, or Timespec, not {}"
133 .format(type(time)))
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700134
135 @property
136 def seconds(self):
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700137 # TODO(atash) ensure that everywhere a Timespec is created that it's
138 # converted to GPR_CLOCK_REALTIME then and not every time someone wants to
139 # read values off in Python.
140 cdef grpc.gpr_timespec real_time = (
141 grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
142 return real_time.seconds
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700143
144 @property
145 def nanoseconds(self):
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700146 cdef grpc.gpr_timespec real_time = (
147 grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
148 return real_time.nanoseconds
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700149
150 def __float__(self):
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700151 cdef grpc.gpr_timespec real_time = (
152 grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
153 return <double>real_time.seconds + <double>real_time.nanoseconds / 1e9
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700154
155 infinite_future = Timespec(float("+inf"))
156 infinite_past = Timespec(float("-inf"))
157
158
159cdef class CallDetails:
160
161 def __cinit__(self):
162 grpc.grpc_call_details_init(&self.c_details)
163
164 def __dealloc__(self):
165 grpc.grpc_call_details_destroy(&self.c_details)
166
167 @property
168 def method(self):
169 if self.c_details.method != NULL:
170 return <bytes>self.c_details.method
171 else:
172 return None
173
174 @property
175 def host(self):
176 if self.c_details.host != NULL:
177 return <bytes>self.c_details.host
178 else:
179 return None
180
181 @property
182 def deadline(self):
183 timespec = Timespec(float("-inf"))
184 timespec.c_time = self.c_details.deadline
185 return timespec
186
187
188cdef class OperationTag:
189
190 def __cinit__(self, user_tag):
191 self.user_tag = user_tag
192 self.references = []
193
194
195cdef class Event:
196
197 def __cinit__(self, grpc.grpc_completion_type type, bint success,
198 object tag, call.Call operation_call,
199 CallDetails request_call_details,
200 Metadata request_metadata,
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800201 bint is_new_request,
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700202 Operations batch_operations):
203 self.type = type
204 self.success = success
205 self.tag = tag
206 self.operation_call = operation_call
207 self.request_call_details = request_call_details
208 self.request_metadata = request_metadata
209 self.batch_operations = batch_operations
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800210 self.is_new_request = is_new_request
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700211
212
213cdef class ByteBuffer:
214
215 def __cinit__(self, data):
216 if data is None:
217 self.c_byte_buffer = NULL
218 return
219 if isinstance(data, bytes):
220 pass
221 elif isinstance(data, basestring):
222 data = data.encode()
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800223 elif isinstance(data, ByteBuffer):
224 data = (<ByteBuffer>data).bytes()
225 if data is None:
226 self.c_byte_buffer = NULL
227 return
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700228 else:
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800229 raise TypeError("expected value to be of type str, bytes, or "
230 "ByteBuffer, not {}".format(type(data)))
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700231
232 cdef char *c_data = data
233 data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data))
234 self.c_byte_buffer = grpc.grpc_raw_byte_buffer_create(
235 &data_slice, 1)
236 grpc.gpr_slice_unref(data_slice)
237
238 def bytes(self):
239 cdef grpc.grpc_byte_buffer_reader reader
240 cdef grpc.gpr_slice data_slice
241 cdef size_t data_slice_length
242 cdef void *data_slice_pointer
243 if self.c_byte_buffer != NULL:
244 grpc.grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer)
245 result = b""
246 while grpc.grpc_byte_buffer_reader_next(&reader, &data_slice):
247 data_slice_pointer = grpc.gpr_slice_start_ptr(data_slice)
248 data_slice_length = grpc.gpr_slice_length(data_slice)
249 result += (<char *>data_slice_pointer)[:data_slice_length]
250 grpc.grpc_byte_buffer_reader_destroy(&reader)
251 return result
252 else:
253 return None
254
255 def __len__(self):
256 if self.c_byte_buffer != NULL:
257 return grpc.grpc_byte_buffer_length(self.c_byte_buffer)
258 else:
259 return 0
260
261 def __str__(self):
262 return self.bytes()
263
264 def __dealloc__(self):
265 if self.c_byte_buffer != NULL:
266 grpc.grpc_byte_buffer_destroy(self.c_byte_buffer)
267
268
269cdef class SslPemKeyCertPair:
270
271 def __cinit__(self, private_key, certificate_chain):
272 if isinstance(private_key, bytes):
273 self.private_key = private_key
274 elif isinstance(private_key, basestring):
275 self.private_key = private_key.encode()
276 else:
277 raise TypeError("expected private_key to be of type str or bytes")
278 if isinstance(certificate_chain, bytes):
279 self.certificate_chain = certificate_chain
280 elif isinstance(certificate_chain, basestring):
281 self.certificate_chain = certificate_chain.encode()
282 else:
283 raise TypeError("expected certificate_chain to be of type str or bytes "
284 "or int")
285 self.c_pair.private_key = self.private_key
286 self.c_pair.certificate_chain = self.certificate_chain
287
288
289cdef class ChannelArg:
290
291 def __cinit__(self, key, value):
292 if isinstance(key, bytes):
293 self.key = key
294 elif isinstance(key, basestring):
295 self.key = key.encode()
296 else:
297 raise TypeError("expected key to be of type str or bytes")
298 if isinstance(value, bytes):
299 self.value = value
300 self.c_arg.type = grpc.GRPC_ARG_STRING
301 self.c_arg.value.string = self.value
302 elif isinstance(value, basestring):
303 self.value = value.encode()
304 self.c_arg.type = grpc.GRPC_ARG_STRING
305 self.c_arg.value.string = self.value
306 elif isinstance(value, int):
307 self.value = int(value)
308 self.c_arg.type = grpc.GRPC_ARG_INTEGER
309 self.c_arg.value.integer = self.value
310 else:
311 raise TypeError("expected value to be of type str or bytes or int")
312 self.c_arg.key = self.key
313
314
315cdef class ChannelArgs:
316
317 def __cinit__(self, args):
318 self.args = list(args)
319 for arg in self.args:
320 if not isinstance(arg, ChannelArg):
321 raise TypeError("expected list of ChannelArg")
322 self.c_args.arguments_length = len(self.args)
323 self.c_args.arguments = <grpc.grpc_arg *>grpc.gpr_malloc(
324 self.c_args.arguments_length*sizeof(grpc.grpc_arg)
325 )
326 for i in range(self.c_args.arguments_length):
327 self.c_args.arguments[i] = (<ChannelArg>self.args[i]).c_arg
328
329 def __dealloc__(self):
330 grpc.gpr_free(self.c_args.arguments)
331
332 def __len__(self):
333 # self.args is never stale; it's only updated from this file
334 return len(self.args)
335
336 def __getitem__(self, size_t i):
337 # self.args is never stale; it's only updated from this file
338 return self.args[i]
339
340
341cdef class Metadatum:
342
343 def __cinit__(self, key, value):
344 if isinstance(key, bytes):
345 self._key = key
346 elif isinstance(key, basestring):
347 self._key = key.encode()
348 else:
349 raise TypeError("expected key to be of type str or bytes")
350 if isinstance(value, bytes):
351 self._value = value
352 elif isinstance(value, basestring):
353 self._value = value.encode()
354 else:
355 raise TypeError("expected value to be of type str or bytes")
356 self.c_metadata.key = self._key
357 self.c_metadata.value = self._value
358 self.c_metadata.value_length = len(self._value)
359
360 @property
361 def key(self):
362 return <bytes>self.c_metadata.key
363
364 @property
365 def value(self):
366 return <bytes>self.c_metadata.value[:self.c_metadata.value_length]
367
368 def __len__(self):
369 return 2
370
371 def __getitem__(self, size_t i):
372 if i == 0:
373 return self.key
374 elif i == 1:
375 return self.value
376 else:
377 raise IndexError("index must be 0 (key) or 1 (value)")
378
379 def __iter__(self):
380 return iter((self.key, self.value))
381
382
383cdef class _MetadataIterator:
384
385 cdef size_t i
386 cdef Metadata metadata
387
388 def __cinit__(self, Metadata metadata not None):
389 self.i = 0
390 self.metadata = metadata
391
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700392 def __iter__(self):
393 return self
394
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700395 def __next__(self):
396 if self.i < len(self.metadata):
397 result = self.metadata[self.i]
398 self.i = self.i + 1
399 return result
400 else:
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700401 raise StopIteration
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700402
403
404cdef class Metadata:
405
406 def __cinit__(self, metadata):
407 self.metadata = list(metadata)
408 for metadatum in metadata:
409 if not isinstance(metadatum, Metadatum):
410 raise TypeError("expected list of Metadatum")
411 grpc.grpc_metadata_array_init(&self.c_metadata_array)
412 self.c_metadata_array.count = len(self.metadata)
413 self.c_metadata_array.capacity = len(self.metadata)
414 self.c_metadata_array.metadata = <grpc.grpc_metadata *>grpc.gpr_malloc(
415 self.c_metadata_array.count*sizeof(grpc.grpc_metadata)
416 )
417 for i in range(self.c_metadata_array.count):
418 self.c_metadata_array.metadata[i] = (
419 (<Metadatum>self.metadata[i]).c_metadata)
420
421 def __dealloc__(self):
422 # this frees the allocated memory for the grpc_metadata_array (although
423 # it'd be nice if that were documented somewhere...) TODO(atash): document
424 # this in the C core
425 grpc.grpc_metadata_array_destroy(&self.c_metadata_array)
426
427 def __len__(self):
428 return self.c_metadata_array.count
429
430 def __getitem__(self, size_t i):
431 return Metadatum(
432 key=<bytes>self.c_metadata_array.metadata[i].key,
433 value=<bytes>self.c_metadata_array.metadata[i].value[
434 :self.c_metadata_array.metadata[i].value_length])
435
436 def __iter__(self):
437 return _MetadataIterator(self)
438
439
440cdef class Operation:
441
442 def __cinit__(self):
443 self.references = []
444 self._received_status_details = NULL
445 self._received_status_details_capacity = 0
446 self.is_valid = False
447
448 @property
449 def type(self):
450 return self.c_op.type
451
452 @property
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800453 def has_status(self):
454 return self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
455
456 @property
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700457 def received_message(self):
458 if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
459 raise TypeError("self must be an operation receiving a message")
460 return self._received_message
461
462 @property
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800463 def received_message_or_none(self):
464 if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
465 return None
466 return self._received_message
467
468 @property
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700469 def received_metadata(self):
470 if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
471 self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
472 raise TypeError("self must be an operation receiving metadata")
473 return self._received_metadata
474
475 @property
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800476 def received_metadata_or_none(self):
477 if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
478 self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
479 return None
480 return self._received_metadata
481
482 @property
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700483 def received_status_code(self):
484 if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
485 raise TypeError("self must be an operation receiving a status code")
486 return self._received_status_code
487
488 @property
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800489 def received_status_code_or_none(self):
490 if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
491 return None
492 return self._received_status_code
493
494 @property
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700495 def received_status_details(self):
496 if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
497 raise TypeError("self must be an operation receiving status details")
498 if self._received_status_details:
499 return self._received_status_details
500 else:
501 return None
502
503 @property
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800504 def received_status_details_or_none(self):
505 if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
506 return None
507 if self._received_status_details:
508 return self._received_status_details
509 else:
510 return None
511
512 @property
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700513 def received_cancelled(self):
514 if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
515 raise TypeError("self must be an operation receiving cancellation "
516 "information")
517 return False if self._received_cancelled == 0 else True
518
Masood Malekghassemiaed42a82015-12-07 16:35:40 -0800519 @property
520 def received_cancelled_or_none(self):
521 if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
522 return None
523 return False if self._received_cancelled == 0 else True
524
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700525 def __dealloc__(self):
526 # We *almost* don't need to do anything; most of the objects are handled by
527 # Python. The remaining one(s) are primitive fields filled in by GRPC core.
528 # This means that we need to clean up after receive_status_on_client.
529 if self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
530 grpc.gpr_free(self._received_status_details)
531
532def operation_send_initial_metadata(Metadata metadata):
533 cdef Operation op = Operation()
534 op.c_op.type = grpc.GRPC_OP_SEND_INITIAL_METADATA
535 op.c_op.data.send_initial_metadata.count = metadata.c_metadata_array.count
536 op.c_op.data.send_initial_metadata.metadata = (
537 metadata.c_metadata_array.metadata)
538 op.references.append(metadata)
539 op.is_valid = True
540 return op
541
542def operation_send_message(data):
543 cdef Operation op = Operation()
544 op.c_op.type = grpc.GRPC_OP_SEND_MESSAGE
545 byte_buffer = ByteBuffer(data)
546 op.c_op.data.send_message = byte_buffer.c_byte_buffer
547 op.references.append(byte_buffer)
548 op.is_valid = True
549 return op
550
551def operation_send_close_from_client():
552 cdef Operation op = Operation()
553 op.c_op.type = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT
554 op.is_valid = True
555 return op
556
557def operation_send_status_from_server(
558 Metadata metadata, grpc.grpc_status_code code, details):
559 if isinstance(details, bytes):
560 pass
561 elif isinstance(details, basestring):
562 details = details.encode()
563 else:
564 raise TypeError("expected a str or bytes object for details")
565 cdef Operation op = Operation()
566 op.c_op.type = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER
567 op.c_op.data.send_status_from_server.trailing_metadata_count = (
568 metadata.c_metadata_array.count)
569 op.c_op.data.send_status_from_server.trailing_metadata = (
570 metadata.c_metadata_array.metadata)
571 op.c_op.data.send_status_from_server.status = code
572 op.c_op.data.send_status_from_server.status_details = details
573 op.references.append(metadata)
574 op.references.append(details)
575 op.is_valid = True
576 return op
577
578def operation_receive_initial_metadata():
579 cdef Operation op = Operation()
580 op.c_op.type = grpc.GRPC_OP_RECV_INITIAL_METADATA
581 op._received_metadata = Metadata([])
582 op.c_op.data.receive_initial_metadata = (
583 &op._received_metadata.c_metadata_array)
584 op.is_valid = True
585 return op
586
587def operation_receive_message():
588 cdef Operation op = Operation()
589 op.c_op.type = grpc.GRPC_OP_RECV_MESSAGE
590 op._received_message = ByteBuffer(None)
591 # n.b. the c_op.data.receive_message field needs to be deleted by us,
592 # anyway, so we just let that be handled by the ByteBuffer() we allocated
593 # the line before.
594 op.c_op.data.receive_message = &op._received_message.c_byte_buffer
595 op.is_valid = True
596 return op
597
598def operation_receive_status_on_client():
599 cdef Operation op = Operation()
600 op.c_op.type = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
601 op._received_metadata = Metadata([])
602 op.c_op.data.receive_status_on_client.trailing_metadata = (
603 &op._received_metadata.c_metadata_array)
604 op.c_op.data.receive_status_on_client.status = (
605 &op._received_status_code)
606 op.c_op.data.receive_status_on_client.status_details = (
607 &op._received_status_details)
608 op.c_op.data.receive_status_on_client.status_details_capacity = (
609 &op._received_status_details_capacity)
610 op.is_valid = True
611 return op
612
613def operation_receive_close_on_server():
614 cdef Operation op = Operation()
615 op.c_op.type = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER
616 op.c_op.data.receive_close_on_server.cancelled = &op._received_cancelled
617 op.is_valid = True
618 return op
619
620
621cdef class _OperationsIterator:
622
623 cdef size_t i
624 cdef Operations operations
625
626 def __cinit__(self, Operations operations not None):
627 self.i = 0
628 self.operations = operations
629
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700630 def __iter__(self):
631 return self
632
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700633 def __next__(self):
634 if self.i < len(self.operations):
635 result = self.operations[self.i]
636 self.i = self.i + 1
637 return result
638 else:
Masood Malekghassemi5a65bcd2015-09-25 11:27:10 -0700639 raise StopIteration
Masood Malekghassemi743c10c2015-06-16 18:05:27 -0700640
641
642cdef class Operations:
643
644 def __cinit__(self, operations):
645 self.operations = list(operations) # normalize iterable
646 self.c_ops = NULL
647 self.c_nops = 0
648 for operation in self.operations:
649 if not isinstance(operation, Operation):
650 raise TypeError("expected operations to be iterable of Operation")
651 self.c_nops = len(self.operations)
652 self.c_ops = <grpc.grpc_op *>grpc.gpr_malloc(
653 sizeof(grpc.grpc_op)*self.c_nops)
654 for i in range(self.c_nops):
655 self.c_ops[i] = (<Operation>(self.operations[i])).c_op
656
657 def __len__(self):
658 return self.c_nops
659
660 def __getitem__(self, size_t i):
661 # self.operations is never stale; it's only updated from this file
662 return self.operations[i]
663
664 def __dealloc__(self):
665 grpc.gpr_free(self.c_ops)
666
667 def __iter__(self):
668 return _OperationsIterator(self)
669