mirror of https://github.com/grpc/grpc.git
Exposes the C core batch API to the Python layers. Provides a shim to enable the old Python API to remain the same (for now).pull/1558/head
parent
4bbc821637
commit
a2918d2e04
36 changed files with 3097 additions and 2957 deletions
@ -1,86 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "grpc/_adapter/_completion_queue.h" |
||||
#include "grpc/_adapter/_channel.h" |
||||
#include "grpc/_adapter/_call.h" |
||||
#include "grpc/_adapter/_server.h" |
||||
#include "grpc/_adapter/_client_credentials.h" |
||||
#include "grpc/_adapter/_server_credentials.h" |
||||
|
||||
static PyObject *init(PyObject *self) { |
||||
grpc_init(); |
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
static PyObject *shutdown(PyObject *self) { |
||||
grpc_shutdown(); |
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
static PyMethodDef _c_methods[] = { |
||||
{"init", (PyCFunction)init, METH_NOARGS, |
||||
"Initialize the module's static state."}, |
||||
{"shut_down", (PyCFunction)shutdown, METH_NOARGS, |
||||
"Shut down the module's static state."}, |
||||
{NULL}, |
||||
}; |
||||
|
||||
PyMODINIT_FUNC init_c(void) { |
||||
PyObject *module; |
||||
|
||||
module = Py_InitModule3("_c", _c_methods, |
||||
"Wrappings of C structures and functions."); |
||||
|
||||
if (pygrpc_add_completion_queue(module) == -1) { |
||||
return; |
||||
} |
||||
if (pygrpc_add_channel(module) == -1) { |
||||
return; |
||||
} |
||||
if (pygrpc_add_call(module) == -1) { |
||||
return; |
||||
} |
||||
if (pygrpc_add_server(module) == -1) { |
||||
return; |
||||
} |
||||
if (pygrpc_add_client_credentials(module) == -1) { |
||||
return; |
||||
} |
||||
if (pygrpc_add_server_credentials(module) == -1) { |
||||
return; |
||||
} |
||||
} |
@ -0,0 +1,271 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC__ADAPTER__C_TYPES_H_ |
||||
#define GRPC__ADAPTER__C_TYPES_H_ |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/grpc_security.h> |
||||
|
||||
|
||||
/*=========================*/ |
||||
/* Client-side credentials */ |
||||
/*=========================*/ |
||||
|
||||
typedef struct ClientCredentials { |
||||
PyObject_HEAD |
||||
grpc_credentials *c_creds; |
||||
} ClientCredentials; |
||||
void pygrpc_ClientCredentials_dealloc(ClientCredentials *self); |
||||
ClientCredentials *pygrpc_ClientCredentials_google_default( |
||||
PyTypeObject *type, PyObject *ignored); |
||||
ClientCredentials *pygrpc_ClientCredentials_ssl( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
ClientCredentials *pygrpc_ClientCredentials_composite( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
ClientCredentials *pygrpc_ClientCredentials_compute_engine( |
||||
PyTypeObject *type, PyObject *ignored); |
||||
ClientCredentials *pygrpc_ClientCredentials_service_account( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
ClientCredentials *pygrpc_ClientCredentials_jwt( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
ClientCredentials *pygrpc_ClientCredentials_refresh_token( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
ClientCredentials *pygrpc_ClientCredentials_fake_transport_security( |
||||
PyTypeObject *type, PyObject *ignored); |
||||
ClientCredentials *pygrpc_ClientCredentials_iam( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
extern PyTypeObject pygrpc_ClientCredentials_type; |
||||
|
||||
|
||||
/*=========================*/ |
||||
/* Server-side credentials */ |
||||
/*=========================*/ |
||||
|
||||
typedef struct ServerCredentials { |
||||
PyObject_HEAD |
||||
grpc_server_credentials *c_creds; |
||||
} ServerCredentials; |
||||
void pygrpc_ServerCredentials_dealloc(ServerCredentials *self); |
||||
ServerCredentials *pygrpc_ServerCredentials_ssl( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
ServerCredentials *pygrpc_ServerCredentials_fake_transport_security( |
||||
PyTypeObject *type, PyObject *ignored); |
||||
extern PyTypeObject pygrpc_ServerCredentials_type; |
||||
|
||||
|
||||
/*==================*/ |
||||
/* Completion queue */ |
||||
/*==================*/ |
||||
|
||||
typedef struct CompletionQueue { |
||||
PyObject_HEAD |
||||
grpc_completion_queue *c_cq; |
||||
} CompletionQueue; |
||||
CompletionQueue *pygrpc_CompletionQueue_new( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
void pygrpc_CompletionQueue_dealloc(CompletionQueue *self); |
||||
PyObject *pygrpc_CompletionQueue_next( |
||||
CompletionQueue *self, PyObject *args, PyObject *kwargs); |
||||
PyObject *pygrpc_CompletionQueue_shutdown( |
||||
CompletionQueue *self, PyObject *ignored); |
||||
extern PyTypeObject pygrpc_CompletionQueue_type; |
||||
|
||||
|
||||
/*======*/ |
||||
/* Call */ |
||||
/*======*/ |
||||
|
||||
typedef struct Call { |
||||
PyObject_HEAD |
||||
grpc_call *c_call; |
||||
CompletionQueue *cq; |
||||
} Call; |
||||
Call *pygrpc_Call_new_empty(CompletionQueue *cq); |
||||
void pygrpc_Call_dealloc(Call *self); |
||||
PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs); |
||||
PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs); |
||||
extern PyTypeObject pygrpc_Call_type; |
||||
|
||||
|
||||
/*=========*/ |
||||
/* Channel */ |
||||
/*=========*/ |
||||
|
||||
typedef struct Channel { |
||||
PyObject_HEAD |
||||
grpc_channel *c_chan; |
||||
} Channel; |
||||
Channel *pygrpc_Channel_new( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
void pygrpc_Channel_dealloc(Channel *self); |
||||
Call *pygrpc_Channel_create_call( |
||||
Channel *self, PyObject *args, PyObject *kwargs); |
||||
extern PyTypeObject pygrpc_Channel_type; |
||||
|
||||
|
||||
/*========*/ |
||||
/* Server */ |
||||
/*========*/ |
||||
|
||||
typedef struct Server { |
||||
PyObject_HEAD |
||||
grpc_server *c_serv; |
||||
CompletionQueue *cq; |
||||
} Server; |
||||
Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs); |
||||
void pygrpc_Server_dealloc(Server *self); |
||||
PyObject *pygrpc_Server_request_call( |
||||
Server *self, PyObject *args, PyObject *kwargs); |
||||
PyObject *pygrpc_Server_add_http2_port( |
||||
Server *self, PyObject *args, PyObject *kwargs); |
||||
PyObject *pygrpc_Server_start(Server *self, PyObject *ignored); |
||||
PyObject *pygrpc_Server_shutdown( |
||||
Server *self, PyObject *args, PyObject *kwargs); |
||||
extern PyTypeObject pygrpc_Server_type; |
||||
|
||||
/*=========*/ |
||||
/* Utility */ |
||||
/*=========*/ |
||||
|
||||
/* Every tag that passes from Python GRPC to GRPC core is of this type. */ |
||||
typedef struct pygrpc_tag { |
||||
PyObject *user_tag; |
||||
Call *call; |
||||
grpc_call_details request_call_details; |
||||
grpc_metadata_array request_metadata; |
||||
grpc_op *ops; |
||||
size_t nops; |
||||
int is_new_call; |
||||
} pygrpc_tag; |
||||
|
||||
/* Construct a tag associated with a batch call. Does not take ownership of the
|
||||
resources in the elements of ops. */ |
||||
pygrpc_tag *pygrpc_produce_batch_tag(PyObject *user_tag, Call *call, |
||||
grpc_op *ops, size_t nops); |
||||
|
||||
|
||||
/* Construct a tag associated with a server request. The calling code should
|
||||
use the appropriate fields of the produced tag in the invocation of |
||||
grpc_server_request_call. */ |
||||
pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call); |
||||
|
||||
/* Construct a tag associated with a server shutdown. */ |
||||
pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag); |
||||
|
||||
/* Frees all resources owned by the tag and the tag itself. */ |
||||
void pygrpc_discard_tag(pygrpc_tag *tag); |
||||
|
||||
/* Consumes an event and its associated tag, providing a Python tuple of the
|
||||
form `(type, tag, call, call_details, results)` (where type is an integer |
||||
corresponding to a grpc_completion_type, tag is an arbitrary PyObject, call |
||||
is the call object associated with the event [if any], call_details is a |
||||
tuple of form `(method, host, deadline)` [if such details are available], |
||||
and resultd is a list of tuples of form `(type, metadata, message, status, |
||||
cancelled)` [where type corresponds to a grpc_op_type, metadata is a |
||||
sequence of 2-sequences of strings, message is a byte string, and status is |
||||
a 2-tuple of an integer corresponding to grpc_status_code and a string of |
||||
status details]). |
||||
|
||||
Frees all resources associated with the event tag. */ |
||||
PyObject *pygrpc_consume_event(grpc_event event); |
||||
|
||||
/* Transliterate the Python tuple of form `(type, metadata, message,
|
||||
status)` (where type is an integer corresponding to a grpc_op_type, metadata |
||||
is a sequence of 2-sequences of strings, message is a byte string, and |
||||
status is 2-tuple of an integer corresponding to grpc_status_code and a |
||||
string of status details) to a grpc_op suitable for use in a |
||||
grpc_call_start_batch invocation. The grpc_op is a 'directory' of resources |
||||
that must be freed after GRPC core is done with them. |
||||
|
||||
Calls gpr_malloc (or the appropriate type-specific grpc_*_create function) |
||||
to populate the appropriate union-discriminated members of the op. |
||||
|
||||
Returns true on success, false on failure. */ |
||||
int pygrpc_produce_op(PyObject *op, grpc_op *result); |
||||
|
||||
/* Discards all resources associated with the passed in op that was produced by
|
||||
pygrpc_produce_op. */ |
||||
void pygrpc_discard_op(grpc_op op); |
||||
|
||||
/* Transliterate the grpc_ops (which have been sent through a
|
||||
grpc_call_start_batch invocation and whose corresponding event has appeared |
||||
on a completion queue) to a Python tuple of form `(type, metadata, message, |
||||
status, cancelled)` (where type is an integer corresponding to a |
||||
grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a |
||||
byte string, and status is 2-tuple of an integer corresponding to |
||||
grpc_status_code and a string of status details). |
||||
|
||||
Calls gpr_free (or the appropriate type-specific grpc_*_destroy function) on |
||||
the appropriate union-discriminated populated members of the ops. */ |
||||
PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops); |
||||
|
||||
/* Transliterate from a gpr_timespec to a double (in units of seconds, either
|
||||
from the epoch if interpreted absolutely or as a delta otherwise). */ |
||||
double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec); |
||||
|
||||
/* Transliterate from a double (in units of seconds from the epoch if
|
||||
interpreted absolutely or as a delta otherwise) to a gpr_timespec. */ |
||||
gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds); |
||||
|
||||
/* Returns true on success, false on failure. */ |
||||
int pygrpc_cast_pylist_to_send_metadata( |
||||
PyObject *pylist, grpc_metadata **metadata, size_t *count); |
||||
/* Returns a metadata array as a Python object on success, else NULL. */ |
||||
PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata); |
||||
|
||||
/* Transliterate from a list of python channel arguments (2-tuples of string
|
||||
and string|integer|None) to a grpc_channel_args object. The strings placed |
||||
in the grpc_channel_args object's grpc_arg elements are views of the Python |
||||
object. The Python object must live long enough for the grpc_channel_args |
||||
to be used. Arguments set to None are silently ignored. Returns true on |
||||
success, false on failure. */ |
||||
int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args); |
||||
void pygrpc_discard_channel_args(grpc_channel_args args); |
||||
|
||||
/* Read the bytes from grpc_byte_buffer to a gpr_malloc'd array of bytes;
|
||||
output to result and result_size. */ |
||||
void pygrpc_byte_buffer_to_bytes( |
||||
grpc_byte_buffer *buffer, char **result, size_t *result_size); |
||||
|
||||
|
||||
/*========*/ |
||||
/* Module */ |
||||
/*========*/ |
||||
|
||||
/* Returns 0 on success, -1 on failure. */ |
||||
int pygrpc_module_add_types(PyObject *module); |
||||
|
||||
#endif /* GRPC__ADAPTER__C_TYPES_H_ */ |
@ -0,0 +1,163 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_c/types.h" |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
|
||||
PyMethodDef pygrpc_Call_methods[] = { |
||||
{"start_batch", (PyCFunction)pygrpc_Call_start_batch, METH_KEYWORDS, ""}, |
||||
{"cancel", (PyCFunction)pygrpc_Call_cancel, METH_KEYWORDS, ""}, |
||||
{NULL} |
||||
}; |
||||
const char pygrpc_Call_doc[] = "See grpc._adapter._types.Call."; |
||||
PyTypeObject pygrpc_Call_type = { |
||||
PyObject_HEAD_INIT(NULL) |
||||
0, /* ob_size */ |
||||
"Call", /* tp_name */ |
||||
sizeof(Call), /* tp_basicsize */ |
||||
0, /* tp_itemsize */ |
||||
(destructor)pygrpc_Call_dealloc, /* tp_dealloc */ |
||||
0, /* tp_print */ |
||||
0, /* tp_getattr */ |
||||
0, /* tp_setattr */ |
||||
0, /* tp_compare */ |
||||
0, /* tp_repr */ |
||||
0, /* tp_as_number */ |
||||
0, /* tp_as_sequence */ |
||||
0, /* tp_as_mapping */ |
||||
0, /* tp_hash */ |
||||
0, /* tp_call */ |
||||
0, /* tp_str */ |
||||
0, /* tp_getattro */ |
||||
0, /* tp_setattro */ |
||||
0, /* tp_as_buffer */ |
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
||||
pygrpc_Call_doc, /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
pygrpc_Call_methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
0, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
0 /* tp_new */ |
||||
}; |
||||
|
||||
Call *pygrpc_Call_new_empty(CompletionQueue *cq) { |
||||
Call *call = (Call *)pygrpc_Call_type.tp_alloc(&pygrpc_Call_type, 0); |
||||
call->c_call = NULL; |
||||
call->cq = cq; |
||||
Py_XINCREF(call->cq); |
||||
return call; |
||||
} |
||||
void pygrpc_Call_dealloc(Call *self) { |
||||
if (self->c_call) { |
||||
grpc_call_destroy(self->c_call); |
||||
} |
||||
Py_XDECREF(self->cq); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs) { |
||||
PyObject *op_list; |
||||
PyObject *user_tag; |
||||
grpc_op *ops; |
||||
size_t nops; |
||||
size_t i; |
||||
size_t j; |
||||
pygrpc_tag *tag; |
||||
grpc_call_error errcode; |
||||
static char *keywords[] = {"ops", "tag", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:start_batch", keywords, |
||||
&op_list, &user_tag)) { |
||||
return NULL; |
||||
} |
||||
if (!PyList_Check(op_list)) { |
||||
PyErr_SetString(PyExc_TypeError, "expected a list of OpArgs"); |
||||
return NULL; |
||||
} |
||||
nops = PyList_Size(op_list); |
||||
ops = gpr_malloc(sizeof(grpc_op) * nops); |
||||
for (i = 0; i < nops; ++i) { |
||||
PyObject *item = PyList_GET_ITEM(op_list, i); |
||||
if (!pygrpc_produce_op(item, &ops[i])) { |
||||
for (j = 0; j < i; ++j) { |
||||
pygrpc_discard_op(ops[j]); |
||||
} |
||||
return NULL; |
||||
} |
||||
} |
||||
tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops); |
||||
errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag); |
||||
gpr_free(ops); |
||||
return PyInt_FromLong(errcode); |
||||
} |
||||
PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs) { |
||||
PyObject *py_code = NULL; |
||||
grpc_call_error errcode; |
||||
int code; |
||||
char *details = NULL; |
||||
static char *keywords[] = {"code", "details", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Os:start_batch", keywords, |
||||
&py_code, &details)) { |
||||
return NULL; |
||||
} |
||||
if (py_code != NULL && details != NULL) { |
||||
if (!PyInt_Check(py_code)) { |
||||
PyErr_SetString(PyExc_TypeError, "expected integer code"); |
||||
return NULL; |
||||
} |
||||
code = PyInt_AsLong(py_code); |
||||
errcode = grpc_call_cancel_with_status(self->c_call, code, details); |
||||
} else if (py_code != NULL || details != NULL) { |
||||
PyErr_SetString(PyExc_ValueError, |
||||
"if `code` is specified, so must `details`"); |
||||
return NULL; |
||||
} else { |
||||
errcode = grpc_call_cancel(self->c_call); |
||||
} |
||||
return PyInt_FromLong(errcode); |
||||
} |
@ -0,0 +1,134 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_c/types.h" |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
|
||||
PyMethodDef pygrpc_Channel_methods[] = { |
||||
{"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""}, |
||||
{NULL} |
||||
}; |
||||
const char pygrpc_Channel_doc[] = "See grpc._adapter._types.Channel."; |
||||
PyTypeObject pygrpc_Channel_type = { |
||||
PyObject_HEAD_INIT(NULL) |
||||
0, /* ob_size */ |
||||
"Channel", /* tp_name */ |
||||
sizeof(Channel), /* tp_basicsize */ |
||||
0, /* tp_itemsize */ |
||||
(destructor)pygrpc_Channel_dealloc, /* tp_dealloc */ |
||||
0, /* tp_print */ |
||||
0, /* tp_getattr */ |
||||
0, /* tp_setattr */ |
||||
0, /* tp_compare */ |
||||
0, /* tp_repr */ |
||||
0, /* tp_as_number */ |
||||
0, /* tp_as_sequence */ |
||||
0, /* tp_as_mapping */ |
||||
0, /* tp_hash */ |
||||
0, /* tp_call */ |
||||
0, /* tp_str */ |
||||
0, /* tp_getattro */ |
||||
0, /* tp_setattro */ |
||||
0, /* tp_as_buffer */ |
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
||||
pygrpc_Channel_doc, /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
pygrpc_Channel_methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
0, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
(newfunc)pygrpc_Channel_new /* tp_new */ |
||||
}; |
||||
|
||||
Channel *pygrpc_Channel_new( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
Channel *self; |
||||
const char *target; |
||||
PyObject *py_args; |
||||
ClientCredentials *creds = NULL; |
||||
grpc_channel_args c_args; |
||||
char *keywords[] = {"target", "args", "creds", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords, |
||||
&target, &py_args, &pygrpc_ClientCredentials_type, &creds)) { |
||||
return NULL; |
||||
} |
||||
if (!pygrpc_produce_channel_args(py_args, &c_args)) { |
||||
return NULL; |
||||
} |
||||
self = (Channel *)type->tp_alloc(type, 0); |
||||
if (creds) { |
||||
self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args); |
||||
} else { |
||||
self->c_chan = grpc_channel_create(target, &c_args); |
||||
} |
||||
pygrpc_discard_channel_args(c_args); |
||||
return self; |
||||
} |
||||
void pygrpc_Channel_dealloc(Channel *self) { |
||||
grpc_channel_destroy(self->c_chan); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
Call *pygrpc_Channel_create_call( |
||||
Channel *self, PyObject *args, PyObject *kwargs) { |
||||
Call *call; |
||||
CompletionQueue *cq; |
||||
const char *method; |
||||
const char *host; |
||||
double deadline; |
||||
char *keywords[] = {"cq", "method", "host", "deadline", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!ssd:create_call", keywords, |
||||
&pygrpc_CompletionQueue_type, &cq, &method, &host, &deadline)) { |
||||
return NULL; |
||||
} |
||||
call = pygrpc_Call_new_empty(cq); |
||||
call->c_call = grpc_channel_create_call( |
||||
self->c_chan, cq->c_cq, method, host, |
||||
pygrpc_cast_double_to_gpr_timespec(deadline)); |
||||
return call; |
||||
} |
@ -0,0 +1,286 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_c/types.h" |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/grpc_security.h> |
||||
|
||||
|
||||
PyMethodDef pygrpc_ClientCredentials_methods[] = { |
||||
{"google_default", (PyCFunction)pygrpc_ClientCredentials_google_default, |
||||
METH_CLASS|METH_NOARGS, ""}, |
||||
{"ssl", (PyCFunction)pygrpc_ClientCredentials_ssl, |
||||
METH_CLASS|METH_KEYWORDS, ""}, |
||||
{"composite", (PyCFunction)pygrpc_ClientCredentials_composite, |
||||
METH_CLASS|METH_KEYWORDS, ""}, |
||||
{"compute_engine", (PyCFunction)pygrpc_ClientCredentials_compute_engine, |
||||
METH_CLASS|METH_NOARGS, ""}, |
||||
{"service_account", (PyCFunction)pygrpc_ClientCredentials_service_account, |
||||
METH_CLASS|METH_KEYWORDS, ""}, |
||||
{"jwt", (PyCFunction)pygrpc_ClientCredentials_jwt, |
||||
METH_CLASS|METH_KEYWORDS, ""}, |
||||
{"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token, |
||||
METH_CLASS|METH_KEYWORDS, ""}, |
||||
{"fake_transport_security", |
||||
(PyCFunction)pygrpc_ClientCredentials_fake_transport_security, |
||||
METH_CLASS|METH_NOARGS, ""}, |
||||
{"iam", (PyCFunction)pygrpc_ClientCredentials_iam, |
||||
METH_CLASS|METH_KEYWORDS, ""}, |
||||
{NULL} |
||||
}; |
||||
const char pygrpc_ClientCredentials_doc[] = ""; |
||||
PyTypeObject pygrpc_ClientCredentials_type = { |
||||
PyObject_HEAD_INIT(NULL) |
||||
0, /* ob_size */ |
||||
"ClientCredentials", /* tp_name */ |
||||
sizeof(ClientCredentials), /* tp_basicsize */ |
||||
0, /* tp_itemsize */ |
||||
(destructor)pygrpc_ClientCredentials_dealloc, /* tp_dealloc */ |
||||
0, /* tp_print */ |
||||
0, /* tp_getattr */ |
||||
0, /* tp_setattr */ |
||||
0, /* tp_compare */ |
||||
0, /* tp_repr */ |
||||
0, /* tp_as_number */ |
||||
0, /* tp_as_sequence */ |
||||
0, /* tp_as_mapping */ |
||||
0, /* tp_hash */ |
||||
0, /* tp_call */ |
||||
0, /* tp_str */ |
||||
0, /* tp_getattro */ |
||||
0, /* tp_setattro */ |
||||
0, /* tp_as_buffer */ |
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
||||
pygrpc_ClientCredentials_doc, /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
pygrpc_ClientCredentials_methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
0, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
0 /* tp_new */ |
||||
}; |
||||
|
||||
void pygrpc_ClientCredentials_dealloc(ClientCredentials *self) { |
||||
grpc_credentials_release(self->c_creds); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_google_default( |
||||
PyTypeObject *type, PyObject *ignored) { |
||||
ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_google_default_credentials_create(); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, |
||||
"couldn't create Google default credentials"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_ssl( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
ClientCredentials *self; |
||||
const char *root_certs; |
||||
const char *private_key = NULL; |
||||
const char *cert_chain = NULL; |
||||
grpc_ssl_pem_key_cert_pair key_cert_pair; |
||||
static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords, |
||||
&root_certs, &private_key, &cert_chain)) { |
||||
return NULL; |
||||
} |
||||
self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
if (private_key && cert_chain) { |
||||
key_cert_pair.private_key = private_key; |
||||
key_cert_pair.cert_chain = cert_chain; |
||||
self->c_creds = grpc_ssl_credentials_create(root_certs, &key_cert_pair); |
||||
} else { |
||||
self->c_creds = grpc_ssl_credentials_create(root_certs, NULL); |
||||
} |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_composite( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
ClientCredentials *self; |
||||
ClientCredentials *creds1; |
||||
ClientCredentials *creds2; |
||||
static char *keywords[] = {"creds1", "creds2", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords, |
||||
&pygrpc_ClientCredentials_type, &creds1, |
||||
&pygrpc_ClientCredentials_type, &creds2)) { |
||||
return NULL; |
||||
} |
||||
self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_composite_credentials_create( |
||||
creds1->c_creds, creds2->c_creds); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_compute_engine( |
||||
PyTypeObject *type, PyObject *ignored) { |
||||
ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_compute_engine_credentials_create(); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, |
||||
"couldn't create compute engine credentials"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_service_account( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
ClientCredentials *self; |
||||
const char *json_key; |
||||
const char *scope; |
||||
double lifetime; |
||||
static char *keywords[] = {"json_key", "scope", "token_lifetime", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssd:service_account", keywords, |
||||
&json_key, &scope, &lifetime)) { |
||||
return NULL; |
||||
} |
||||
self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_service_account_credentials_create( |
||||
json_key, scope, pygrpc_cast_double_to_gpr_timespec(lifetime)); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, |
||||
"couldn't create service account credentials"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_jwt( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
ClientCredentials *self; |
||||
const char *json_key; |
||||
double lifetime; |
||||
static char *keywords[] = {"json_key", "token_lifetime", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd:jwt", keywords, |
||||
&json_key, &lifetime)) { |
||||
return NULL; |
||||
} |
||||
self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_jwt_credentials_create( |
||||
json_key, pygrpc_cast_double_to_gpr_timespec(lifetime)); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_refresh_token( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
ClientCredentials *self; |
||||
const char *json_refresh_token; |
||||
static char *keywords[] = {"json_refresh_token", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords, |
||||
&json_refresh_token)) { |
||||
return NULL; |
||||
} |
||||
self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_refresh_token_credentials_create(json_refresh_token); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, |
||||
"couldn't create credentials from refresh token"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_fake_transport_security( |
||||
PyTypeObject *type, PyObject *ignored) { |
||||
ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_fake_transport_security_credentials_create(); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, |
||||
"couldn't create fake credentials; " |
||||
"something is horribly wrong with the universe"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
ClientCredentials *pygrpc_ClientCredentials_iam( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
ClientCredentials *self; |
||||
const char *authorization_token; |
||||
const char *authority_selector; |
||||
static char *keywords[] = {"authorization_token", "authority_selector", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:iam", keywords, |
||||
&authorization_token, &authority_selector)) { |
||||
return NULL; |
||||
} |
||||
self = (ClientCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_iam_credentials_create(authorization_token, |
||||
authority_selector); |
||||
if (!self->c_creds) { |
||||
Py_DECREF(self); |
||||
PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials"); |
||||
return NULL; |
||||
} |
||||
return self; |
||||
} |
||||
|
@ -0,0 +1,124 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_c/types.h" |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
|
||||
PyMethodDef pygrpc_CompletionQueue_methods[] = { |
||||
{"next", (PyCFunction)pygrpc_CompletionQueue_next, METH_KEYWORDS, ""}, |
||||
{"shutdown", (PyCFunction)pygrpc_CompletionQueue_shutdown, METH_NOARGS, ""}, |
||||
{NULL} |
||||
}; |
||||
const char pygrpc_CompletionQueue_doc[] = |
||||
"See grpc._adapter._types.CompletionQueue."; |
||||
PyTypeObject pygrpc_CompletionQueue_type = { |
||||
PyObject_HEAD_INIT(NULL) |
||||
0, /* ob_size */ |
||||
"CompletionQueue", /* tp_name */ |
||||
sizeof(CompletionQueue), /* tp_basicsize */ |
||||
0, /* tp_itemsize */ |
||||
(destructor)pygrpc_CompletionQueue_dealloc, /* tp_dealloc */ |
||||
0, /* tp_print */ |
||||
0, /* tp_getattr */ |
||||
0, /* tp_setattr */ |
||||
0, /* tp_compare */ |
||||
0, /* tp_repr */ |
||||
0, /* tp_as_number */ |
||||
0, /* tp_as_sequence */ |
||||
0, /* tp_as_mapping */ |
||||
0, /* tp_hash */ |
||||
0, /* tp_call */ |
||||
0, /* tp_str */ |
||||
0, /* tp_getattro */ |
||||
0, /* tp_setattro */ |
||||
0, /* tp_as_buffer */ |
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
||||
pygrpc_CompletionQueue_doc, /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
pygrpc_CompletionQueue_methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
0, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
(newfunc)pygrpc_CompletionQueue_new /* tp_new */ |
||||
}; |
||||
|
||||
CompletionQueue *pygrpc_CompletionQueue_new( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0); |
||||
self->c_cq = grpc_completion_queue_create(); |
||||
return self; |
||||
} |
||||
|
||||
void pygrpc_CompletionQueue_dealloc(CompletionQueue *self) { |
||||
grpc_completion_queue_destroy(self->c_cq); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
PyObject *pygrpc_CompletionQueue_next( |
||||
CompletionQueue *self, PyObject *args, PyObject *kwargs) { |
||||
double deadline; |
||||
grpc_event event; |
||||
PyObject *transliterated_event; |
||||
static char *keywords[] = {"deadline", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:next", keywords, |
||||
&deadline)) { |
||||
return NULL; |
||||
} |
||||
Py_BEGIN_ALLOW_THREADS; |
||||
event = grpc_completion_queue_next( |
||||
self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline)); |
||||
Py_END_ALLOW_THREADS; |
||||
transliterated_event = pygrpc_consume_event(event); |
||||
return transliterated_event; |
||||
} |
||||
|
||||
PyObject *pygrpc_CompletionQueue_shutdown( |
||||
CompletionQueue *self, PyObject *ignored) { |
||||
grpc_completion_queue_shutdown(self->c_cq); |
||||
Py_RETURN_NONE; |
||||
} |
@ -0,0 +1,183 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_c/types.h" |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
|
||||
PyMethodDef pygrpc_Server_methods[] = { |
||||
{"request_call", (PyCFunction)pygrpc_Server_request_call, |
||||
METH_KEYWORDS, ""}, |
||||
{"add_http2_port", (PyCFunction)pygrpc_Server_add_http2_port, |
||||
METH_KEYWORDS, ""}, |
||||
{"start", (PyCFunction)pygrpc_Server_start, METH_NOARGS, ""}, |
||||
{"shutdown", (PyCFunction)pygrpc_Server_shutdown, METH_KEYWORDS, ""}, |
||||
{NULL} |
||||
}; |
||||
const char pygrpc_Server_doc[] = "See grpc._adapter._types.Server."; |
||||
PyTypeObject pygrpc_Server_type = { |
||||
PyObject_HEAD_INIT(NULL) |
||||
0, /* ob_size */ |
||||
"Server", /* tp_name */ |
||||
sizeof(Server), /* tp_basicsize */ |
||||
0, /* tp_itemsize */ |
||||
(destructor)pygrpc_Server_dealloc, /* tp_dealloc */ |
||||
0, /* tp_print */ |
||||
0, /* tp_getattr */ |
||||
0, /* tp_setattr */ |
||||
0, /* tp_compare */ |
||||
0, /* tp_repr */ |
||||
0, /* tp_as_number */ |
||||
0, /* tp_as_sequence */ |
||||
0, /* tp_as_mapping */ |
||||
0, /* tp_hash */ |
||||
0, /* tp_call */ |
||||
0, /* tp_str */ |
||||
0, /* tp_getattro */ |
||||
0, /* tp_setattro */ |
||||
0, /* tp_as_buffer */ |
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
||||
pygrpc_Server_doc, /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
pygrpc_Server_methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
0, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
(newfunc)pygrpc_Server_new /* tp_new */ |
||||
}; |
||||
|
||||
Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
Server *self; |
||||
CompletionQueue *cq; |
||||
PyObject *py_args; |
||||
grpc_channel_args c_args; |
||||
char *keywords[] = {"cq", "args", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Channel", keywords, |
||||
&pygrpc_CompletionQueue_type, &cq, &py_args)) { |
||||
return NULL; |
||||
} |
||||
if (!pygrpc_produce_channel_args(py_args, &c_args)) { |
||||
return NULL; |
||||
} |
||||
self = (Server *)type->tp_alloc(type, 0); |
||||
self->c_serv = grpc_server_create(&c_args); |
||||
pygrpc_discard_channel_args(c_args); |
||||
self->cq = cq; |
||||
Py_INCREF(self->cq); |
||||
return self; |
||||
} |
||||
|
||||
void pygrpc_Server_dealloc(Server *self) { |
||||
grpc_server_destroy(self->c_serv); |
||||
Py_XDECREF(self->cq); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
PyObject *pygrpc_Server_request_call( |
||||
Server *self, PyObject *args, PyObject *kwargs) { |
||||
CompletionQueue *cq; |
||||
PyObject *user_tag; |
||||
pygrpc_tag *tag; |
||||
Call *empty_call; |
||||
grpc_call_error errcode; |
||||
static char *keywords[] = {"cq", "tag", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords( |
||||
args, kwargs, "O!O", keywords, |
||||
&pygrpc_CompletionQueue_type, &cq, &user_tag)) { |
||||
return NULL; |
||||
} |
||||
empty_call = pygrpc_Call_new_empty(cq); |
||||
tag = pygrpc_produce_request_tag(user_tag, empty_call); |
||||
errcode = grpc_server_request_call( |
||||
self->c_serv, &tag->call->c_call, &tag->request_call_details, |
||||
&tag->request_metadata, tag->call->cq->c_cq, self->cq->c_cq, tag); |
||||
Py_DECREF(empty_call); |
||||
return PyInt_FromLong(errcode); |
||||
} |
||||
|
||||
PyObject *pygrpc_Server_add_http2_port( |
||||
Server *self, PyObject *args, PyObject *kwargs) { |
||||
const char *addr; |
||||
ServerCredentials *creds = NULL; |
||||
int port; |
||||
static char *keywords[] = {"addr", "creds", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords( |
||||
args, kwargs, "s|O!:add_http2_port", keywords, |
||||
&addr, &pygrpc_ServerCredentials_type, &creds)) { |
||||
return NULL; |
||||
} |
||||
if (creds) { |
||||
port = grpc_server_add_secure_http2_port( |
||||
self->c_serv, addr, creds->c_creds); |
||||
} else { |
||||
port = grpc_server_add_http2_port(self->c_serv, addr); |
||||
} |
||||
return PyInt_FromLong(port); |
||||
|
||||
} |
||||
|
||||
PyObject *pygrpc_Server_start(Server *self, PyObject *ignored) { |
||||
grpc_server_start(self->c_serv); |
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
PyObject *pygrpc_Server_shutdown( |
||||
Server *self, PyObject *args, PyObject *kwargs) { |
||||
PyObject *user_tag = NULL; |
||||
pygrpc_tag *tag; |
||||
static char *keywords[] = {"tag", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", keywords, &user_tag)) { |
||||
return NULL; |
||||
} |
||||
if (user_tag) { |
||||
tag = pygrpc_produce_server_shutdown_tag(user_tag); |
||||
grpc_server_shutdown_and_notify(self->c_serv, tag); |
||||
} else { |
||||
grpc_server_shutdown(self->c_serv); |
||||
} |
||||
Py_RETURN_NONE; |
||||
} |
@ -0,0 +1,146 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_c/types.h" |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/grpc_security.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
|
||||
PyMethodDef pygrpc_ServerCredentials_methods[] = { |
||||
{"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl, |
||||
METH_CLASS|METH_KEYWORDS, ""}, |
||||
{"fake_transport_security", |
||||
(PyCFunction)pygrpc_ServerCredentials_fake_transport_security, |
||||
METH_CLASS|METH_NOARGS, ""}, |
||||
{NULL} |
||||
}; |
||||
const char pygrpc_ServerCredentials_doc[] = ""; |
||||
PyTypeObject pygrpc_ServerCredentials_type = { |
||||
PyObject_HEAD_INIT(NULL) |
||||
0, /* ob_size */ |
||||
"ServerCredentials", /* tp_name */ |
||||
sizeof(ServerCredentials), /* tp_basicsize */ |
||||
0, /* tp_itemsize */ |
||||
(destructor)pygrpc_ServerCredentials_dealloc, /* tp_dealloc */ |
||||
0, /* tp_print */ |
||||
0, /* tp_getattr */ |
||||
0, /* tp_setattr */ |
||||
0, /* tp_compare */ |
||||
0, /* tp_repr */ |
||||
0, /* tp_as_number */ |
||||
0, /* tp_as_sequence */ |
||||
0, /* tp_as_mapping */ |
||||
0, /* tp_hash */ |
||||
0, /* tp_call */ |
||||
0, /* tp_str */ |
||||
0, /* tp_getattro */ |
||||
0, /* tp_setattro */ |
||||
0, /* tp_as_buffer */ |
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
||||
pygrpc_ServerCredentials_doc, /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
pygrpc_ServerCredentials_methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
0, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
0 /* tp_new */ |
||||
}; |
||||
|
||||
void pygrpc_ServerCredentials_dealloc(ServerCredentials *self) { |
||||
grpc_server_credentials_release(self->c_creds); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
ServerCredentials *pygrpc_ServerCredentials_ssl( |
||||
PyTypeObject *type, PyObject *args, PyObject *kwargs) { |
||||
ServerCredentials *self; |
||||
const char *root_certs; |
||||
PyObject *py_key_cert_pairs; |
||||
grpc_ssl_pem_key_cert_pair *key_cert_pairs; |
||||
size_t num_key_cert_pairs; |
||||
size_t i; |
||||
static char *keywords[] = {"root_certs", "key_cert_pairs", NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zO:ssl", keywords, |
||||
&root_certs, &py_key_cert_pairs)) { |
||||
return NULL; |
||||
} |
||||
if (!PyList_Check(py_key_cert_pairs)) { |
||||
PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuples of strings"); |
||||
return NULL; |
||||
} |
||||
num_key_cert_pairs = PyList_Size(py_key_cert_pairs); |
||||
key_cert_pairs = |
||||
gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs); |
||||
for (i = 0; i < num_key_cert_pairs; ++i) { |
||||
PyObject *item = PyList_GET_ITEM(py_key_cert_pairs, i); |
||||
const char *key; |
||||
const char *cert; |
||||
if (!PyArg_ParseTuple(item, "zz", &key, &cert)) { |
||||
gpr_free(key_cert_pairs); |
||||
PyErr_SetString(PyExc_TypeError, |
||||
"expected a list of 2-tuples of strings"); |
||||
return NULL; |
||||
} |
||||
key_cert_pairs[i].private_key = key; |
||||
key_cert_pairs[i].cert_chain = cert; |
||||
} |
||||
|
||||
self = (ServerCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_ssl_server_credentials_create( |
||||
root_certs, key_cert_pairs, num_key_cert_pairs); |
||||
gpr_free(key_cert_pairs); |
||||
return self; |
||||
} |
||||
|
||||
ServerCredentials *pygrpc_ServerCredentials_fake_transport_security( |
||||
PyTypeObject *type, PyObject *ignored) { |
||||
ServerCredentials *self = (ServerCredentials *)type->tp_alloc(type, 0); |
||||
self->c_creds = grpc_fake_transport_security_server_credentials_create(); |
||||
return self; |
||||
} |
||||
|
@ -0,0 +1,460 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <math.h> |
||||
|
||||
#define PY_SSIZE_T_CLEAN |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/slice.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
#include "grpc/_adapter/_c/types.h" |
||||
|
||||
pygrpc_tag *pygrpc_produce_batch_tag( |
||||
PyObject *user_tag, Call *call, grpc_op *ops, size_t nops) { |
||||
pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); |
||||
tag->user_tag = user_tag; |
||||
Py_XINCREF(tag->user_tag); |
||||
tag->call = call; |
||||
Py_XINCREF(tag->call); |
||||
tag->ops = gpr_malloc(sizeof(grpc_op)*nops); |
||||
memcpy(tag->ops, ops, sizeof(grpc_op)*nops); |
||||
tag->nops = nops; |
||||
grpc_call_details_init(&tag->request_call_details); |
||||
grpc_metadata_array_init(&tag->request_metadata); |
||||
tag->is_new_call = 0; |
||||
return tag; |
||||
} |
||||
|
||||
pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call) { |
||||
pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); |
||||
tag->user_tag = user_tag; |
||||
Py_XINCREF(tag->user_tag); |
||||
tag->call = empty_call; |
||||
Py_XINCREF(tag->call); |
||||
tag->ops = NULL; |
||||
tag->nops = 0; |
||||
grpc_call_details_init(&tag->request_call_details); |
||||
grpc_metadata_array_init(&tag->request_metadata); |
||||
tag->is_new_call = 1; |
||||
return tag; |
||||
} |
||||
|
||||
pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag) { |
||||
pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); |
||||
tag->user_tag = user_tag; |
||||
Py_XINCREF(tag->user_tag); |
||||
tag->call = NULL; |
||||
tag->ops = NULL; |
||||
tag->nops = 0; |
||||
grpc_call_details_init(&tag->request_call_details); |
||||
grpc_metadata_array_init(&tag->request_metadata); |
||||
tag->is_new_call = 0; |
||||
return tag; |
||||
} |
||||
|
||||
void pygrpc_discard_tag(pygrpc_tag *tag) { |
||||
if (!tag) { |
||||
return; |
||||
} |
||||
Py_XDECREF(tag->user_tag); |
||||
Py_XDECREF(tag->call); |
||||
gpr_free(tag->ops); |
||||
grpc_call_details_destroy(&tag->request_call_details); |
||||
grpc_metadata_array_destroy(&tag->request_metadata); |
||||
gpr_free(tag); |
||||
} |
||||
|
||||
PyObject *pygrpc_consume_event(grpc_event event) { |
||||
pygrpc_tag *tag; |
||||
PyObject *result; |
||||
if (event.type == GRPC_QUEUE_TIMEOUT) { |
||||
Py_RETURN_NONE; |
||||
} |
||||
tag = event.tag; |
||||
switch (event.type) { |
||||
case GRPC_QUEUE_SHUTDOWN: |
||||
result = Py_BuildValue("iOOOOO", GRPC_QUEUE_SHUTDOWN, |
||||
Py_None, Py_None, Py_None, Py_None, Py_True); |
||||
break; |
||||
case GRPC_OP_COMPLETE: |
||||
if (tag->is_new_call) { |
||||
result = Py_BuildValue( |
||||
"iOO(ssd)[(iNOOOO)]O", GRPC_OP_COMPLETE, tag->user_tag, tag->call, |
||||
tag->request_call_details.method, tag->request_call_details.host, |
||||
pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline), |
||||
GRPC_OP_RECV_INITIAL_METADATA, |
||||
pygrpc_cast_metadata_array_to_pylist(tag->request_metadata), Py_None, |
||||
Py_None, Py_None, Py_None, |
||||
event.success ? Py_True : Py_False); |
||||
} else { |
||||
result = Py_BuildValue("iOOONO", GRPC_OP_COMPLETE, tag->user_tag, |
||||
tag->call, Py_None, pygrpc_consume_ops(tag->ops, tag->nops), |
||||
event.success ? Py_True : Py_False); |
||||
} |
||||
break; |
||||
default: |
||||
PyErr_SetString(PyExc_ValueError, |
||||
"unknown completion type; could not translate event"); |
||||
return NULL; |
||||
} |
||||
pygrpc_discard_tag(tag); |
||||
return result; |
||||
} |
||||
|
||||
int pygrpc_produce_op(PyObject *op, grpc_op *result) { |
||||
static const int OP_TUPLE_SIZE = 5; |
||||
static const int STATUS_TUPLE_SIZE = 2; |
||||
static const int TYPE_INDEX = 0; |
||||
static const int INITIAL_METADATA_INDEX = 1; |
||||
static const int TRAILING_METADATA_INDEX = 2; |
||||
static const int MESSAGE_INDEX = 3; |
||||
static const int STATUS_INDEX = 4; |
||||
static const int STATUS_CODE_INDEX = 0; |
||||
static const int STATUS_DETAILS_INDEX = 1; |
||||
grpc_op c_op; |
||||
if (!PyTuple_Check(op)) { |
||||
PyErr_SetString(PyExc_TypeError, "expected tuple op"); |
||||
return 0; |
||||
} |
||||
if (PyTuple_Size(op) != OP_TUPLE_SIZE) { |
||||
char buf[64]; |
||||
snprintf(buf, sizeof(buf), "expected tuple op of length %d", OP_TUPLE_SIZE); |
||||
PyErr_SetString(PyExc_ValueError, buf); |
||||
return 0; |
||||
} |
||||
int type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX)); |
||||
if (PyErr_Occurred()) { |
||||
return 0; |
||||
} |
||||
Py_ssize_t message_size; |
||||
char *message; |
||||
char *status_details; |
||||
gpr_slice message_slice; |
||||
c_op.op = type; |
||||
switch (type) { |
||||
case GRPC_OP_SEND_INITIAL_METADATA: |
||||
if (!pygrpc_cast_pylist_to_send_metadata( |
||||
PyTuple_GetItem(op, INITIAL_METADATA_INDEX), |
||||
&c_op.data.send_initial_metadata.metadata, |
||||
&c_op.data.send_initial_metadata.count)) { |
||||
return 0; |
||||
} |
||||
break; |
||||
case GRPC_OP_SEND_MESSAGE: |
||||
PyString_AsStringAndSize( |
||||
PyTuple_GET_ITEM(op, MESSAGE_INDEX), &message, &message_size); |
||||
message_slice = gpr_slice_from_copied_buffer(message, message_size); |
||||
c_op.data.send_message = grpc_byte_buffer_create(&message_slice, 1); |
||||
gpr_slice_unref(message_slice); |
||||
break; |
||||
case GRPC_OP_SEND_CLOSE_FROM_CLIENT: |
||||
/* Don't need to fill in any other fields. */ |
||||
break; |
||||
case GRPC_OP_SEND_STATUS_FROM_SERVER: |
||||
if (!pygrpc_cast_pylist_to_send_metadata( |
||||
PyTuple_GetItem(op, TRAILING_METADATA_INDEX), |
||||
&c_op.data.send_status_from_server.trailing_metadata, |
||||
&c_op.data.send_status_from_server.trailing_metadata_count)) { |
||||
return 0; |
||||
} |
||||
if (!PyTuple_Check(PyTuple_GET_ITEM(op, STATUS_INDEX))) { |
||||
char buf[64]; |
||||
snprintf(buf, sizeof(buf), "expected tuple status in op of length %d", |
||||
STATUS_TUPLE_SIZE); |
||||
PyErr_SetString(PyExc_TypeError, buf); |
||||
return 0; |
||||
} |
||||
c_op.data.send_status_from_server.status = PyInt_AsLong( |
||||
PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_CODE_INDEX)); |
||||
status_details = PyString_AsString( |
||||
PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_DETAILS_INDEX)); |
||||
if (PyErr_Occurred()) { |
||||
return 0; |
||||
} |
||||
c_op.data.send_status_from_server.status_details = |
||||
gpr_malloc(strlen(status_details) + 1); |
||||
strcpy((char *)c_op.data.send_status_from_server.status_details, |
||||
status_details); |
||||
break; |
||||
case GRPC_OP_RECV_INITIAL_METADATA: |
||||
c_op.data.recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array)); |
||||
grpc_metadata_array_init(c_op.data.recv_initial_metadata); |
||||
break; |
||||
case GRPC_OP_RECV_MESSAGE: |
||||
c_op.data.recv_message = gpr_malloc(sizeof(grpc_byte_buffer *)); |
||||
break; |
||||
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
||||
c_op.data.recv_status_on_client.trailing_metadata = |
||||
gpr_malloc(sizeof(grpc_metadata_array)); |
||||
grpc_metadata_array_init(c_op.data.recv_status_on_client.trailing_metadata); |
||||
c_op.data.recv_status_on_client.status = |
||||
gpr_malloc(sizeof(grpc_status_code *)); |
||||
c_op.data.recv_status_on_client.status_details = |
||||
gpr_malloc(sizeof(char *)); |
||||
*c_op.data.recv_status_on_client.status_details = NULL; |
||||
c_op.data.recv_status_on_client.status_details_capacity = |
||||
gpr_malloc(sizeof(size_t)); |
||||
*c_op.data.recv_status_on_client.status_details_capacity = 0; |
||||
break; |
||||
case GRPC_OP_RECV_CLOSE_ON_SERVER: |
||||
c_op.data.recv_close_on_server.cancelled = gpr_malloc(sizeof(int)); |
||||
break; |
||||
default: |
||||
return 0; |
||||
} |
||||
*result = c_op; |
||||
return 1; |
||||
} |
||||
|
||||
void pygrpc_discard_op(grpc_op op) { |
||||
switch(op.op) { |
||||
case GRPC_OP_SEND_INITIAL_METADATA: |
||||
gpr_free(op.data.send_initial_metadata.metadata); |
||||
break; |
||||
case GRPC_OP_SEND_MESSAGE: |
||||
grpc_byte_buffer_destroy(op.data.send_message); |
||||
break; |
||||
case GRPC_OP_SEND_CLOSE_FROM_CLIENT: |
||||
/* Don't need to free any fields. */ |
||||
break; |
||||
case GRPC_OP_SEND_STATUS_FROM_SERVER: |
||||
gpr_free(op.data.send_status_from_server.trailing_metadata); |
||||
gpr_free((char *)op.data.send_status_from_server.status_details); |
||||
break; |
||||
case GRPC_OP_RECV_INITIAL_METADATA: |
||||
grpc_metadata_array_destroy(op.data.recv_initial_metadata); |
||||
gpr_free(op.data.recv_initial_metadata); |
||||
break; |
||||
case GRPC_OP_RECV_MESSAGE: |
||||
grpc_byte_buffer_destroy(*op.data.recv_message); |
||||
gpr_free(op.data.recv_message); |
||||
break; |
||||
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
||||
grpc_metadata_array_destroy(op.data.recv_status_on_client.trailing_metadata); |
||||
gpr_free(op.data.recv_status_on_client.trailing_metadata); |
||||
gpr_free(op.data.recv_status_on_client.status); |
||||
gpr_free(*op.data.recv_status_on_client.status_details); |
||||
gpr_free(op.data.recv_status_on_client.status_details); |
||||
gpr_free(op.data.recv_status_on_client.status_details_capacity); |
||||
break; |
||||
case GRPC_OP_RECV_CLOSE_ON_SERVER: |
||||
gpr_free(op.data.recv_close_on_server.cancelled); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops) { |
||||
static const int TYPE_INDEX = 0; |
||||
static const int INITIAL_METADATA_INDEX = 1; |
||||
static const int TRAILING_METADATA_INDEX = 2; |
||||
static const int MESSAGE_INDEX = 3; |
||||
static const int STATUS_INDEX = 4; |
||||
static const int CANCELLED_INDEX = 5; |
||||
static const int OPRESULT_LENGTH = 6; |
||||
PyObject *list; |
||||
size_t i; |
||||
size_t j; |
||||
char *bytes; |
||||
size_t bytes_size; |
||||
PyObject *results = PyList_New(nops); |
||||
if (!results) { |
||||
return NULL; |
||||
} |
||||
for (i = 0; i < nops; ++i) { |
||||
PyObject *result = PyTuple_Pack(OPRESULT_LENGTH, Py_None, Py_None, Py_None, |
||||
Py_None, Py_None, Py_None); |
||||
PyTuple_SetItem(result, TYPE_INDEX, PyInt_FromLong(op[i].op)); |
||||
switch(op[i].op) { |
||||
case GRPC_OP_RECV_INITIAL_METADATA: |
||||
PyTuple_SetItem(result, INITIAL_METADATA_INDEX, |
||||
list=PyList_New(op[i].data.recv_initial_metadata->count)); |
||||
for (j = 0; j < op[i].data.recv_initial_metadata->count; ++j) { |
||||
grpc_metadata md = op[i].data.recv_initial_metadata->metadata[j]; |
||||
PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value, |
||||
(Py_ssize_t)md.value_length)); |
||||
} |
||||
break; |
||||
case GRPC_OP_RECV_MESSAGE: |
||||
if (*op[i].data.recv_message) { |
||||
pygrpc_byte_buffer_to_bytes( |
||||
*op[i].data.recv_message, &bytes, &bytes_size); |
||||
PyTuple_SetItem(result, MESSAGE_INDEX, |
||||
PyString_FromStringAndSize(bytes, bytes_size)); |
||||
gpr_free(bytes); |
||||
} else { |
||||
PyTuple_SetItem(result, MESSAGE_INDEX, Py_BuildValue("")); |
||||
} |
||||
break; |
||||
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
||||
PyTuple_SetItem( |
||||
result, TRAILING_METADATA_INDEX, |
||||
list = PyList_New(op[i].data.recv_status_on_client.trailing_metadata->count)); |
||||
for (j = 0; j < op[i].data.recv_status_on_client.trailing_metadata->count; ++j) { |
||||
grpc_metadata md = |
||||
op[i].data.recv_status_on_client.trailing_metadata->metadata[j]; |
||||
PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value, |
||||
(Py_ssize_t)md.value_length)); |
||||
} |
||||
PyTuple_SetItem( |
||||
result, STATUS_INDEX, Py_BuildValue( |
||||
"is", *op[i].data.recv_status_on_client.status, |
||||
*op[i].data.recv_status_on_client.status_details)); |
||||
break; |
||||
case GRPC_OP_RECV_CLOSE_ON_SERVER: |
||||
PyTuple_SetItem( |
||||
result, CANCELLED_INDEX, |
||||
PyBool_FromLong(*op[i].data.recv_close_on_server.cancelled)); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
pygrpc_discard_op(op[i]); |
||||
PyList_SetItem(results, i, result); |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) { |
||||
return timespec.tv_sec + 1e-9*timespec.tv_nsec; |
||||
} |
||||
|
||||
gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) { |
||||
gpr_timespec result; |
||||
if isinf(seconds) { |
||||
result = seconds > 0.0 ? gpr_inf_future : gpr_inf_past; |
||||
} else { |
||||
result.tv_sec = (time_t)seconds; |
||||
result.tv_nsec = ((seconds - result.tv_sec) * 1e9); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args) { |
||||
size_t num_args = PyList_Size(py_args); |
||||
size_t i; |
||||
grpc_channel_args args = {num_args, gpr_malloc(sizeof(grpc_arg) * num_args)}; |
||||
for (i = 0; i < args.num_args; ++i) { |
||||
char *key; |
||||
PyObject *value; |
||||
if (!PyArg_ParseTuple(PyList_GetItem(py_args, i), "zO", &key, &value)) { |
||||
gpr_free(args.args); |
||||
args.num_args = 0; |
||||
args.args = NULL; |
||||
PyErr_SetString(PyExc_TypeError, |
||||
"expected a list of 2-tuple of str and str|int|None"); |
||||
return 0; |
||||
} |
||||
args.args[i].key = key; |
||||
if (PyInt_Check(value)) { |
||||
args.args[i].type = GRPC_ARG_INTEGER; |
||||
args.args[i].value.integer = PyInt_AsLong(value); |
||||
} else if (PyString_Check(value)) { |
||||
args.args[i].type = GRPC_ARG_STRING; |
||||
args.args[i].value.string = PyString_AsString(value); |
||||
} else if (value == Py_None) { |
||||
--args.num_args; |
||||
--i; |
||||
continue; |
||||
} else { |
||||
gpr_free(args.args); |
||||
args.num_args = 0; |
||||
args.args = NULL; |
||||
PyErr_SetString(PyExc_TypeError, |
||||
"expected a list of 2-tuple of str and str|int|None"); |
||||
return 0; |
||||
} |
||||
} |
||||
*c_args = args; |
||||
return 1; |
||||
} |
||||
|
||||
void pygrpc_discard_channel_args(grpc_channel_args args) { |
||||
gpr_free(args.args); |
||||
} |
||||
|
||||
int pygrpc_cast_pylist_to_send_metadata( |
||||
PyObject *pylist, grpc_metadata **metadata, size_t *count) { |
||||
size_t i; |
||||
Py_ssize_t value_length; |
||||
*count = PyList_Size(pylist); |
||||
*metadata = gpr_malloc(sizeof(grpc_metadata) * *count); |
||||
for (i = 0; i < *count; ++i) { |
||||
if (!PyArg_ParseTuple( |
||||
PyList_GetItem(pylist, i), "ss#", |
||||
&(*metadata)[i].key, &(*metadata)[i].value, &value_length)) { |
||||
gpr_free(*metadata); |
||||
*count = 0; |
||||
*metadata = NULL; |
||||
return 0; |
||||
} |
||||
(*metadata)[i].value_length = value_length; |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata) { |
||||
PyObject *result = PyList_New(metadata.count); |
||||
size_t i; |
||||
for (i = 0; i < metadata.count; ++i) { |
||||
PyList_SetItem( |
||||
result, i, Py_BuildValue( |
||||
"ss#", metadata.metadata[i].key, metadata.metadata[i].value, |
||||
(Py_ssize_t)metadata.metadata[i].value_length)); |
||||
if (PyErr_Occurred()) { |
||||
Py_DECREF(result); |
||||
return NULL; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
void pygrpc_byte_buffer_to_bytes( |
||||
grpc_byte_buffer *buffer, char **result, size_t *result_size) { |
||||
grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer); |
||||
gpr_slice slice; |
||||
char *read_result = NULL; |
||||
size_t size = 0; |
||||
while (grpc_byte_buffer_reader_next(reader, &slice)) { |
||||
read_result = gpr_realloc(read_result, size + GPR_SLICE_LENGTH(slice)); |
||||
memcpy(read_result + size, GPR_SLICE_START_PTR(slice), |
||||
GPR_SLICE_LENGTH(slice)); |
||||
size = size + GPR_SLICE_LENGTH(slice); |
||||
gpr_slice_unref(slice); |
||||
} |
||||
grpc_byte_buffer_reader_destroy(reader); |
||||
*result_size = size; |
||||
*result = read_result; |
||||
} |
@ -1,438 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_call.h" |
||||
|
||||
#include <math.h> |
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "grpc/_adapter/_channel.h" |
||||
#include "grpc/_adapter/_completion_queue.h" |
||||
#include "grpc/_adapter/_error.h" |
||||
#include "grpc/_adapter/_tag.h" |
||||
|
||||
static PyObject *pygrpc_call_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { |
||||
Call *self = (Call *)type->tp_alloc(type, 0); |
||||
Channel *channel; |
||||
CompletionQueue *completion_queue; |
||||
const char *method; |
||||
const char *host; |
||||
double deadline; |
||||
static char *kwlist[] = {"channel", "completion_queue", |
||||
"method", "host", "deadline", NULL}; |
||||
|
||||
if (!PyArg_ParseTupleAndKeywords( |
||||
args, kwds, "O!O!ssd:Call", kwlist, |
||||
&pygrpc_ChannelType, &channel, |
||||
&pygrpc_CompletionQueueType, &completion_queue, |
||||
&method, &host, &deadline)) { |
||||
return NULL; |
||||
} |
||||
|
||||
/* TODO(nathaniel): Hoist the gpr_timespec <-> PyFloat arithmetic into its own
|
||||
* function with its own test coverage. |
||||
*/ |
||||
self->c_call = grpc_channel_create_call( |
||||
channel->c_channel, completion_queue->c_completion_queue, method, host, |
||||
gpr_time_from_nanos(deadline * GPR_NS_PER_SEC)); |
||||
self->completion_queue = completion_queue; |
||||
Py_INCREF(self->completion_queue); |
||||
self->channel = channel; |
||||
Py_INCREF(self->channel); |
||||
grpc_call_details_init(&self->call_details); |
||||
grpc_metadata_array_init(&self->recv_metadata); |
||||
grpc_metadata_array_init(&self->recv_trailing_metadata); |
||||
self->send_metadata = NULL; |
||||
self->send_metadata_count = 0; |
||||
self->send_trailing_metadata = NULL; |
||||
self->send_trailing_metadata_count = 0; |
||||
self->send_message = NULL; |
||||
self->recv_message = NULL; |
||||
self->adding_to_trailing = 0; |
||||
|
||||
return (PyObject *)self; |
||||
} |
||||
|
||||
static void pygrpc_call_dealloc(Call *self) { |
||||
if (self->c_call != NULL) { |
||||
grpc_call_destroy(self->c_call); |
||||
} |
||||
Py_XDECREF(self->completion_queue); |
||||
Py_XDECREF(self->channel); |
||||
Py_XDECREF(self->server); |
||||
grpc_call_details_destroy(&self->call_details); |
||||
grpc_metadata_array_destroy(&self->recv_metadata); |
||||
grpc_metadata_array_destroy(&self->recv_trailing_metadata); |
||||
if (self->send_message) { |
||||
grpc_byte_buffer_destroy(self->send_message); |
||||
} |
||||
if (self->recv_message) { |
||||
grpc_byte_buffer_destroy(self->recv_message); |
||||
} |
||||
gpr_free(self->status_details); |
||||
gpr_free(self->send_metadata); |
||||
gpr_free(self->send_trailing_metadata); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_invoke(Call *self, PyObject *args) { |
||||
PyObject *completion_queue; |
||||
PyObject *metadata_tag; |
||||
PyObject *finish_tag; |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_init_metadata_tag; |
||||
pygrpc_tag *c_metadata_tag; |
||||
pygrpc_tag *c_finish_tag; |
||||
grpc_op send_initial_metadata; |
||||
grpc_op recv_initial_metadata; |
||||
grpc_op recv_status_on_client; |
||||
|
||||
if (!(PyArg_ParseTuple(args, "O!OO:invoke", &pygrpc_CompletionQueueType, |
||||
&completion_queue, &metadata_tag, &finish_tag))) { |
||||
return NULL; |
||||
} |
||||
send_initial_metadata.op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
send_initial_metadata.data.send_initial_metadata.metadata = self->send_metadata; |
||||
send_initial_metadata.data.send_initial_metadata.count = self->send_metadata_count; |
||||
recv_initial_metadata.op = GRPC_OP_RECV_INITIAL_METADATA; |
||||
recv_initial_metadata.data.recv_initial_metadata = &self->recv_metadata; |
||||
recv_status_on_client.op = GRPC_OP_RECV_STATUS_ON_CLIENT; |
||||
recv_status_on_client.data.recv_status_on_client.trailing_metadata = &self->recv_trailing_metadata; |
||||
recv_status_on_client.data.recv_status_on_client.status = &self->status; |
||||
recv_status_on_client.data.recv_status_on_client.status_details = &self->status_details; |
||||
recv_status_on_client.data.recv_status_on_client.status_details_capacity = &self->status_details_capacity; |
||||
c_init_metadata_tag = pygrpc_tag_new(PYGRPC_INITIAL_METADATA, NULL, self); |
||||
c_metadata_tag = pygrpc_tag_new(PYGRPC_CLIENT_METADATA_READ, metadata_tag, self); |
||||
c_finish_tag = pygrpc_tag_new(PYGRPC_FINISHED_CLIENT, finish_tag, self); |
||||
|
||||
call_error = grpc_call_start_batch(self->c_call, &send_initial_metadata, 1, c_init_metadata_tag); |
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_init_metadata_tag); |
||||
pygrpc_tag_destroy(c_metadata_tag); |
||||
pygrpc_tag_destroy(c_finish_tag); |
||||
return result; |
||||
} |
||||
call_error = grpc_call_start_batch(self->c_call, &recv_initial_metadata, 1, c_metadata_tag); |
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_metadata_tag); |
||||
pygrpc_tag_destroy(c_finish_tag); |
||||
return result; |
||||
} |
||||
call_error = grpc_call_start_batch(self->c_call, &recv_status_on_client, 1, c_finish_tag); |
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_finish_tag); |
||||
return result; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_write(Call *self, PyObject *args) { |
||||
const char *bytes; |
||||
int length; |
||||
PyObject *tag; |
||||
gpr_slice slice; |
||||
grpc_byte_buffer *byte_buffer; |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_tag; |
||||
grpc_op op; |
||||
|
||||
if (!(PyArg_ParseTuple(args, "s#O:write", &bytes, &length, &tag))) { |
||||
return NULL; |
||||
} |
||||
c_tag = pygrpc_tag_new(PYGRPC_WRITE_ACCEPTED, tag, self); |
||||
|
||||
slice = gpr_slice_from_copied_buffer(bytes, length); |
||||
byte_buffer = grpc_byte_buffer_create(&slice, 1); |
||||
gpr_slice_unref(slice); |
||||
|
||||
if (self->send_message) { |
||||
grpc_byte_buffer_destroy(self->send_message); |
||||
} |
||||
self->send_message = byte_buffer; |
||||
|
||||
op.op = GRPC_OP_SEND_MESSAGE; |
||||
op.data.send_message = self->send_message; |
||||
|
||||
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag); |
||||
|
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_tag); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_complete(Call *self, PyObject *tag) { |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_FINISH_ACCEPTED, tag, self); |
||||
grpc_op op; |
||||
|
||||
op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; |
||||
|
||||
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag); |
||||
|
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_tag); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_accept(Call *self, PyObject *args) { |
||||
PyObject *completion_queue; |
||||
PyObject *tag; |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_tag; |
||||
grpc_op op; |
||||
|
||||
if (!(PyArg_ParseTuple(args, "O!O:accept", &pygrpc_CompletionQueueType, |
||||
&completion_queue, &tag))) { |
||||
return NULL; |
||||
} |
||||
|
||||
op.op = GRPC_OP_RECV_CLOSE_ON_SERVER; |
||||
op.data.recv_close_on_server.cancelled = &self->cancelled; |
||||
c_tag = pygrpc_tag_new(PYGRPC_FINISHED_SERVER, tag, self); |
||||
|
||||
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag); |
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_tag); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_add_metadata(Call *self, PyObject *args) { |
||||
const char* key = NULL; |
||||
const char* value = NULL; |
||||
int value_length = 0; |
||||
grpc_metadata metadata; |
||||
if (!PyArg_ParseTuple(args, "ss#", &key, &value, &value_length)) { |
||||
return NULL; |
||||
} |
||||
metadata.key = key; |
||||
metadata.value = value; |
||||
metadata.value_length = value_length; |
||||
if (self->adding_to_trailing) { |
||||
self->send_trailing_metadata = gpr_realloc(self->send_trailing_metadata, (self->send_trailing_metadata_count + 1) * sizeof(grpc_metadata)); |
||||
self->send_trailing_metadata[self->send_trailing_metadata_count] = metadata; |
||||
self->send_trailing_metadata_count = self->send_trailing_metadata_count + 1; |
||||
} else { |
||||
self->send_metadata = gpr_realloc(self->send_metadata, (self->send_metadata_count + 1) * sizeof(grpc_metadata)); |
||||
self->send_metadata[self->send_metadata_count] = metadata; |
||||
self->send_metadata_count = self->send_metadata_count + 1; |
||||
} |
||||
return pygrpc_translate_call_error(GRPC_CALL_OK); |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_premetadata(Call *self) { |
||||
grpc_op op; |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_INITIAL_METADATA, NULL, self); |
||||
op.op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
op.data.send_initial_metadata.metadata = self->send_metadata; |
||||
op.data.send_initial_metadata.count = self->send_metadata_count; |
||||
self->adding_to_trailing = 1; |
||||
|
||||
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag); |
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_tag); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_read(Call *self, PyObject *tag) { |
||||
grpc_op op; |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_READ, tag, self); |
||||
|
||||
op.op = GRPC_OP_RECV_MESSAGE; |
||||
if (self->recv_message) { |
||||
grpc_byte_buffer_destroy(self->recv_message); |
||||
self->recv_message = NULL; |
||||
} |
||||
op.data.recv_message = &self->recv_message; |
||||
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag); |
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_tag); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_status(Call *self, PyObject *args) { |
||||
PyObject *status; |
||||
PyObject *code; |
||||
PyObject *details; |
||||
PyObject *tag; |
||||
grpc_status_code c_code; |
||||
char *c_message; |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_tag; |
||||
grpc_op op; |
||||
|
||||
if (!(PyArg_ParseTuple(args, "OO:status", &status, &tag))) { |
||||
return NULL; |
||||
} |
||||
c_tag = pygrpc_tag_new(PYGRPC_FINISH_ACCEPTED, tag, self); |
||||
|
||||
code = PyObject_GetAttrString(status, "code"); |
||||
if (code == NULL) { |
||||
return NULL; |
||||
} |
||||
details = PyObject_GetAttrString(status, "details"); |
||||
if (details == NULL) { |
||||
Py_DECREF(code); |
||||
return NULL; |
||||
} |
||||
c_code = PyInt_AsLong(code); |
||||
Py_DECREF(code); |
||||
if (c_code == -1 && PyErr_Occurred()) { |
||||
Py_DECREF(details); |
||||
return NULL; |
||||
} |
||||
c_message = PyBytes_AsString(details); |
||||
Py_DECREF(details); |
||||
if (c_message == NULL) { |
||||
return NULL; |
||||
} |
||||
if (self->status_details) { |
||||
gpr_free(self->status_details); |
||||
} |
||||
self->status_details = gpr_malloc(strlen(c_message)+1); |
||||
strcpy(self->status_details, c_message); |
||||
op.op = GRPC_OP_SEND_STATUS_FROM_SERVER; |
||||
op.data.send_status_from_server.trailing_metadata_count = self->send_trailing_metadata_count; |
||||
op.data.send_status_from_server.trailing_metadata = self->send_trailing_metadata; |
||||
op.data.send_status_from_server.status = c_code; |
||||
op.data.send_status_from_server.status_details = self->status_details; |
||||
|
||||
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag); |
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result == NULL) { |
||||
pygrpc_tag_destroy(c_tag); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_call_cancel(Call *self) { |
||||
return pygrpc_translate_call_error(grpc_call_cancel(self->c_call)); |
||||
} |
||||
|
||||
static PyMethodDef methods[] = { |
||||
{"invoke", (PyCFunction)pygrpc_call_invoke, METH_VARARGS, |
||||
"Invoke this call."}, |
||||
{"write", (PyCFunction)pygrpc_call_write, METH_VARARGS, |
||||
"Write bytes to this call."}, |
||||
{"complete", (PyCFunction)pygrpc_call_complete, METH_O, |
||||
"Complete writes to this call."}, |
||||
{"accept", (PyCFunction)pygrpc_call_accept, METH_VARARGS, "Accept an RPC."}, |
||||
{"add_metadata", (PyCFunction)pygrpc_call_add_metadata, METH_VARARGS, |
||||
"Add metadata to the call. May not be called after invoke on the client " |
||||
"side. On the server side: when called before premetadata it provides " |
||||
"'leading' metadata, when called after premetadata but before status it " |
||||
"provides 'trailing metadata'; may not be called after status."}, |
||||
{"premetadata", (PyCFunction)pygrpc_call_premetadata, METH_VARARGS, |
||||
"Indicate the end of leading metadata in the response."}, |
||||
{"read", (PyCFunction)pygrpc_call_read, METH_O, |
||||
"Read bytes from this call."}, |
||||
{"status", (PyCFunction)pygrpc_call_status, METH_VARARGS, |
||||
"Report this call's status."}, |
||||
{"cancel", (PyCFunction)pygrpc_call_cancel, METH_NOARGS, |
||||
"Cancel this call."}, |
||||
{NULL}}; |
||||
|
||||
PyTypeObject pygrpc_CallType = { |
||||
PyVarObject_HEAD_INIT(NULL, 0) |
||||
"_grpc.Call", /*tp_name*/ |
||||
sizeof(Call), /*tp_basicsize*/ |
||||
0, /*tp_itemsize*/ |
||||
(destructor)pygrpc_call_dealloc, /*tp_dealloc*/ |
||||
0, /*tp_print*/ |
||||
0, /*tp_getattr*/ |
||||
0, /*tp_setattr*/ |
||||
0, /*tp_compare*/ |
||||
0, /*tp_repr*/ |
||||
0, /*tp_as_number*/ |
||||
0, /*tp_as_sequence*/ |
||||
0, /*tp_as_mapping*/ |
||||
0, /*tp_hash */ |
||||
0, /*tp_call*/ |
||||
0, /*tp_str*/ |
||||
0, /*tp_getattro*/ |
||||
0, /*tp_setattro*/ |
||||
0, /*tp_as_buffer*/ |
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
||||
"Wrapping of grpc_call.", /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
0, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
pygrpc_call_new, /* tp_new */ |
||||
}; |
||||
|
||||
int pygrpc_add_call(PyObject *module) { |
||||
if (PyType_Ready(&pygrpc_CallType) < 0) { |
||||
return -1; |
||||
} |
||||
if (PyModule_AddObject(module, "Call", (PyObject *)&pygrpc_CallType) == -1) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
@ -1,77 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _ADAPTER__CALL_H_ |
||||
#define _ADAPTER__CALL_H_ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "grpc/_adapter/_completion_queue.h" |
||||
#include "grpc/_adapter/_channel.h" |
||||
#include "grpc/_adapter/_server.h" |
||||
|
||||
typedef struct { |
||||
PyObject_HEAD |
||||
|
||||
CompletionQueue *completion_queue; |
||||
Channel *channel; |
||||
Server *server; |
||||
|
||||
/* Legacy state. */ |
||||
grpc_call_details call_details; |
||||
grpc_metadata_array recv_metadata; |
||||
grpc_metadata_array recv_trailing_metadata; |
||||
grpc_metadata *send_metadata; |
||||
size_t send_metadata_count; |
||||
grpc_metadata *send_trailing_metadata; |
||||
size_t send_trailing_metadata_count; |
||||
int adding_to_trailing; |
||||
|
||||
grpc_byte_buffer *send_message; |
||||
grpc_byte_buffer *recv_message; |
||||
|
||||
grpc_status_code status; |
||||
char *status_details; |
||||
size_t status_details_capacity; |
||||
|
||||
int cancelled; |
||||
|
||||
grpc_call *c_call; |
||||
} Call; |
||||
|
||||
extern PyTypeObject pygrpc_CallType; |
||||
|
||||
int pygrpc_add_call(PyObject *module); |
||||
|
||||
#endif /* _ADAPTER__CALL_H_ */ |
@ -1,135 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_channel.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/grpc_security.h> |
||||
|
||||
#include "grpc/_adapter/_client_credentials.h" |
||||
|
||||
static int pygrpc_channel_init(Channel *self, PyObject *args, PyObject *kwds) { |
||||
const char *hostport; |
||||
PyObject *client_credentials; |
||||
char *server_host_override = NULL; |
||||
static char *kwlist[] = {"hostport", "client_credentials", |
||||
"server_host_override", NULL}; |
||||
grpc_arg server_host_override_arg; |
||||
grpc_channel_args channel_args; |
||||
|
||||
if (!(PyArg_ParseTupleAndKeywords(args, kwds, "sO|z:Channel", kwlist, |
||||
&hostport, &client_credentials, |
||||
&server_host_override))) { |
||||
return -1; |
||||
} |
||||
if (client_credentials == Py_None) { |
||||
self->c_channel = grpc_channel_create(hostport, NULL); |
||||
return 0; |
||||
} else { |
||||
if (server_host_override == NULL) { |
||||
self->c_channel = grpc_secure_channel_create( |
||||
((ClientCredentials *)client_credentials)->c_client_credentials, |
||||
hostport, NULL); |
||||
} else { |
||||
server_host_override_arg.type = GRPC_ARG_STRING; |
||||
server_host_override_arg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG; |
||||
server_host_override_arg.value.string = server_host_override; |
||||
channel_args.num_args = 1; |
||||
channel_args.args = &server_host_override_arg; |
||||
self->c_channel = grpc_secure_channel_create( |
||||
((ClientCredentials *)client_credentials)->c_client_credentials, |
||||
hostport, &channel_args); |
||||
} |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
static void pygrpc_channel_dealloc(Channel *self) { |
||||
if (self->c_channel != NULL) { |
||||
grpc_channel_destroy(self->c_channel); |
||||
} |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
PyTypeObject pygrpc_ChannelType = { |
||||
PyVarObject_HEAD_INIT(NULL, 0) |
||||
"_grpc.Channel", /*tp_name*/ |
||||
sizeof(Channel), /*tp_basicsize*/ |
||||
0, /*tp_itemsize*/ |
||||
(destructor)pygrpc_channel_dealloc, /*tp_dealloc*/ |
||||
0, /*tp_print*/ |
||||
0, /*tp_getattr*/ |
||||
0, /*tp_setattr*/ |
||||
0, /*tp_compare*/ |
||||
0, /*tp_repr*/ |
||||
0, /*tp_as_number*/ |
||||
0, /*tp_as_sequence*/ |
||||
0, /*tp_as_mapping*/ |
||||
0, /*tp_hash */ |
||||
0, /*tp_call*/ |
||||
0, /*tp_str*/ |
||||
0, /*tp_getattro*/ |
||||
0, /*tp_setattro*/ |
||||
0, /*tp_as_buffer*/ |
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
||||
"Wrapping of grpc_channel.", /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
0, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
(initproc)pygrpc_channel_init, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
PyType_GenericNew, /* tp_new */ |
||||
}; |
||||
|
||||
int pygrpc_add_channel(PyObject *module) { |
||||
if (PyType_Ready(&pygrpc_ChannelType) < 0) { |
||||
return -1; |
||||
} |
||||
if (PyModule_AddObject(module, "Channel", (PyObject *)&pygrpc_ChannelType) == |
||||
-1) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
@ -1,49 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _ADAPTER__CHANNEL_H_ |
||||
#define _ADAPTER__CHANNEL_H_ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
typedef struct { |
||||
PyObject_HEAD |
||||
grpc_channel *c_channel; |
||||
} Channel; |
||||
|
||||
extern PyTypeObject pygrpc_ChannelType; |
||||
|
||||
int pygrpc_add_channel(PyObject *module); |
||||
|
||||
#endif /* _ADAPTER__CHANNEL_H_ */ |
@ -1,121 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_client_credentials.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc_security.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
static int pygrpc_client_credentials_init(ClientCredentials *self, |
||||
PyObject *args, PyObject *kwds) { |
||||
char *root_certificates; |
||||
grpc_ssl_pem_key_cert_pair key_certificate_pair; |
||||
static char *kwlist[] = {"root_certificates", "private_key", |
||||
"certificate_chain", NULL}; |
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "zzz:ClientCredentials", kwlist, |
||||
&root_certificates, |
||||
&key_certificate_pair.private_key, |
||||
&key_certificate_pair.cert_chain)) { |
||||
return -1; |
||||
} |
||||
|
||||
if (key_certificate_pair.private_key != NULL && key_certificate_pair.cert_chain != NULL) { |
||||
self->c_client_credentials = |
||||
grpc_ssl_credentials_create(root_certificates, &key_certificate_pair); |
||||
} else { |
||||
self->c_client_credentials = |
||||
grpc_ssl_credentials_create(root_certificates, NULL); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static void pygrpc_client_credentials_dealloc(ClientCredentials *self) { |
||||
if (self->c_client_credentials != NULL) { |
||||
grpc_credentials_release(self->c_client_credentials); |
||||
} |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
PyTypeObject pygrpc_ClientCredentialsType = { |
||||
PyVarObject_HEAD_INIT(NULL, 0) |
||||
"_grpc.ClientCredencials", /*tp_name*/ |
||||
sizeof(ClientCredentials), /*tp_basicsize*/ |
||||
0, /*tp_itemsize*/ |
||||
(destructor)pygrpc_client_credentials_dealloc, /*tp_dealloc*/ |
||||
0, /*tp_print*/ |
||||
0, /*tp_getattr*/ |
||||
0, /*tp_setattr*/ |
||||
0, /*tp_compare*/ |
||||
0, /*tp_repr*/ |
||||
0, /*tp_as_number*/ |
||||
0, /*tp_as_sequence*/ |
||||
0, /*tp_as_mapping*/ |
||||
0, /*tp_hash */ |
||||
0, /*tp_call*/ |
||||
0, /*tp_str*/ |
||||
0, /*tp_getattro*/ |
||||
0, /*tp_setattro*/ |
||||
0, /*tp_as_buffer*/ |
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
||||
"Wrapping of grpc_credentials.", /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
0, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
(initproc)pygrpc_client_credentials_init, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
PyType_GenericNew, /* tp_new */ |
||||
}; |
||||
|
||||
int pygrpc_add_client_credentials(PyObject *module) { |
||||
if (PyType_Ready(&pygrpc_ClientCredentialsType) < 0) { |
||||
return -1; |
||||
} |
||||
if (PyModule_AddObject(module, "ClientCredentials", |
||||
(PyObject *)&pygrpc_ClientCredentialsType) == -1) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
@ -1,49 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _ADAPTER__CLIENT_CREDENTIALS_H_ |
||||
#define _ADAPTER__CLIENT_CREDENTIALS_H_ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc_security.h> |
||||
|
||||
typedef struct { |
||||
PyObject_HEAD |
||||
grpc_credentials *c_client_credentials; |
||||
} ClientCredentials; |
||||
|
||||
extern PyTypeObject pygrpc_ClientCredentialsType; |
||||
|
||||
int pygrpc_add_client_credentials(PyObject *module); |
||||
|
||||
#endif /* _ADAPTER__CLIENT_CREDENTIALS_H_ */ |
@ -1,653 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_completion_queue.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "grpc/_adapter/_call.h" |
||||
#include "grpc/_adapter/_tag.h" |
||||
|
||||
static PyObject *status_class; |
||||
static PyObject *service_acceptance_class; |
||||
static PyObject *event_class; |
||||
|
||||
static PyObject *ok_status_code; |
||||
static PyObject *cancelled_status_code; |
||||
static PyObject *unknown_status_code; |
||||
static PyObject *invalid_argument_status_code; |
||||
static PyObject *expired_status_code; |
||||
static PyObject *not_found_status_code; |
||||
static PyObject *already_exists_status_code; |
||||
static PyObject *permission_denied_status_code; |
||||
static PyObject *unauthenticated_status_code; |
||||
static PyObject *resource_exhausted_status_code; |
||||
static PyObject *failed_precondition_status_code; |
||||
static PyObject *aborted_status_code; |
||||
static PyObject *out_of_range_status_code; |
||||
static PyObject *unimplemented_status_code; |
||||
static PyObject *internal_error_status_code; |
||||
static PyObject *unavailable_status_code; |
||||
static PyObject *data_loss_status_code; |
||||
|
||||
static PyObject *stop_event_kind; |
||||
static PyObject *write_event_kind; |
||||
static PyObject *complete_event_kind; |
||||
static PyObject *service_event_kind; |
||||
static PyObject *read_event_kind; |
||||
static PyObject *metadata_event_kind; |
||||
static PyObject *finish_event_kind; |
||||
|
||||
static PyObject *pygrpc_as_py_time(gpr_timespec *timespec) { |
||||
return PyFloat_FromDouble( |
||||
timespec->tv_sec + ((double)timespec->tv_nsec) / 1.0E9); |
||||
} |
||||
|
||||
static PyObject *pygrpc_status_code(grpc_status_code c_status_code) { |
||||
switch (c_status_code) { |
||||
case GRPC_STATUS_OK: |
||||
return ok_status_code; |
||||
case GRPC_STATUS_CANCELLED: |
||||
return cancelled_status_code; |
||||
case GRPC_STATUS_UNKNOWN: |
||||
return unknown_status_code; |
||||
case GRPC_STATUS_INVALID_ARGUMENT: |
||||
return invalid_argument_status_code; |
||||
case GRPC_STATUS_DEADLINE_EXCEEDED: |
||||
return expired_status_code; |
||||
case GRPC_STATUS_NOT_FOUND: |
||||
return not_found_status_code; |
||||
case GRPC_STATUS_ALREADY_EXISTS: |
||||
return already_exists_status_code; |
||||
case GRPC_STATUS_PERMISSION_DENIED: |
||||
return permission_denied_status_code; |
||||
case GRPC_STATUS_UNAUTHENTICATED: |
||||
return unauthenticated_status_code; |
||||
case GRPC_STATUS_RESOURCE_EXHAUSTED: |
||||
return resource_exhausted_status_code; |
||||
case GRPC_STATUS_FAILED_PRECONDITION: |
||||
return failed_precondition_status_code; |
||||
case GRPC_STATUS_ABORTED: |
||||
return aborted_status_code; |
||||
case GRPC_STATUS_OUT_OF_RANGE: |
||||
return out_of_range_status_code; |
||||
case GRPC_STATUS_UNIMPLEMENTED: |
||||
return unimplemented_status_code; |
||||
case GRPC_STATUS_INTERNAL: |
||||
return internal_error_status_code; |
||||
case GRPC_STATUS_UNAVAILABLE: |
||||
return unavailable_status_code; |
||||
case GRPC_STATUS_DATA_LOSS: |
||||
return data_loss_status_code; |
||||
default: |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
static PyObject *pygrpc_metadata_collection_get( |
||||
grpc_metadata *metadata_elements, size_t count) { |
||||
PyObject *metadata = PyList_New(count); |
||||
size_t i; |
||||
for (i = 0; i < count; ++i) { |
||||
grpc_metadata elem = metadata_elements[i]; |
||||
PyObject *key = PyString_FromString(elem.key); |
||||
PyObject *value = PyString_FromStringAndSize(elem.value, elem.value_length); |
||||
PyObject* kvp = PyTuple_Pack(2, key, value); |
||||
/* n.b. PyList_SetItem *steals* a reference to the set element. */ |
||||
PyList_SetItem(metadata, i, kvp); |
||||
Py_DECREF(key); |
||||
Py_DECREF(value); |
||||
} |
||||
return metadata; |
||||
} |
||||
|
||||
static PyObject *pygrpc_stop_event_args(grpc_event *c_event) { |
||||
return PyTuple_Pack(8, stop_event_kind, Py_None, Py_None, Py_None, |
||||
Py_None, Py_None, Py_None, Py_None); |
||||
} |
||||
|
||||
static PyObject *pygrpc_write_event_args(grpc_event *c_event) { |
||||
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag); |
||||
PyObject *user_tag = tag->user_tag; |
||||
PyObject *write_accepted = Py_True; |
||||
return PyTuple_Pack(8, write_event_kind, user_tag, |
||||
write_accepted, Py_None, Py_None, Py_None, Py_None, |
||||
Py_None); |
||||
} |
||||
|
||||
static PyObject *pygrpc_complete_event_args(grpc_event *c_event) { |
||||
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag); |
||||
PyObject *user_tag = tag->user_tag; |
||||
PyObject *complete_accepted = Py_True; |
||||
return PyTuple_Pack(8, complete_event_kind, user_tag, |
||||
Py_None, complete_accepted, Py_None, Py_None, Py_None, |
||||
Py_None); |
||||
} |
||||
|
||||
static PyObject *pygrpc_service_event_args(grpc_event *c_event) { |
||||
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag); |
||||
PyObject *user_tag = tag->user_tag; |
||||
if (tag->call->call_details.method == NULL) { |
||||
return PyTuple_Pack( |
||||
8, service_event_kind, user_tag, Py_None, Py_None, Py_None, Py_None, |
||||
Py_None, Py_None); |
||||
} else { |
||||
PyObject *method = NULL; |
||||
PyObject *host = NULL; |
||||
PyObject *service_deadline = NULL; |
||||
PyObject *service_acceptance = NULL; |
||||
PyObject *metadata = NULL; |
||||
PyObject *event_args = NULL; |
||||
|
||||
method = PyBytes_FromString(tag->call->call_details.method); |
||||
if (method == NULL) { |
||||
goto error; |
||||
} |
||||
host = PyBytes_FromString(tag->call->call_details.host); |
||||
if (host == NULL) { |
||||
goto error; |
||||
} |
||||
service_deadline = |
||||
pygrpc_as_py_time(&tag->call->call_details.deadline); |
||||
if (service_deadline == NULL) { |
||||
goto error; |
||||
} |
||||
|
||||
service_acceptance = |
||||
PyObject_CallFunctionObjArgs(service_acceptance_class, tag->call, |
||||
method, host, service_deadline, NULL); |
||||
if (service_acceptance == NULL) { |
||||
goto error; |
||||
} |
||||
|
||||
metadata = pygrpc_metadata_collection_get( |
||||
tag->call->recv_metadata.metadata, |
||||
tag->call->recv_metadata.count); |
||||
event_args = PyTuple_Pack(8, service_event_kind, |
||||
user_tag, Py_None, Py_None, |
||||
service_acceptance, Py_None, Py_None, |
||||
metadata); |
||||
|
||||
Py_DECREF(service_acceptance); |
||||
Py_DECREF(metadata); |
||||
error: |
||||
Py_XDECREF(method); |
||||
Py_XDECREF(host); |
||||
Py_XDECREF(service_deadline); |
||||
|
||||
return event_args; |
||||
} |
||||
} |
||||
|
||||
static PyObject *pygrpc_read_event_args(grpc_event *c_event) { |
||||
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag); |
||||
PyObject *user_tag = tag->user_tag; |
||||
if (tag->call->recv_message == NULL) { |
||||
return PyTuple_Pack(8, read_event_kind, user_tag, |
||||
Py_None, Py_None, Py_None, Py_None, Py_None, Py_None); |
||||
} else { |
||||
size_t length; |
||||
size_t offset; |
||||
grpc_byte_buffer_reader *reader; |
||||
gpr_slice slice; |
||||
char *c_bytes; |
||||
PyObject *bytes; |
||||
PyObject *event_args; |
||||
|
||||
length = grpc_byte_buffer_length(tag->call->recv_message); |
||||
reader = grpc_byte_buffer_reader_create(tag->call->recv_message); |
||||
c_bytes = gpr_malloc(length); |
||||
offset = 0; |
||||
while (grpc_byte_buffer_reader_next(reader, &slice)) { |
||||
memcpy(c_bytes + offset, GPR_SLICE_START_PTR(slice), |
||||
GPR_SLICE_LENGTH(slice)); |
||||
offset += GPR_SLICE_LENGTH(slice); |
||||
} |
||||
grpc_byte_buffer_reader_destroy(reader); |
||||
bytes = PyBytes_FromStringAndSize(c_bytes, length); |
||||
gpr_free(c_bytes); |
||||
if (bytes == NULL) { |
||||
return NULL; |
||||
} |
||||
event_args = PyTuple_Pack(8, read_event_kind, user_tag, |
||||
Py_None, Py_None, Py_None, bytes, Py_None, |
||||
Py_None); |
||||
Py_DECREF(bytes); |
||||
return event_args; |
||||
} |
||||
} |
||||
|
||||
static PyObject *pygrpc_metadata_event_args(grpc_event *c_event) { |
||||
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag); |
||||
PyObject *user_tag = tag->user_tag; |
||||
PyObject *metadata = pygrpc_metadata_collection_get( |
||||
tag->call->recv_metadata.metadata, |
||||
tag->call->recv_metadata.count); |
||||
PyObject* result = PyTuple_Pack( |
||||
8, metadata_event_kind, user_tag, Py_None, Py_None, |
||||
Py_None, Py_None, Py_None, metadata); |
||||
Py_DECREF(metadata); |
||||
return result; |
||||
} |
||||
|
||||
static PyObject *pygrpc_finished_server_event_args(grpc_event *c_event) { |
||||
PyObject *code; |
||||
PyObject *details; |
||||
PyObject *status; |
||||
PyObject *event_args; |
||||
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag); |
||||
PyObject *user_tag = tag->user_tag; |
||||
|
||||
code = pygrpc_status_code(tag->call->cancelled ? GRPC_STATUS_CANCELLED : GRPC_STATUS_OK); |
||||
if (code == NULL) { |
||||
PyErr_SetString(PyExc_RuntimeError, "Unrecognized status code!"); |
||||
return NULL; |
||||
} |
||||
details = PyBytes_FromString(""); |
||||
if (details == NULL) { |
||||
return NULL; |
||||
} |
||||
status = PyObject_CallFunctionObjArgs(status_class, code, details, NULL); |
||||
Py_DECREF(details); |
||||
if (status == NULL) { |
||||
return NULL; |
||||
} |
||||
event_args = PyTuple_Pack(8, finish_event_kind, user_tag, |
||||
Py_None, Py_None, Py_None, Py_None, status, |
||||
Py_None); |
||||
Py_DECREF(status); |
||||
return event_args; |
||||
} |
||||
|
||||
static PyObject *pygrpc_finished_client_event_args(grpc_event *c_event) { |
||||
PyObject *code; |
||||
PyObject *details; |
||||
PyObject *status; |
||||
PyObject *event_args; |
||||
PyObject *metadata; |
||||
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag); |
||||
PyObject *user_tag = tag->user_tag; |
||||
|
||||
code = pygrpc_status_code(tag->call->status); |
||||
if (code == NULL) { |
||||
PyErr_SetString(PyExc_RuntimeError, "Unrecognized status code!"); |
||||
return NULL; |
||||
} |
||||
if (tag->call->status_details == NULL) { |
||||
details = PyBytes_FromString(""); |
||||
} else { |
||||
details = PyBytes_FromString(tag->call->status_details); |
||||
} |
||||
if (details == NULL) { |
||||
return NULL; |
||||
} |
||||
status = PyObject_CallFunctionObjArgs(status_class, code, details, NULL); |
||||
Py_DECREF(details); |
||||
if (status == NULL) { |
||||
return NULL; |
||||
} |
||||
metadata = pygrpc_metadata_collection_get( |
||||
tag->call->recv_trailing_metadata.metadata, |
||||
tag->call->recv_trailing_metadata.count); |
||||
event_args = PyTuple_Pack(8, finish_event_kind, user_tag, |
||||
Py_None, Py_None, Py_None, Py_None, status, |
||||
metadata); |
||||
Py_DECREF(status); |
||||
Py_DECREF(metadata); |
||||
return event_args; |
||||
} |
||||
|
||||
static int pygrpc_completion_queue_init(CompletionQueue *self, PyObject *args, |
||||
PyObject *kwds) { |
||||
static char *kwlist[] = {NULL}; |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, ":CompletionQueue", kwlist)) { |
||||
return -1; |
||||
} |
||||
self->c_completion_queue = grpc_completion_queue_create(); |
||||
return 0; |
||||
} |
||||
|
||||
static void pygrpc_completion_queue_dealloc(CompletionQueue *self) { |
||||
grpc_completion_queue_destroy(self->c_completion_queue); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
static PyObject *pygrpc_completion_queue_get(CompletionQueue *self, |
||||
PyObject *args) { |
||||
PyObject *deadline; |
||||
double double_deadline; |
||||
gpr_timespec deadline_timespec; |
||||
grpc_event c_event; |
||||
|
||||
PyObject *event_args; |
||||
PyObject *event; |
||||
|
||||
pygrpc_tag *tag; |
||||
|
||||
if (!(PyArg_ParseTuple(args, "O:get", &deadline))) { |
||||
return NULL; |
||||
} |
||||
|
||||
if (deadline == Py_None) { |
||||
deadline_timespec = gpr_inf_future; |
||||
} else { |
||||
double_deadline = PyFloat_AsDouble(deadline); |
||||
if (PyErr_Occurred()) { |
||||
return NULL; |
||||
} |
||||
deadline_timespec = gpr_time_from_nanos((long)(double_deadline * 1.0E9)); |
||||
} |
||||
|
||||
/* TODO(nathaniel): Suppress clang-format in this block and remove the
|
||||
unnecessary and unPythonic semicolons trailing the _ALLOW_THREADS macros. |
||||
(Right now clang-format only understands //-demarcated suppressions.) */
|
||||
Py_BEGIN_ALLOW_THREADS; |
||||
c_event = |
||||
grpc_completion_queue_next(self->c_completion_queue, deadline_timespec); |
||||
Py_END_ALLOW_THREADS; |
||||
|
||||
tag = (pygrpc_tag *)c_event.tag; |
||||
|
||||
switch (c_event.type) { |
||||
case GRPC_QUEUE_TIMEOUT: |
||||
Py_RETURN_NONE; |
||||
break; |
||||
case GRPC_QUEUE_SHUTDOWN: |
||||
event_args = pygrpc_stop_event_args(&c_event); |
||||
break; |
||||
case GRPC_OP_COMPLETE: { |
||||
if (!tag) { |
||||
PyErr_SetString(PyExc_Exception, "Unrecognized event type!"); |
||||
return NULL; |
||||
} |
||||
switch (tag->type) { |
||||
case PYGRPC_INITIAL_METADATA: |
||||
if (tag) { |
||||
pygrpc_tag_destroy(tag); |
||||
} |
||||
return pygrpc_completion_queue_get(self, args); |
||||
case PYGRPC_WRITE_ACCEPTED: |
||||
event_args = pygrpc_write_event_args(&c_event); |
||||
break; |
||||
case PYGRPC_FINISH_ACCEPTED: |
||||
event_args = pygrpc_complete_event_args(&c_event); |
||||
break; |
||||
case PYGRPC_SERVER_RPC_NEW: |
||||
event_args = pygrpc_service_event_args(&c_event); |
||||
break; |
||||
case PYGRPC_READ: |
||||
event_args = pygrpc_read_event_args(&c_event); |
||||
break; |
||||
case PYGRPC_CLIENT_METADATA_READ: |
||||
event_args = pygrpc_metadata_event_args(&c_event); |
||||
break; |
||||
case PYGRPC_FINISHED_CLIENT: |
||||
event_args = pygrpc_finished_client_event_args(&c_event); |
||||
break; |
||||
case PYGRPC_FINISHED_SERVER: |
||||
event_args = pygrpc_finished_server_event_args(&c_event); |
||||
break; |
||||
default: |
||||
PyErr_SetString(PyExc_Exception, "Unrecognized op event type!"); |
||||
return NULL; |
||||
} |
||||
break; |
||||
} |
||||
default: |
||||
PyErr_SetString(PyExc_Exception, "Unrecognized event type!"); |
||||
return NULL; |
||||
} |
||||
|
||||
if (event_args == NULL) { |
||||
return NULL; |
||||
} |
||||
|
||||
event = PyObject_CallObject(event_class, event_args); |
||||
|
||||
Py_DECREF(event_args); |
||||
if (tag) { |
||||
pygrpc_tag_destroy(tag); |
||||
} |
||||
|
||||
return event; |
||||
} |
||||
|
||||
static PyObject *pygrpc_completion_queue_stop(CompletionQueue *self) { |
||||
grpc_completion_queue_shutdown(self->c_completion_queue); |
||||
|
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
static PyMethodDef methods[] = { |
||||
{"get", (PyCFunction)pygrpc_completion_queue_get, METH_VARARGS, |
||||
"Get the next event."}, |
||||
{"stop", (PyCFunction)pygrpc_completion_queue_stop, METH_NOARGS, |
||||
"Stop this completion queue."}, |
||||
{NULL}}; |
||||
|
||||
PyTypeObject pygrpc_CompletionQueueType = { |
||||
PyVarObject_HEAD_INIT(NULL, 0) |
||||
"_gprc.CompletionQueue", /*tp_name*/ |
||||
sizeof(CompletionQueue), /*tp_basicsize*/ |
||||
0, /*tp_itemsize*/ |
||||
(destructor)pygrpc_completion_queue_dealloc, /*tp_dealloc*/ |
||||
0, /*tp_print*/ |
||||
0, /*tp_getattr*/ |
||||
0, /*tp_setattr*/ |
||||
0, /*tp_compare*/ |
||||
0, /*tp_repr*/ |
||||
0, /*tp_as_number*/ |
||||
0, /*tp_as_sequence*/ |
||||
0, /*tp_as_mapping*/ |
||||
0, /*tp_hash */ |
||||
0, /*tp_call*/ |
||||
0, /*tp_str*/ |
||||
0, /*tp_getattro*/ |
||||
0, /*tp_setattro*/ |
||||
0, /*tp_as_buffer*/ |
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
||||
"Wrapping of grpc_completion_queue.", /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
(initproc)pygrpc_completion_queue_init, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
PyType_GenericNew, /* tp_new */ |
||||
}; |
||||
|
||||
static int pygrpc_get_status_codes(PyObject *datatypes_module) { |
||||
PyObject *code_class = PyObject_GetAttrString(datatypes_module, "Code"); |
||||
if (code_class == NULL) { |
||||
return -1; |
||||
} |
||||
ok_status_code = PyObject_GetAttrString(code_class, "OK"); |
||||
if (ok_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
cancelled_status_code = PyObject_GetAttrString(code_class, "CANCELLED"); |
||||
if (cancelled_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
unknown_status_code = PyObject_GetAttrString(code_class, "UNKNOWN"); |
||||
if (unknown_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
invalid_argument_status_code = |
||||
PyObject_GetAttrString(code_class, "INVALID_ARGUMENT"); |
||||
if (invalid_argument_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
expired_status_code = PyObject_GetAttrString(code_class, "EXPIRED"); |
||||
if (expired_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
not_found_status_code = PyObject_GetAttrString(code_class, "NOT_FOUND"); |
||||
if (not_found_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
already_exists_status_code = |
||||
PyObject_GetAttrString(code_class, "ALREADY_EXISTS"); |
||||
if (already_exists_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
permission_denied_status_code = |
||||
PyObject_GetAttrString(code_class, "PERMISSION_DENIED"); |
||||
if (permission_denied_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
unauthenticated_status_code = |
||||
PyObject_GetAttrString(code_class, "UNAUTHENTICATED"); |
||||
if (unauthenticated_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
resource_exhausted_status_code = |
||||
PyObject_GetAttrString(code_class, "RESOURCE_EXHAUSTED"); |
||||
if (resource_exhausted_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
failed_precondition_status_code = |
||||
PyObject_GetAttrString(code_class, "FAILED_PRECONDITION"); |
||||
if (failed_precondition_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
aborted_status_code = PyObject_GetAttrString(code_class, "ABORTED"); |
||||
if (aborted_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
out_of_range_status_code = PyObject_GetAttrString(code_class, "OUT_OF_RANGE"); |
||||
if (out_of_range_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
unimplemented_status_code = |
||||
PyObject_GetAttrString(code_class, "UNIMPLEMENTED"); |
||||
if (unimplemented_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
internal_error_status_code = |
||||
PyObject_GetAttrString(code_class, "INTERNAL_ERROR"); |
||||
if (internal_error_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
unavailable_status_code = PyObject_GetAttrString(code_class, "UNAVAILABLE"); |
||||
if (unavailable_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
data_loss_status_code = PyObject_GetAttrString(code_class, "DATA_LOSS"); |
||||
if (data_loss_status_code == NULL) { |
||||
return -1; |
||||
} |
||||
Py_DECREF(code_class); |
||||
return 0; |
||||
} |
||||
|
||||
static int pygrpc_get_event_kinds(PyObject *event_class) { |
||||
PyObject *kind_class = PyObject_GetAttrString(event_class, "Kind"); |
||||
if (kind_class == NULL) { |
||||
return -1; |
||||
} |
||||
stop_event_kind = PyObject_GetAttrString(kind_class, "STOP"); |
||||
if (stop_event_kind == NULL) { |
||||
return -1; |
||||
} |
||||
write_event_kind = PyObject_GetAttrString(kind_class, "WRITE_ACCEPTED"); |
||||
if (write_event_kind == NULL) { |
||||
return -1; |
||||
} |
||||
complete_event_kind = PyObject_GetAttrString(kind_class, "COMPLETE_ACCEPTED"); |
||||
if (complete_event_kind == NULL) { |
||||
return -1; |
||||
} |
||||
service_event_kind = PyObject_GetAttrString(kind_class, "SERVICE_ACCEPTED"); |
||||
if (service_event_kind == NULL) { |
||||
return -1; |
||||
} |
||||
read_event_kind = PyObject_GetAttrString(kind_class, "READ_ACCEPTED"); |
||||
if (read_event_kind == NULL) { |
||||
return -1; |
||||
} |
||||
metadata_event_kind = PyObject_GetAttrString(kind_class, "METADATA_ACCEPTED"); |
||||
if (metadata_event_kind == NULL) { |
||||
return -1; |
||||
} |
||||
finish_event_kind = PyObject_GetAttrString(kind_class, "FINISH"); |
||||
if (finish_event_kind == NULL) { |
||||
return -1; |
||||
} |
||||
Py_DECREF(kind_class); |
||||
return 0; |
||||
} |
||||
|
||||
int pygrpc_add_completion_queue(PyObject *module) { |
||||
char *datatypes_module_path = "grpc._adapter._datatypes"; |
||||
PyObject *datatypes_module = PyImport_ImportModule(datatypes_module_path); |
||||
if (datatypes_module == NULL) { |
||||
return -1; |
||||
} |
||||
status_class = PyObject_GetAttrString(datatypes_module, "Status"); |
||||
service_acceptance_class = |
||||
PyObject_GetAttrString(datatypes_module, "ServiceAcceptance"); |
||||
event_class = PyObject_GetAttrString(datatypes_module, "Event"); |
||||
if (status_class == NULL || service_acceptance_class == NULL || |
||||
event_class == NULL) { |
||||
return -1; |
||||
} |
||||
if (pygrpc_get_status_codes(datatypes_module) == -1) { |
||||
return -1; |
||||
} |
||||
if (pygrpc_get_event_kinds(event_class) == -1) { |
||||
return -1; |
||||
} |
||||
Py_DECREF(datatypes_module); |
||||
|
||||
if (PyType_Ready(&pygrpc_CompletionQueueType) < 0) { |
||||
return -1; |
||||
} |
||||
if (PyModule_AddObject(module, "CompletionQueue", |
||||
(PyObject *)&pygrpc_CompletionQueueType) == -1) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
@ -1,86 +0,0 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
"""Datatypes passed between Python and C code.""" |
||||
|
||||
import collections |
||||
import enum |
||||
|
||||
|
||||
@enum.unique |
||||
class Code(enum.IntEnum): |
||||
"""One Platform error codes (see status.h and codes.proto).""" |
||||
|
||||
OK = 0 |
||||
CANCELLED = 1 |
||||
UNKNOWN = 2 |
||||
INVALID_ARGUMENT = 3 |
||||
EXPIRED = 4 |
||||
NOT_FOUND = 5 |
||||
ALREADY_EXISTS = 6 |
||||
PERMISSION_DENIED = 7 |
||||
UNAUTHENTICATED = 16 |
||||
RESOURCE_EXHAUSTED = 8 |
||||
FAILED_PRECONDITION = 9 |
||||
ABORTED = 10 |
||||
OUT_OF_RANGE = 11 |
||||
UNIMPLEMENTED = 12 |
||||
INTERNAL_ERROR = 13 |
||||
UNAVAILABLE = 14 |
||||
DATA_LOSS = 15 |
||||
|
||||
|
||||
class Status(collections.namedtuple('Status', ['code', 'details'])): |
||||
"""Describes an RPC's overall status.""" |
||||
|
||||
|
||||
class ServiceAcceptance( |
||||
collections.namedtuple( |
||||
'ServiceAcceptance', ['call', 'method', 'host', 'deadline'])): |
||||
"""Describes an RPC on the service side at the start of service.""" |
||||
|
||||
|
||||
class Event( |
||||
collections.namedtuple( |
||||
'Event', |
||||
['kind', 'tag', 'write_accepted', 'complete_accepted', |
||||
'service_acceptance', 'bytes', 'status', 'metadata'])): |
||||
"""Describes an event emitted from a completion queue.""" |
||||
|
||||
@enum.unique |
||||
class Kind(enum.Enum): |
||||
"""Describes the kind of an event.""" |
||||
|
||||
STOP = object() |
||||
WRITE_ACCEPTED = object() |
||||
COMPLETE_ACCEPTED = object() |
||||
SERVICE_ACCEPTED = object() |
||||
READ_ACCEPTED = object() |
||||
METADATA_ACCEPTED = object() |
||||
FINISH = object() |
@ -1,79 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_error.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
const PyObject *pygrpc_translate_call_error(grpc_call_error call_error) { |
||||
switch (call_error) { |
||||
case GRPC_CALL_OK: |
||||
Py_RETURN_NONE; |
||||
case GRPC_CALL_ERROR: |
||||
PyErr_SetString(PyExc_Exception, "Defect: unknown defect!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_NOT_ON_SERVER: |
||||
PyErr_SetString(PyExc_Exception, |
||||
"Defect: client-only method called on server!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_NOT_ON_CLIENT: |
||||
PyErr_SetString(PyExc_Exception, |
||||
"Defect: server-only method called on client!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_ALREADY_ACCEPTED: |
||||
PyErr_SetString(PyExc_Exception, |
||||
"Defect: attempted to accept already-accepted call!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_ALREADY_INVOKED: |
||||
PyErr_SetString(PyExc_Exception, |
||||
"Defect: attempted to invoke already-invoked call!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_NOT_INVOKED: |
||||
PyErr_SetString(PyExc_Exception, "Defect: Call not yet invoked!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_ALREADY_FINISHED: |
||||
PyErr_SetString(PyExc_Exception, "Defect: Call already finished!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_TOO_MANY_OPERATIONS: |
||||
PyErr_SetString(PyExc_Exception, |
||||
"Defect: Attempted extra read or extra write on call!"); |
||||
return NULL; |
||||
case GRPC_CALL_ERROR_INVALID_FLAGS: |
||||
PyErr_SetString(PyExc_Exception, "Defect: invalid flags!"); |
||||
return NULL; |
||||
default: |
||||
PyErr_SetString(PyExc_Exception, "Defect: Unknown call error!"); |
||||
return NULL; |
||||
} |
||||
} |
@ -1,42 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _ADAPTER__ERROR_H_ |
||||
#define _ADAPTER__ERROR_H_ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
const PyObject *pygrpc_translate_call_error(grpc_call_error call_error); |
||||
|
||||
#endif /* _ADAPTER__ERROR_H_ */ |
@ -0,0 +1,258 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
"""Temporary old _low-like layer. |
||||
|
||||
Eases refactoring burden while we overhaul the Python framework. |
||||
|
||||
Plan: |
||||
The layers used to look like: |
||||
... # outside _adapter |
||||
fore.py + rear.py # visible outside _adapter |
||||
_low |
||||
_c |
||||
The layers currently look like: |
||||
... # outside _adapter |
||||
fore.py + rear.py # visible outside _adapter |
||||
_low_intermediary # adapter for new '_low' to old '_low' |
||||
_low # new '_low' |
||||
_c # new '_c' |
||||
We will later remove _low_intermediary after refactoring of fore.py and |
||||
rear.py according to the ticket system refactoring and get: |
||||
... # outside _adapter, refactored |
||||
fore.py + rear.py # visible outside _adapter, refactored |
||||
_low # new '_low' |
||||
_c # new '_c' |
||||
""" |
||||
|
||||
import collections |
||||
import enum |
||||
|
||||
from grpc._adapter import _low |
||||
from grpc._adapter import _types |
||||
|
||||
_IGNORE_ME_TAG = object() |
||||
Code = _types.StatusCode |
||||
|
||||
|
||||
class Status(collections.namedtuple('Status', ['code', 'details'])): |
||||
"""Describes an RPC's overall status.""" |
||||
|
||||
|
||||
class ServiceAcceptance( |
||||
collections.namedtuple( |
||||
'ServiceAcceptance', ['call', 'method', 'host', 'deadline'])): |
||||
"""Describes an RPC on the service side at the start of service.""" |
||||
|
||||
|
||||
class Event( |
||||
collections.namedtuple( |
||||
'Event', |
||||
['kind', 'tag', 'write_accepted', 'complete_accepted', |
||||
'service_acceptance', 'bytes', 'status', 'metadata'])): |
||||
"""Describes an event emitted from a completion queue.""" |
||||
|
||||
@enum.unique |
||||
class Kind(enum.Enum): |
||||
"""Describes the kind of an event.""" |
||||
|
||||
STOP = object() |
||||
WRITE_ACCEPTED = object() |
||||
COMPLETE_ACCEPTED = object() |
||||
SERVICE_ACCEPTED = object() |
||||
READ_ACCEPTED = object() |
||||
METADATA_ACCEPTED = object() |
||||
FINISH = object() |
||||
|
||||
|
||||
class _TagAdapter(collections.namedtuple('_TagAdapter', [ |
||||
'user_tag', |
||||
'kind' |
||||
])): |
||||
pass |
||||
|
||||
|
||||
class Call(object): |
||||
"""Adapter from old _low.Call interface to new _low.Call.""" |
||||
|
||||
def __init__(self, channel, completion_queue, method, host, deadline): |
||||
self._internal = channel._internal.create_call( |
||||
completion_queue._internal, method, host, deadline) |
||||
self._metadata = [] |
||||
|
||||
@staticmethod |
||||
def _from_internal(internal): |
||||
call = Call.__new__(Call) |
||||
call._internal = internal |
||||
call._metadata = [] |
||||
return call |
||||
|
||||
def invoke(self, completion_queue, metadata_tag, finish_tag): |
||||
err0 = self._internal.start_batch([ |
||||
_types.OpArgs.send_initial_metadata(self._metadata) |
||||
], _IGNORE_ME_TAG) |
||||
err1 = self._internal.start_batch([ |
||||
_types.OpArgs.recv_initial_metadata() |
||||
], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED)) |
||||
err2 = self._internal.start_batch([ |
||||
_types.OpArgs.recv_status_on_client() |
||||
], _TagAdapter(finish_tag, Event.Kind.FINISH)) |
||||
return err0 if err0 != _types.CallError.OK else err1 if err1 != _types.CallError.OK else err2 if err2 != _types.CallError.OK else _types.CallError.OK |
||||
|
||||
def write(self, message, tag): |
||||
return self._internal.start_batch([ |
||||
_types.OpArgs.send_message(message) |
||||
], _TagAdapter(tag, Event.Kind.WRITE_ACCEPTED)) |
||||
|
||||
def complete(self, tag): |
||||
return self._internal.start_batch([ |
||||
_types.OpArgs.send_close_from_client() |
||||
], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED)) |
||||
|
||||
def accept(self, completion_queue, tag): |
||||
return self._internal.start_batch([ |
||||
_types.OpArgs.recv_close_on_server() |
||||
], _TagAdapter(tag, Event.Kind.FINISH)) |
||||
|
||||
def add_metadata(self, key, value): |
||||
self._metadata.append((key, value)) |
||||
|
||||
def premetadata(self): |
||||
return self._internal.start_batch([ |
||||
_types.OpArgs.send_initial_metadata(self._metadata) |
||||
], _IGNORE_ME_TAG) |
||||
self._metadata = [] |
||||
|
||||
def read(self, tag): |
||||
return self._internal.start_batch([ |
||||
_types.OpArgs.recv_message() |
||||
], _TagAdapter(tag, Event.Kind.READ_ACCEPTED)) |
||||
|
||||
def status(self, status, tag): |
||||
return self._internal.start_batch([ |
||||
_types.OpArgs.send_status_from_server(self._metadata, status.code, status.details) |
||||
], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED)) |
||||
|
||||
def cancel(self): |
||||
return self._internal.cancel() |
||||
|
||||
|
||||
class Channel(object): |
||||
"""Adapter from old _low.Channel interface to new _low.Channel.""" |
||||
|
||||
def __init__(self, hostport, client_credentials, server_host_override=None): |
||||
args = [] |
||||
if server_host_override: |
||||
args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override)) |
||||
creds = None |
||||
if client_credentials: |
||||
creds = client_credentials._internal |
||||
self._internal = _low.Channel(hostport, args, creds) |
||||
|
||||
|
||||
class CompletionQueue(object): |
||||
"""Adapter from old _low.CompletionQueue interface to new _low.CompletionQueue.""" |
||||
|
||||
def __init__(self): |
||||
self._internal = _low.CompletionQueue() |
||||
|
||||
def get(self, deadline=None): |
||||
if deadline is None: |
||||
ev = self._internal.next() |
||||
else: |
||||
ev = self._internal.next(deadline) |
||||
if ev is None: |
||||
return None |
||||
elif ev.tag is _IGNORE_ME_TAG: |
||||
return self.get(deadline) |
||||
elif ev.type == _types.EventType.QUEUE_SHUTDOWN: |
||||
kind = Event.Kind.STOP |
||||
tag = None |
||||
write_accepted = None |
||||
complete_accepted = None |
||||
service_acceptance = None |
||||
message_bytes = None |
||||
status = None |
||||
metadata = None |
||||
elif ev.type == _types.EventType.OP_COMPLETE: |
||||
kind = ev.tag.kind |
||||
tag = ev.tag.user_tag |
||||
write_accepted = ev.success if kind == Event.Kind.WRITE_ACCEPTED else None |
||||
complete_accepted = ev.success if kind == Event.Kind.COMPLETE_ACCEPTED else None |
||||
service_acceptance = ServiceAcceptance(Call._from_internal(ev.call), ev.call_details.method, ev.call_details.host, ev.call_details.deadline) if kind == Event.Kind.SERVICE_ACCEPTED else None |
||||
message_bytes = ev.results[0].message if kind == Event.Kind.READ_ACCEPTED else None |
||||
status = Status(ev.results[0].status.code, ev.results[0].status.details) if (kind == Event.Kind.FINISH and ev.results[0].status) else Status(_types.StatusCode.CANCELLED if ev.results[0].cancelled else _types.StatusCode.OK, '') if ev.results[0].cancelled is not None else None |
||||
metadata = ev.results[0].initial_metadata if (kind in [Event.Kind.SERVICE_ACCEPTED, Event.Kind.METADATA_ACCEPTED]) else (ev.results[0].trailing_metadata if kind == Event.Kind.FINISH else None) |
||||
else: |
||||
raise RuntimeError('unknown event') |
||||
result_ev = Event(kind=kind, tag=tag, write_accepted=write_accepted, complete_accepted=complete_accepted, service_acceptance=service_acceptance, bytes=message_bytes, status=status, metadata=metadata) |
||||
return result_ev |
||||
|
||||
def stop(self): |
||||
self._internal.shutdown() |
||||
|
||||
|
||||
class Server(object): |
||||
"""Adapter from old _low.Server interface to new _low.Server.""" |
||||
|
||||
def __init__(self, completion_queue): |
||||
self._internal = _low.Server(completion_queue._internal, []) |
||||
self._internal_cq = completion_queue._internal |
||||
|
||||
def add_http2_addr(self, addr): |
||||
return self._internal.add_http2_port(addr) |
||||
|
||||
def add_secure_http2_addr(self, addr, server_credentials): |
||||
if server_credentials is None: |
||||
return self._internal.add_http2_port(addr, None) |
||||
else: |
||||
return self._internal.add_http2_port(addr, server_credentials._internal) |
||||
|
||||
def start(self): |
||||
return self._internal.start() |
||||
|
||||
def service(self, tag): |
||||
return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED)) |
||||
|
||||
def stop(self): |
||||
return self._internal.shutdown() |
||||
|
||||
|
||||
class ClientCredentials(object): |
||||
"""Adapter from old _low.ClientCredentials interface to new _low.ClientCredentials.""" |
||||
|
||||
def __init__(self, root_certificates, private_key, certificate_chain): |
||||
self._internal = _low.ClientCredentials.ssl(root_certificates, private_key, certificate_chain) |
||||
|
||||
|
||||
class ServerCredentials(object): |
||||
"""Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials.""" |
||||
|
||||
def __init__(self, root_credentials, pair_sequence): |
||||
self._internal = _low.ServerCredentials.ssl(root_credentials, list(pair_sequence)) |
@ -0,0 +1,421 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
"""Tests for the old '_low'.""" |
||||
|
||||
import time |
||||
import unittest |
||||
|
||||
from grpc._adapter import _intermediary_low as _low |
||||
|
||||
_STREAM_LENGTH = 300 |
||||
_TIMEOUT = 5 |
||||
_AFTER_DELAY = 2 |
||||
_FUTURE = time.time() + 60 * 60 * 24 |
||||
_BYTE_SEQUENCE = b'\abcdefghijklmnopqrstuvwxyz0123456789' * 200 |
||||
_BYTE_SEQUENCE_SEQUENCE = tuple( |
||||
bytes(bytearray((row + column) % 256 for column in range(row))) |
||||
for row in range(_STREAM_LENGTH)) |
||||
|
||||
class LonelyClientTest(unittest.TestCase): |
||||
|
||||
def testLonelyClient(self): |
||||
host = 'nosuchhostexists' |
||||
port = 54321 |
||||
method = 'test method' |
||||
deadline = time.time() + _TIMEOUT |
||||
after_deadline = deadline + _AFTER_DELAY |
||||
metadata_tag = object() |
||||
finish_tag = object() |
||||
|
||||
completion_queue = _low.CompletionQueue() |
||||
channel = _low.Channel('%s:%d' % (host, port), None) |
||||
client_call = _low.Call(channel, completion_queue, method, host, deadline) |
||||
|
||||
client_call.invoke(completion_queue, metadata_tag, finish_tag) |
||||
first_event = completion_queue.get(after_deadline) |
||||
self.assertIsNotNone(first_event) |
||||
second_event = completion_queue.get(after_deadline) |
||||
self.assertIsNotNone(second_event) |
||||
kinds = [event.kind for event in (first_event, second_event)] |
||||
self.assertItemsEqual( |
||||
(_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH), |
||||
kinds) |
||||
|
||||
self.assertIsNone(completion_queue.get(after_deadline)) |
||||
|
||||
completion_queue.stop() |
||||
stop_event = completion_queue.get(_FUTURE) |
||||
self.assertEqual(_low.Event.Kind.STOP, stop_event.kind) |
||||
|
||||
del client_call |
||||
del channel |
||||
del completion_queue |
||||
|
||||
|
||||
class EchoTest(unittest.TestCase): |
||||
|
||||
def setUp(self): |
||||
self.host = 'localhost' |
||||
|
||||
self.server_completion_queue = _low.CompletionQueue() |
||||
self.server = _low.Server(self.server_completion_queue) |
||||
port = self.server.add_http2_addr('[::]:0') |
||||
self.server.start() |
||||
|
||||
self.client_completion_queue = _low.CompletionQueue() |
||||
self.channel = _low.Channel('%s:%d' % (self.host, port), None) |
||||
|
||||
def tearDown(self): |
||||
self.server.stop() |
||||
# NOTE(nathaniel): Yep, this is weird; it's a consequence of |
||||
# grpc_server_destroy's being what has the effect of telling the server's |
||||
# completion queue to pump out all pending events/tags immediately rather |
||||
# than gracefully completing all outstanding RPCs while accepting no new |
||||
# ones. |
||||
# TODO(nathaniel): Deallocation of a Python object shouldn't have this kind |
||||
# of observable side effect let alone such an important one. |
||||
del self.server |
||||
self.server_completion_queue.stop() |
||||
self.client_completion_queue.stop() |
||||
while True: |
||||
event = self.server_completion_queue.get(_FUTURE) |
||||
if event is not None and event.kind is _low.Event.Kind.STOP: |
||||
break |
||||
while True: |
||||
event = self.client_completion_queue.get(_FUTURE) |
||||
if event is not None and event.kind is _low.Event.Kind.STOP: |
||||
break |
||||
self.server_completion_queue = None |
||||
self.client_completion_queue = None |
||||
|
||||
def _perform_echo_test(self, test_data): |
||||
method = 'test method' |
||||
details = 'test details' |
||||
server_leading_metadata_key = 'my_server_leading_key' |
||||
server_leading_metadata_value = 'my_server_leading_value' |
||||
server_trailing_metadata_key = 'my_server_trailing_key' |
||||
server_trailing_metadata_value = 'my_server_trailing_value' |
||||
client_metadata_key = 'my_client_key' |
||||
client_metadata_value = 'my_client_value' |
||||
server_leading_binary_metadata_key = 'my_server_leading_key-bin' |
||||
server_leading_binary_metadata_value = b'\0'*2047 |
||||
server_trailing_binary_metadata_key = 'my_server_trailing_key-bin' |
||||
server_trailing_binary_metadata_value = b'\0'*2047 |
||||
client_binary_metadata_key = 'my_client_key-bin' |
||||
client_binary_metadata_value = b'\0'*2047 |
||||
deadline = _FUTURE |
||||
metadata_tag = object() |
||||
finish_tag = object() |
||||
write_tag = object() |
||||
complete_tag = object() |
||||
service_tag = object() |
||||
read_tag = object() |
||||
status_tag = object() |
||||
|
||||
server_data = [] |
||||
client_data = [] |
||||
|
||||
client_call = _low.Call(self.channel, self.client_completion_queue, |
||||
method, self.host, deadline) |
||||
client_call.add_metadata(client_metadata_key, client_metadata_value) |
||||
client_call.add_metadata(client_binary_metadata_key, |
||||
client_binary_metadata_value) |
||||
|
||||
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag) |
||||
|
||||
self.server.service(service_tag) |
||||
service_accepted = self.server_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(service_accepted) |
||||
self.assertIs(service_accepted.kind, _low.Event.Kind.SERVICE_ACCEPTED) |
||||
self.assertIs(service_accepted.tag, service_tag) |
||||
self.assertEqual(method, service_accepted.service_acceptance.method) |
||||
self.assertEqual(self.host, service_accepted.service_acceptance.host) |
||||
self.assertIsNotNone(service_accepted.service_acceptance.call) |
||||
metadata = dict(service_accepted.metadata) |
||||
self.assertIn(client_metadata_key, metadata) |
||||
self.assertEqual(client_metadata_value, metadata[client_metadata_key]) |
||||
self.assertIn(client_binary_metadata_key, metadata) |
||||
self.assertEqual(client_binary_metadata_value, |
||||
metadata[client_binary_metadata_key]) |
||||
server_call = service_accepted.service_acceptance.call |
||||
server_call.accept(self.server_completion_queue, finish_tag) |
||||
server_call.add_metadata(server_leading_metadata_key, |
||||
server_leading_metadata_value) |
||||
server_call.add_metadata(server_leading_binary_metadata_key, |
||||
server_leading_binary_metadata_value) |
||||
server_call.premetadata() |
||||
|
||||
metadata_accepted = self.client_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(metadata_accepted) |
||||
self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind) |
||||
self.assertEqual(metadata_tag, metadata_accepted.tag) |
||||
metadata = dict(metadata_accepted.metadata) |
||||
self.assertIn(server_leading_metadata_key, metadata) |
||||
self.assertEqual(server_leading_metadata_value, |
||||
metadata[server_leading_metadata_key]) |
||||
self.assertIn(server_leading_binary_metadata_key, metadata) |
||||
self.assertEqual(server_leading_binary_metadata_value, |
||||
metadata[server_leading_binary_metadata_key]) |
||||
|
||||
for datum in test_data: |
||||
client_call.write(datum, write_tag) |
||||
write_accepted = self.client_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(write_accepted) |
||||
self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED) |
||||
self.assertIs(write_accepted.tag, write_tag) |
||||
self.assertIs(write_accepted.write_accepted, True) |
||||
|
||||
server_call.read(read_tag) |
||||
read_accepted = self.server_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(read_accepted) |
||||
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) |
||||
self.assertEqual(read_tag, read_accepted.tag) |
||||
self.assertIsNotNone(read_accepted.bytes) |
||||
server_data.append(read_accepted.bytes) |
||||
|
||||
server_call.write(read_accepted.bytes, write_tag) |
||||
write_accepted = self.server_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(write_accepted) |
||||
self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind) |
||||
self.assertEqual(write_tag, write_accepted.tag) |
||||
self.assertTrue(write_accepted.write_accepted) |
||||
|
||||
client_call.read(read_tag) |
||||
read_accepted = self.client_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(read_accepted) |
||||
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) |
||||
self.assertEqual(read_tag, read_accepted.tag) |
||||
self.assertIsNotNone(read_accepted.bytes) |
||||
client_data.append(read_accepted.bytes) |
||||
|
||||
client_call.complete(complete_tag) |
||||
complete_accepted = self.client_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(complete_accepted) |
||||
self.assertIs(complete_accepted.kind, _low.Event.Kind.COMPLETE_ACCEPTED) |
||||
self.assertIs(complete_accepted.tag, complete_tag) |
||||
self.assertIs(complete_accepted.complete_accepted, True) |
||||
|
||||
server_call.read(read_tag) |
||||
read_accepted = self.server_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(read_accepted) |
||||
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) |
||||
self.assertEqual(read_tag, read_accepted.tag) |
||||
self.assertIsNone(read_accepted.bytes) |
||||
|
||||
server_call.add_metadata(server_trailing_metadata_key, |
||||
server_trailing_metadata_value) |
||||
server_call.add_metadata(server_trailing_binary_metadata_key, |
||||
server_trailing_binary_metadata_value) |
||||
|
||||
server_call.status(_low.Status(_low.Code.OK, details), status_tag) |
||||
server_terminal_event_one = self.server_completion_queue.get(_FUTURE) |
||||
server_terminal_event_two = self.server_completion_queue.get(_FUTURE) |
||||
if server_terminal_event_one.kind == _low.Event.Kind.COMPLETE_ACCEPTED: |
||||
status_accepted = server_terminal_event_one |
||||
rpc_accepted = server_terminal_event_two |
||||
else: |
||||
status_accepted = server_terminal_event_two |
||||
rpc_accepted = server_terminal_event_one |
||||
self.assertIsNotNone(status_accepted) |
||||
self.assertIsNotNone(rpc_accepted) |
||||
self.assertEqual(_low.Event.Kind.COMPLETE_ACCEPTED, status_accepted.kind) |
||||
self.assertEqual(status_tag, status_accepted.tag) |
||||
self.assertTrue(status_accepted.complete_accepted) |
||||
self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind) |
||||
self.assertEqual(finish_tag, rpc_accepted.tag) |
||||
self.assertEqual(_low.Status(_low.Code.OK, ''), rpc_accepted.status) |
||||
|
||||
client_call.read(read_tag) |
||||
client_terminal_event_one = self.client_completion_queue.get(_FUTURE) |
||||
client_terminal_event_two = self.client_completion_queue.get(_FUTURE) |
||||
if client_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED: |
||||
read_accepted = client_terminal_event_one |
||||
finish_accepted = client_terminal_event_two |
||||
else: |
||||
read_accepted = client_terminal_event_two |
||||
finish_accepted = client_terminal_event_one |
||||
self.assertIsNotNone(read_accepted) |
||||
self.assertIsNotNone(finish_accepted) |
||||
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) |
||||
self.assertEqual(read_tag, read_accepted.tag) |
||||
self.assertIsNone(read_accepted.bytes) |
||||
self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind) |
||||
self.assertEqual(finish_tag, finish_accepted.tag) |
||||
self.assertEqual(_low.Status(_low.Code.OK, details), finish_accepted.status) |
||||
metadata = dict(finish_accepted.metadata) |
||||
self.assertIn(server_trailing_metadata_key, metadata) |
||||
self.assertEqual(server_trailing_metadata_value, |
||||
metadata[server_trailing_metadata_key]) |
||||
self.assertIn(server_trailing_binary_metadata_key, metadata) |
||||
self.assertEqual(server_trailing_binary_metadata_value, |
||||
metadata[server_trailing_binary_metadata_key]) |
||||
|
||||
server_timeout_none_event = self.server_completion_queue.get(0) |
||||
self.assertIsNone(server_timeout_none_event) |
||||
client_timeout_none_event = self.client_completion_queue.get(0) |
||||
self.assertIsNone(client_timeout_none_event) |
||||
|
||||
self.assertSequenceEqual(test_data, server_data) |
||||
self.assertSequenceEqual(test_data, client_data) |
||||
|
||||
def testNoEcho(self): |
||||
self._perform_echo_test(()) |
||||
|
||||
def testOneByteEcho(self): |
||||
self._perform_echo_test([b'\x07']) |
||||
|
||||
def testOneManyByteEcho(self): |
||||
self._perform_echo_test([_BYTE_SEQUENCE]) |
||||
|
||||
def testManyOneByteEchoes(self): |
||||
self._perform_echo_test(_BYTE_SEQUENCE) |
||||
|
||||
def testManyManyByteEchoes(self): |
||||
self._perform_echo_test(_BYTE_SEQUENCE_SEQUENCE) |
||||
|
||||
|
||||
class CancellationTest(unittest.TestCase): |
||||
|
||||
def setUp(self): |
||||
self.host = 'localhost' |
||||
|
||||
self.server_completion_queue = _low.CompletionQueue() |
||||
self.server = _low.Server(self.server_completion_queue) |
||||
port = self.server.add_http2_addr('[::]:0') |
||||
self.server.start() |
||||
|
||||
self.client_completion_queue = _low.CompletionQueue() |
||||
self.channel = _low.Channel('%s:%d' % (self.host, port), None) |
||||
|
||||
def tearDown(self): |
||||
self.server.stop() |
||||
del self.server |
||||
self.server_completion_queue.stop() |
||||
self.client_completion_queue.stop() |
||||
while True: |
||||
event = self.server_completion_queue.get(0) |
||||
if event is not None and event.kind is _low.Event.Kind.STOP: |
||||
break |
||||
while True: |
||||
event = self.client_completion_queue.get(0) |
||||
if event is not None and event.kind is _low.Event.Kind.STOP: |
||||
break |
||||
|
||||
def testCancellation(self): |
||||
method = 'test method' |
||||
deadline = _FUTURE |
||||
metadata_tag = object() |
||||
finish_tag = object() |
||||
write_tag = object() |
||||
service_tag = object() |
||||
read_tag = object() |
||||
test_data = _BYTE_SEQUENCE_SEQUENCE |
||||
|
||||
server_data = [] |
||||
client_data = [] |
||||
|
||||
client_call = _low.Call(self.channel, self.client_completion_queue, |
||||
method, self.host, deadline) |
||||
|
||||
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag) |
||||
|
||||
self.server.service(service_tag) |
||||
service_accepted = self.server_completion_queue.get(_FUTURE) |
||||
server_call = service_accepted.service_acceptance.call |
||||
|
||||
server_call.accept(self.server_completion_queue, finish_tag) |
||||
server_call.premetadata() |
||||
|
||||
metadata_accepted = self.client_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(metadata_accepted) |
||||
|
||||
for datum in test_data: |
||||
client_call.write(datum, write_tag) |
||||
write_accepted = self.client_completion_queue.get(_FUTURE) |
||||
|
||||
server_call.read(read_tag) |
||||
read_accepted = self.server_completion_queue.get(_FUTURE) |
||||
server_data.append(read_accepted.bytes) |
||||
|
||||
server_call.write(read_accepted.bytes, write_tag) |
||||
write_accepted = self.server_completion_queue.get(_FUTURE) |
||||
self.assertIsNotNone(write_accepted) |
||||
|
||||
client_call.read(read_tag) |
||||
read_accepted = self.client_completion_queue.get(_FUTURE) |
||||
client_data.append(read_accepted.bytes) |
||||
|
||||
client_call.cancel() |
||||
# cancel() is idempotent. |
||||
client_call.cancel() |
||||
client_call.cancel() |
||||
client_call.cancel() |
||||
|
||||
server_call.read(read_tag) |
||||
|
||||
server_terminal_event_one = self.server_completion_queue.get(_FUTURE) |
||||
server_terminal_event_two = self.server_completion_queue.get(_FUTURE) |
||||
if server_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED: |
||||
read_accepted = server_terminal_event_one |
||||
rpc_accepted = server_terminal_event_two |
||||
else: |
||||
read_accepted = server_terminal_event_two |
||||
rpc_accepted = server_terminal_event_one |
||||
self.assertIsNotNone(read_accepted) |
||||
self.assertIsNotNone(rpc_accepted) |
||||
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) |
||||
self.assertIsNone(read_accepted.bytes) |
||||
self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind) |
||||
self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), rpc_accepted.status) |
||||
|
||||
finish_event = self.client_completion_queue.get(_FUTURE) |
||||
self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind) |
||||
self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'), |
||||
finish_event.status) |
||||
|
||||
server_timeout_none_event = self.server_completion_queue.get(0) |
||||
self.assertIsNone(server_timeout_none_event) |
||||
client_timeout_none_event = self.client_completion_queue.get(0) |
||||
self.assertIsNone(client_timeout_none_event) |
||||
|
||||
self.assertSequenceEqual(test_data, server_data) |
||||
self.assertSequenceEqual(test_data, client_data) |
||||
|
||||
|
||||
class ExpirationTest(unittest.TestCase): |
||||
|
||||
@unittest.skip('TODO(nathaniel): Expiration test!') |
||||
def testExpiration(self): |
||||
pass |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main(verbosity=2) |
||||
|
@ -1,202 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_server.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "grpc/_adapter/_call.h" |
||||
#include "grpc/_adapter/_completion_queue.h" |
||||
#include "grpc/_adapter/_error.h" |
||||
#include "grpc/_adapter/_server_credentials.h" |
||||
#include "grpc/_adapter/_tag.h" |
||||
|
||||
static int pygrpc_server_init(Server *self, PyObject *args, PyObject *kwds) { |
||||
CompletionQueue *completion_queue; |
||||
static char *kwlist[] = {"completion_queue", NULL}; |
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!:Server", kwlist, |
||||
&pygrpc_CompletionQueueType, |
||||
&completion_queue)) { |
||||
return -1; |
||||
} |
||||
self->c_server = grpc_server_create(NULL); |
||||
grpc_server_register_completion_queue(self->c_server, |
||||
completion_queue->c_completion_queue); |
||||
self->completion_queue = completion_queue; |
||||
Py_INCREF(completion_queue); |
||||
return 0; |
||||
} |
||||
|
||||
static void pygrpc_server_dealloc(Server *self) { |
||||
if (self->c_server != NULL) { |
||||
grpc_server_destroy(self->c_server); |
||||
} |
||||
Py_XDECREF(self->completion_queue); |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
static PyObject *pygrpc_server_add_http2_addr(Server *self, PyObject *args) { |
||||
const char *addr; |
||||
int port; |
||||
if (!PyArg_ParseTuple(args, "s:add_http2_addr", &addr)) { |
||||
return NULL; |
||||
} |
||||
|
||||
port = grpc_server_add_http2_port(self->c_server, addr); |
||||
if (port == 0) { |
||||
PyErr_SetString(PyExc_RuntimeError, "Couldn't add port to server!"); |
||||
return NULL; |
||||
} |
||||
|
||||
return PyInt_FromLong(port); |
||||
} |
||||
|
||||
static PyObject *pygrpc_server_add_secure_http2_addr(Server *self, |
||||
PyObject *args, |
||||
PyObject *kwargs) { |
||||
const char *addr; |
||||
PyObject *server_credentials; |
||||
static char *kwlist[] = {"addr", "server_credentials", NULL}; |
||||
int port; |
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!:add_secure_http2_addr", |
||||
kwlist, &addr, &pygrpc_ServerCredentialsType, |
||||
&server_credentials)) { |
||||
return NULL; |
||||
} |
||||
port = grpc_server_add_secure_http2_port( |
||||
self->c_server, addr, |
||||
((ServerCredentials *)server_credentials)->c_server_credentials); |
||||
if (port == 0) { |
||||
PyErr_SetString(PyExc_RuntimeError, "Couldn't add port to server!"); |
||||
return NULL; |
||||
} |
||||
return PyInt_FromLong(port); |
||||
} |
||||
|
||||
static PyObject *pygrpc_server_start(Server *self) { |
||||
grpc_server_start(self->c_server); |
||||
|
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
static const PyObject *pygrpc_server_service(Server *self, PyObject *tag) { |
||||
grpc_call_error call_error; |
||||
const PyObject *result; |
||||
pygrpc_tag *c_tag = pygrpc_tag_new_server_rpc_call(tag); |
||||
c_tag->call->completion_queue = self->completion_queue; |
||||
c_tag->call->server = self; |
||||
Py_INCREF(c_tag->call->completion_queue); |
||||
Py_INCREF(c_tag->call->server); |
||||
call_error = grpc_server_request_call( |
||||
self->c_server, &c_tag->call->c_call, &c_tag->call->call_details, |
||||
&c_tag->call->recv_metadata, self->completion_queue->c_completion_queue, |
||||
self->completion_queue->c_completion_queue, c_tag); |
||||
|
||||
result = pygrpc_translate_call_error(call_error); |
||||
if (result != NULL) { |
||||
Py_INCREF(tag); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static PyObject *pygrpc_server_stop(Server *self) { |
||||
grpc_server_shutdown(self->c_server); |
||||
|
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
static PyMethodDef methods[] = { |
||||
{"add_http2_addr", (PyCFunction)pygrpc_server_add_http2_addr, METH_VARARGS, |
||||
"Add an HTTP2 address."}, |
||||
{"add_secure_http2_addr", (PyCFunction)pygrpc_server_add_secure_http2_addr, |
||||
METH_VARARGS, "Add a secure HTTP2 address."}, |
||||
{"start", (PyCFunction)pygrpc_server_start, METH_NOARGS, |
||||
"Starts the server."}, |
||||
{"service", (PyCFunction)pygrpc_server_service, METH_O, "Services a call."}, |
||||
{"stop", (PyCFunction)pygrpc_server_stop, METH_NOARGS, "Stops the server."}, |
||||
{NULL}}; |
||||
|
||||
static PyTypeObject pygrpc_ServerType = { |
||||
PyVarObject_HEAD_INIT(NULL, 0) |
||||
"_gprc.Server", /*tp_name*/ |
||||
sizeof(Server), /*tp_basicsize*/ |
||||
0, /*tp_itemsize*/ |
||||
(destructor)pygrpc_server_dealloc, /*tp_dealloc*/ |
||||
0, /*tp_print*/ |
||||
0, /*tp_getattr*/ |
||||
0, /*tp_setattr*/ |
||||
0, /*tp_compare*/ |
||||
0, /*tp_repr*/ |
||||
0, /*tp_as_number*/ |
||||
0, /*tp_as_sequence*/ |
||||
0, /*tp_as_mapping*/ |
||||
0, /*tp_hash */ |
||||
0, /*tp_call*/ |
||||
0, /*tp_str*/ |
||||
0, /*tp_getattro*/ |
||||
0, /*tp_setattro*/ |
||||
0, /*tp_as_buffer*/ |
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
||||
"Wrapping of grpc_server.", /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
methods, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
(initproc)pygrpc_server_init, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
PyType_GenericNew, /* tp_new */ |
||||
}; |
||||
|
||||
int pygrpc_add_server(PyObject *module) { |
||||
if (PyType_Ready(&pygrpc_ServerType) < 0) { |
||||
return -1; |
||||
} |
||||
if (PyModule_AddObject(module, "Server", (PyObject *)&pygrpc_ServerType) == |
||||
-1) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
@ -1,152 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_server_credentials.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc_security.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
static int pygrpc_server_credentials_init(ServerCredentials *self, |
||||
PyObject *args, PyObject *kwds) { |
||||
char *root_certificates; |
||||
PyObject *pair_sequence; |
||||
Py_ssize_t pair_count; |
||||
grpc_ssl_pem_key_cert_pair *pairs; |
||||
int error; |
||||
PyObject *iterator; |
||||
int i; |
||||
PyObject *pair; |
||||
static char *kwlist[] = {"root_credentials", "pair_sequence", NULL}; |
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "zO:ServerCredentials", kwlist, |
||||
&root_certificates, &pair_sequence)) { |
||||
return -1; |
||||
} |
||||
|
||||
pair_count = PySequence_Length(pair_sequence); |
||||
if (pair_count == -1) { |
||||
return -1; |
||||
} |
||||
|
||||
iterator = PyObject_GetIter(pair_sequence); |
||||
if (iterator == NULL) { |
||||
return -1; |
||||
} |
||||
pairs = gpr_malloc(pair_count * sizeof(grpc_ssl_pem_key_cert_pair)); |
||||
error = 0; |
||||
for (i = 0; i < pair_count; i++) { |
||||
pair = PyIter_Next(iterator); |
||||
if (pair == NULL) { |
||||
error = 1; |
||||
break; |
||||
} |
||||
if (!PyArg_ParseTuple(pair, "ss", &pairs[i].private_key, |
||||
&pairs[i].cert_chain)) { |
||||
error = 1; |
||||
Py_DECREF(pair); |
||||
break; |
||||
} |
||||
Py_DECREF(pair); |
||||
} |
||||
Py_DECREF(iterator); |
||||
|
||||
if (error) { |
||||
gpr_free(pairs); |
||||
return -1; |
||||
} else { |
||||
self->c_server_credentials = grpc_ssl_server_credentials_create( |
||||
root_certificates, pairs, pair_count); |
||||
gpr_free(pairs); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
static void pygrpc_server_credentials_dealloc(ServerCredentials *self) { |
||||
if (self->c_server_credentials != NULL) { |
||||
grpc_server_credentials_release(self->c_server_credentials); |
||||
} |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
PyTypeObject pygrpc_ServerCredentialsType = { |
||||
PyVarObject_HEAD_INIT(NULL, 0) |
||||
"_grpc.ServerCredencials", /*tp_name*/ |
||||
sizeof(ServerCredentials), /*tp_basicsize*/ |
||||
0, /*tp_itemsize*/ |
||||
(destructor)pygrpc_server_credentials_dealloc, /*tp_dealloc*/ |
||||
0, /*tp_print*/ |
||||
0, /*tp_getattr*/ |
||||
0, /*tp_setattr*/ |
||||
0, /*tp_compare*/ |
||||
0, /*tp_repr*/ |
||||
0, /*tp_as_number*/ |
||||
0, /*tp_as_sequence*/ |
||||
0, /*tp_as_mapping*/ |
||||
0, /*tp_hash */ |
||||
0, /*tp_call*/ |
||||
0, /*tp_str*/ |
||||
0, /*tp_getattro*/ |
||||
0, /*tp_setattro*/ |
||||
0, /*tp_as_buffer*/ |
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
||||
"Wrapping of grpc_server_credentials.", /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
0, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
(initproc)pygrpc_server_credentials_init, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
PyType_GenericNew, /* tp_new */ |
||||
}; |
||||
|
||||
int pygrpc_add_server_credentials(PyObject *module) { |
||||
if (PyType_Ready(&pygrpc_ServerCredentialsType) < 0) { |
||||
return -1; |
||||
} |
||||
if (PyModule_AddObject(module, "ServerCredentials", |
||||
(PyObject *)&pygrpc_ServerCredentialsType) == -1) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
@ -1,49 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _ADAPTER__SERVER_CREDENTIALS_H_ |
||||
#define _ADAPTER__SERVER_CREDENTIALS_H_ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc_security.h> |
||||
|
||||
typedef struct { |
||||
PyObject_HEAD |
||||
grpc_server_credentials *c_server_credentials; |
||||
} ServerCredentials; |
||||
|
||||
extern PyTypeObject pygrpc_ServerCredentialsType; |
||||
|
||||
int pygrpc_add_server_credentials(PyObject *module); |
||||
|
||||
#endif /* _ADAPTER__SERVER_CREDENTIALS_H_ */ |
@ -1,65 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_tag.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
pygrpc_tag *pygrpc_tag_new(pygrpc_tag_type type, PyObject *user_tag, |
||||
Call *call) { |
||||
pygrpc_tag *self = (pygrpc_tag *)gpr_malloc(sizeof(pygrpc_tag)); |
||||
memset(self, 0, sizeof(pygrpc_tag)); |
||||
if (user_tag == NULL) { |
||||
self->user_tag = Py_None; |
||||
} else { |
||||
self->user_tag = user_tag; |
||||
} |
||||
Py_INCREF(self->user_tag); |
||||
self->type = type; |
||||
self->call = call; |
||||
Py_INCREF(call); |
||||
return self; |
||||
} |
||||
|
||||
pygrpc_tag *pygrpc_tag_new_server_rpc_call(PyObject *user_tag) { |
||||
return pygrpc_tag_new(PYGRPC_SERVER_RPC_NEW, user_tag, |
||||
(Call *)pygrpc_CallType.tp_alloc(&pygrpc_CallType, 0)); |
||||
} |
||||
|
||||
void pygrpc_tag_destroy(pygrpc_tag *self) { |
||||
Py_XDECREF(self->user_tag); |
||||
Py_XDECREF(self->call); |
||||
gpr_free(self); |
||||
} |
@ -1,70 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _ADAPTER__TAG_H_ |
||||
#define _ADAPTER__TAG_H_ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "grpc/_adapter/_call.h" |
||||
#include "grpc/_adapter/_completion_queue.h" |
||||
|
||||
/* grpc_completion_type is becoming meaningless in grpc_event; this is a partial
|
||||
replacement for its descriptive functionality until Python can move its whole |
||||
C and C adapter stack to more closely resemble the core batching API. */ |
||||
typedef enum { |
||||
PYGRPC_SERVER_RPC_NEW = 0, |
||||
PYGRPC_INITIAL_METADATA = 1, |
||||
PYGRPC_READ = 2, |
||||
PYGRPC_WRITE_ACCEPTED = 3, |
||||
PYGRPC_FINISH_ACCEPTED = 4, |
||||
PYGRPC_CLIENT_METADATA_READ = 5, |
||||
PYGRPC_FINISHED_CLIENT = 6, |
||||
PYGRPC_FINISHED_SERVER = 7 |
||||
} pygrpc_tag_type; |
||||
|
||||
typedef struct { |
||||
pygrpc_tag_type type; |
||||
PyObject *user_tag; |
||||
|
||||
Call *call; |
||||
} pygrpc_tag; |
||||
|
||||
pygrpc_tag *pygrpc_tag_new(pygrpc_tag_type type, PyObject *user_tag, |
||||
Call *call); |
||||
pygrpc_tag *pygrpc_tag_new_server_rpc_call(PyObject *user_tag); |
||||
void pygrpc_tag_destroy(pygrpc_tag *self); |
||||
|
||||
#endif /* _ADAPTER__TAG_H_ */ |
||||
|
@ -0,0 +1,368 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
import abc |
||||
import collections |
||||
import enum |
||||
|
||||
# TODO(atash): decide whether or not to move these enums to the _c module to |
||||
# force build errors with upstream changes. |
||||
|
||||
class GrpcChannelArgumentKeys(enum.Enum): |
||||
"""Mirrors keys used in grpc_channel_args for GRPC-specific arguments.""" |
||||
SSL_TARGET_NAME_OVERRIDE = 'grpc.ssl_target_name_override' |
||||
|
||||
@enum.unique |
||||
class CallError(enum.IntEnum): |
||||
"""Mirrors grpc_call_error in the C core.""" |
||||
OK = 0 |
||||
ERROR = 1 |
||||
ERROR_NOT_ON_SERVER = 2 |
||||
ERROR_NOT_ON_CLIENT = 3 |
||||
ERROR_ALREADY_ACCEPTED = 4 |
||||
ERROR_ALREADY_INVOKED = 5 |
||||
ERROR_NOT_INVOKED = 6 |
||||
ERROR_ALREADY_FINISHED = 7 |
||||
ERROR_TOO_MANY_OPERATIONS = 8 |
||||
ERROR_INVALID_FLAGS = 9 |
||||
ERROR_INVALID_METADATA = 10 |
||||
|
||||
@enum.unique |
||||
class StatusCode(enum.IntEnum): |
||||
"""Mirrors grpc_status_code in the C core.""" |
||||
OK = 0 |
||||
CANCELLED = 1 |
||||
UNKNOWN = 2 |
||||
INVALID_ARGUMENT = 3 |
||||
DEADLINE_EXCEEDED = 4 |
||||
NOT_FOUND = 5 |
||||
ALREADY_EXISTS = 6 |
||||
PERMISSION_DENIED = 7 |
||||
RESOURCE_EXHAUSTED = 8 |
||||
FAILED_PRECONDITION = 9 |
||||
ABORTED = 10 |
||||
OUT_OF_RANGE = 11 |
||||
UNIMPLEMENTED = 12 |
||||
INTERNAL = 13 |
||||
UNAVAILABLE = 14 |
||||
DATA_LOSS = 15 |
||||
UNAUTHENTICATED = 16 |
||||
|
||||
@enum.unique |
||||
class OpType(enum.IntEnum): |
||||
"""Mirrors grpc_op_type in the C core.""" |
||||
SEND_INITIAL_METADATA = 0 |
||||
SEND_MESSAGE = 1 |
||||
SEND_CLOSE_FROM_CLIENT = 2 |
||||
SEND_STATUS_FROM_SERVER = 3 |
||||
RECV_INITIAL_METADATA = 4 |
||||
RECV_MESSAGE = 5 |
||||
RECV_STATUS_ON_CLIENT = 6 |
||||
RECV_CLOSE_ON_SERVER = 7 |
||||
|
||||
@enum.unique |
||||
class EventType(enum.IntEnum): |
||||
"""Mirrors grpc_completion_type in the C core.""" |
||||
QUEUE_SHUTDOWN = 0 |
||||
QUEUE_TIMEOUT = 1 # if seen on the Python side, something went horridly wrong |
||||
OP_COMPLETE = 2 |
||||
|
||||
class Status(collections.namedtuple( |
||||
'Status', [ |
||||
'code', |
||||
'details', |
||||
])): |
||||
"""The end status of a GRPC call. |
||||
|
||||
Attributes: |
||||
code (StatusCode): ... |
||||
details (str): ... |
||||
""" |
||||
|
||||
class CallDetails(collections.namedtuple( |
||||
'CallDetails', [ |
||||
'method', |
||||
'host', |
||||
'deadline', |
||||
])): |
||||
"""Provides information to the server about the client's call. |
||||
|
||||
Attributes: |
||||
method (str): ... |
||||
host (str): ... |
||||
deadline (float): ... |
||||
""" |
||||
|
||||
class OpArgs(collections.namedtuple( |
||||
'OpArgs', [ |
||||
'type', |
||||
'initial_metadata', |
||||
'trailing_metadata', |
||||
'message', |
||||
'status', |
||||
])): |
||||
"""Arguments passed into a GRPC operation. |
||||
|
||||
Attributes: |
||||
type (OpType): ... |
||||
initial_metadata (sequence of 2-sequence of str): Only valid if type == |
||||
OpType.SEND_INITIAL_METADATA, else is None. |
||||
trailing_metadata (sequence of 2-sequence of str): Only valid if type == |
||||
OpType.SEND_STATUS_FROM_SERVER, else is None. |
||||
message (bytes): Only valid if type == OpType.SEND_MESSAGE, else is None. |
||||
status (Status): Only valid if type == OpType.SEND_STATUS_FROM_SERVER, else |
||||
is None. |
||||
""" |
||||
|
||||
@staticmethod |
||||
def send_initial_metadata(initial_metadata): |
||||
return OpArgs(OpType.SEND_INITIAL_METADATA, initial_metadata, None, None, None) |
||||
|
||||
@staticmethod |
||||
def send_message(message): |
||||
return OpArgs(OpType.SEND_MESSAGE, None, None, message, None) |
||||
|
||||
@staticmethod |
||||
def send_close_from_client(): |
||||
return OpArgs(OpType.SEND_CLOSE_FROM_CLIENT, None, None, None, None) |
||||
|
||||
@staticmethod |
||||
def send_status_from_server(trailing_metadata, status_code, status_details): |
||||
return OpArgs(OpType.SEND_STATUS_FROM_SERVER, None, trailing_metadata, None, Status(status_code, status_details)) |
||||
|
||||
@staticmethod |
||||
def recv_initial_metadata(): |
||||
return OpArgs(OpType.RECV_INITIAL_METADATA, None, None, None, None); |
||||
|
||||
@staticmethod |
||||
def recv_message(): |
||||
return OpArgs(OpType.RECV_MESSAGE, None, None, None, None) |
||||
|
||||
@staticmethod |
||||
def recv_status_on_client(): |
||||
return OpArgs(OpType.RECV_STATUS_ON_CLIENT, None, None, None, None) |
||||
|
||||
@staticmethod |
||||
def recv_close_on_server(): |
||||
return OpArgs(OpType.RECV_CLOSE_ON_SERVER, None, None, None, None) |
||||
|
||||
|
||||
class OpResult(collections.namedtuple( |
||||
'OpResult', [ |
||||
'type', |
||||
'initial_metadata', |
||||
'trailing_metadata', |
||||
'message', |
||||
'status', |
||||
'cancelled', |
||||
])): |
||||
"""Results received from a GRPC operation. |
||||
|
||||
Attributes: |
||||
type (OpType): ... |
||||
initial_metadata (sequence of 2-sequence of str): Only valid if type == |
||||
OpType.RECV_INITIAL_METADATA, else is None. |
||||
trailing_metadata (sequence of 2-sequence of str): Only valid if type == |
||||
OpType.RECV_STATUS_ON_CLIENT, else is None. |
||||
message (bytes): Only valid if type == OpType.RECV_MESSAGE, else is None. |
||||
status (Status): Only valid if type == OpType.RECV_STATUS_ON_CLIENT, else |
||||
is None. |
||||
cancelled (bool): Only valid if type == OpType.RECV_CLOSE_ON_SERVER, else |
||||
is None. |
||||
""" |
||||
|
||||
|
||||
class Event(collections.namedtuple( |
||||
'Event', [ |
||||
'type', |
||||
'tag', |
||||
'call', |
||||
'call_details', |
||||
'results', |
||||
'success', |
||||
])): |
||||
"""An event received from a GRPC completion queue. |
||||
|
||||
Attributes: |
||||
type (EventType): ... |
||||
tag (object): ... |
||||
call (Call): The Call object associated with this event (if there is one, |
||||
else None). |
||||
call_details (CallDetails): The call details associated with the |
||||
server-side call (if there is such information, else None). |
||||
results (list of OpResult): ... |
||||
success (bool): ... |
||||
""" |
||||
|
||||
|
||||
class CompletionQueue: |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
@abc.abstractmethod |
||||
def __init__(self): |
||||
pass |
||||
|
||||
def __iter__(self): |
||||
"""This class may be iterated over. |
||||
|
||||
This is the equivalent of calling next() repeatedly with an absolute |
||||
deadline of None (i.e. no deadline). |
||||
""" |
||||
return self |
||||
|
||||
@abc.abstractmethod |
||||
def next(self, deadline=float('+inf')): |
||||
"""Get the next event on this completion queue. |
||||
|
||||
Args: |
||||
deadline (float): absolute deadline in seconds from the Python epoch, or |
||||
None for no deadline. |
||||
|
||||
Returns: |
||||
Event: ... |
||||
""" |
||||
pass |
||||
|
||||
@abc.abstractmethod |
||||
def shutdown(self): |
||||
"""Begin the shutdown process of this completion queue. |
||||
|
||||
Note that this does not immediately destroy the completion queue. |
||||
Nevertheless, user code should not pass it around after invoking this. |
||||
""" |
||||
return None |
||||
|
||||
|
||||
class Call: |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
@abc.abstractmethod |
||||
def start_batch(self, ops, tag): |
||||
"""Start a batch of operations. |
||||
|
||||
Args: |
||||
ops (sequence of OpArgs): ... |
||||
tag (object): ... |
||||
|
||||
Returns: |
||||
CallError: ... |
||||
""" |
||||
return CallError.ERROR |
||||
|
||||
@abc.abstractmethod |
||||
def cancel(self, code=None, details=None): |
||||
"""Cancel the call. |
||||
|
||||
Args: |
||||
code (int): Status code to cancel with (on the server side). If |
||||
specified, so must `details`. |
||||
details (str): Status details to cancel with (on the server side). If |
||||
specified, so must `code`. |
||||
|
||||
Returns: |
||||
CallError: ... |
||||
""" |
||||
return CallError.ERROR |
||||
|
||||
|
||||
class Channel: |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
@abc.abstractmethod |
||||
def __init__(self, target, args, credentials=None): |
||||
"""Initialize a Channel. |
||||
|
||||
Args: |
||||
target (str): ... |
||||
args (sequence of 2-sequence of str, (str|integer)): ... |
||||
credentials (ClientCredentials): If None, create an insecure channel, |
||||
else create a secure channel using the client credentials. |
||||
""" |
||||
|
||||
@abc.abstractmethod |
||||
def create_call(self, completion_queue, method, host, deadline=float('+inf')): |
||||
"""Create a call from this channel. |
||||
|
||||
Args: |
||||
completion_queue (CompletionQueue): ... |
||||
method (str): ... |
||||
host (str): ... |
||||
deadline (float): absolute deadline in seconds from the Python epoch, or |
||||
None for no deadline. |
||||
|
||||
Returns: |
||||
Call: call object associated with this Channel and passed parameters. |
||||
""" |
||||
return None |
||||
|
||||
|
||||
class Server: |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
@abc.abstractmethod |
||||
def __init__(self, completion_queue, args): |
||||
"""Initialize a server. |
||||
|
||||
Args: |
||||
completion_queue (CompletionQueue): ... |
||||
args (sequence of 2-sequence of str, (str|integer)): ... |
||||
""" |
||||
|
||||
@abc.abstractmethod |
||||
def add_http2_port(self, address, credentials=None): |
||||
"""Adds an HTTP/2 address+port to the server. |
||||
|
||||
Args: |
||||
address (str): ... |
||||
credentials (ServerCredentials): If None, create an insecure port, else |
||||
create a secure port using the server credentials. |
||||
""" |
||||
|
||||
@abc.abstractmethod |
||||
def start(self): |
||||
"""Starts the server.""" |
||||
|
||||
@abc.abstractmethod |
||||
def shutdown(self, tag=None): |
||||
"""Shuts down the server. Does not immediately destroy the server. |
||||
|
||||
Args: |
||||
tag (object): if not None, have the server place an event on its |
||||
completion queue notifying it when this server has completely shut down. |
||||
""" |
||||
|
||||
@abc.abstractmethod |
||||
def request_call(self, completion_queue, tag): |
||||
"""Requests a call from the server on the server's completion queue. |
||||
|
||||
Args: |
||||
completion_queue (CompletionQueue): Completion queue for the call. May be |
||||
the same as the server's completion queue. |
||||
tag (object) ... |
||||
""" |
Loading…
Reference in new issue