Merge pull request #4228 from soltanmm/cy-rel

Use updated metadata auth call credentials core API in
Python (and migrate to Cython).
pull/4342/head
Nathaniel Manista 9 years ago
commit 960870549a
  1. 67
      src/python/grpcio/grpc/_adapter/_c/module.c
  2. 61
      src/python/grpcio/grpc/_adapter/_c/types.c
  3. 286
      src/python/grpcio/grpc/_adapter/_c/types.h
  4. 186
      src/python/grpcio/grpc/_adapter/_c/types/call.c
  5. 203
      src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
  6. 187
      src/python/grpcio/grpc/_adapter/_c/types/channel.c
  7. 165
      src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c
  8. 124
      src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
  9. 196
      src/python/grpcio/grpc/_adapter/_c/types/server.c
  10. 137
      src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
  11. 524
      src/python/grpcio/grpc/_adapter/_c/utility.c
  12. 33
      src/python/grpcio/grpc/_adapter/_implementations.py
  13. 45
      src/python/grpcio/grpc/_adapter/_intermediary_low.py
  14. 214
      src/python/grpcio/grpc/_adapter/_low.py
  15. 94
      src/python/grpcio/grpc/_adapter/_types.py
  16. 16
      src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
  17. 31
      src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
  18. 11
      src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
  19. 23
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
  20. 80
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
  21. 59
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
  22. 1
      src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
  23. 82
      src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
  24. 2
      src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
  25. 102
      src/python/grpcio/grpc/_cython/adapter_low.py
  26. 6
      src/python/grpcio/grpc/_cython/cygrpc.pyx
  27. 12
      src/python/grpcio/grpc/_links/invocation.py
  28. 6
      src/python/grpcio/grpc/_links/service.py
  29. 2
      src/python/grpcio/grpc/beta/_server.py
  30. 96
      src/python/grpcio/grpc/beta/implementations.py
  31. 49
      src/python/grpcio/grpc/beta/interfaces.py
  32. 23
      src/python/grpcio/setup.py
  33. 2
      src/python/grpcio/tests/interop/_secure_interop_test.py
  34. 2
      src/python/grpcio/tests/interop/client.py
  35. 12
      src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
  36. 8
      src/python/grpcio/tests/unit/_adapter/_low_test.py
  37. 187
      src/python/grpcio/tests/unit/_cython/adapter_low_test.py
  38. 190
      src/python/grpcio/tests/unit/_cython/cygrpc_test.py
  39. 58
      src/python/grpcio/tests/unit/beta/_beta_features_test.py
  40. 4
      src/python/grpcio/tests/unit/beta/_face_interface_test.py
  41. 6
      src/python/grpcio/tests/unit/beta/test_utilities.py

@ -1,67 +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 <stdlib.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include "grpc/_adapter/_c/types.h"
static PyMethodDef c_methods[] = {
{NULL}
};
PyMODINIT_FUNC init_c(void) {
PyObject *module;
module = Py_InitModule3("_c", c_methods,
"Wrappings of C structures and functions.");
if (pygrpc_module_add_types(module) < 0) {
return;
}
if (PyModule_AddStringConstant(
module, "PRIMARY_USER_AGENT_KEY",
GRPC_ARG_PRIMARY_USER_AGENT_STRING) < 0) {
return;
}
/* GRPC maintains an internal counter of how many times it has been
initialized and handles multiple pairs of grpc_init()/grpc_shutdown()
invocations accordingly. */
grpc_init();
atexit(&grpc_shutdown);
}

@ -1,61 +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/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
int pygrpc_module_add_types(PyObject *module) {
int i;
PyTypeObject *types[] = {
&pygrpc_CallCredentials_type,
&pygrpc_ChannelCredentials_type,
&pygrpc_ServerCredentials_type,
&pygrpc_CompletionQueue_type,
&pygrpc_Call_type,
&pygrpc_Channel_type,
&pygrpc_Server_type
};
for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
if (PyType_Ready(types[i]) < 0) {
return -1;
}
}
for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
Py_INCREF(types[i]);
PyModule_AddObject(module, types[i]->tp_name, (PyObject *)types[i]);
}
return 0;
}

@ -1,286 +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 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 ChannelCredentials {
PyObject_HEAD
grpc_channel_credentials *c_creds;
} ChannelCredentials;
void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self);
ChannelCredentials *pygrpc_ChannelCredentials_google_default(
PyTypeObject *type, PyObject *ignored);
ChannelCredentials *pygrpc_ChannelCredentials_ssl(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ChannelCredentials *pygrpc_ChannelCredentials_composite(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
extern PyTypeObject pygrpc_ChannelCredentials_type;
typedef struct CallCredentials {
PyObject_HEAD
grpc_call_credentials *c_creds;
} CallCredentials;
void pygrpc_CallCredentials_dealloc(CallCredentials *self);
CallCredentials *pygrpc_CallCredentials_composite(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
CallCredentials *pygrpc_CallCredentials_compute_engine(
PyTypeObject *type, PyObject *ignored);
CallCredentials *pygrpc_CallCredentials_jwt(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
CallCredentials *pygrpc_CallCredentials_refresh_token(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
CallCredentials *pygrpc_CallCredentials_iam(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
extern PyTypeObject pygrpc_CallCredentials_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);
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);
PyObject *pygrpc_Call_peer(Call *self);
PyObject *pygrpc_Call_set_credentials(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);
PyObject *pygrpc_Channel_check_connectivity_state(Channel *self, PyObject *args,
PyObject *kwargs);
PyObject *pygrpc_Channel_watch_connectivity_state(Channel *self, PyObject *args,
PyObject *kwargs);
PyObject *pygrpc_Channel_target(Channel *self);
extern PyTypeObject pygrpc_Channel_type;
/*========*/
/* Server */
/*========*/
typedef struct Server {
PyObject_HEAD
grpc_server *c_serv;
CompletionQueue *cq;
int shutdown_called;
} 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);
PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused);
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);
/* Construct a tag associated with a channel state change. */
pygrpc_tag *pygrpc_produce_channel_state_change_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_pyseq_to_send_metadata(
PyObject *pyseq, grpc_metadata **metadata, size_t *count);
/* Returns a metadata array as a Python object on success, else NULL. */
PyObject *pygrpc_cast_metadata_array_to_pyseq(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_ */

@ -1,186 +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/_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, ""},
{"peer", (PyCFunction)pygrpc_Call_peer, METH_NOARGS, ""},
{"set_credentials", (PyCFunction)pygrpc_Call_set_credentials, 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, NULL);
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, NULL);
} 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, NULL);
}
return PyInt_FromLong(errcode);
}
PyObject *pygrpc_Call_peer(Call *self) {
char *peer = grpc_call_get_peer(self->c_call);
PyObject *py_peer = PyString_FromString(peer);
gpr_free(peer);
return py_peer;
}
PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args,
PyObject *kwargs) {
CallCredentials *creds;
grpc_call_error errcode;
static char *keywords[] = {"creds", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "O!:set_credentials", keywords,
&pygrpc_CallCredentials_type, &creds)) {
return NULL;
}
errcode = grpc_call_set_credentials(self->c_call, creds->c_creds);
return PyInt_FromLong(errcode);
}

@ -1,203 +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/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
PyMethodDef pygrpc_CallCredentials_methods[] = {
{"composite", (PyCFunction)pygrpc_CallCredentials_composite,
METH_CLASS|METH_KEYWORDS, ""},
{"compute_engine", (PyCFunction)pygrpc_CallCredentials_compute_engine,
METH_CLASS|METH_NOARGS, ""},
{"jwt", (PyCFunction)pygrpc_CallCredentials_jwt,
METH_CLASS|METH_KEYWORDS, ""},
{"refresh_token", (PyCFunction)pygrpc_CallCredentials_refresh_token,
METH_CLASS|METH_KEYWORDS, ""},
{"iam", (PyCFunction)pygrpc_CallCredentials_iam,
METH_CLASS|METH_KEYWORDS, ""},
{NULL}
};
const char pygrpc_CallCredentials_doc[] = "";
PyTypeObject pygrpc_CallCredentials_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"CallCredentials", /* tp_name */
sizeof(CallCredentials), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_CallCredentials_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_CallCredentials_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_CallCredentials_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_CallCredentials_dealloc(CallCredentials *self) {
grpc_call_credentials_release(self->c_creds);
self->ob_type->tp_free((PyObject *)self);
}
CallCredentials *pygrpc_CallCredentials_composite(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
CallCredentials *self;
CallCredentials *creds1;
CallCredentials *creds2;
static char *keywords[] = {"creds1", "creds2", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
&pygrpc_CallCredentials_type, &creds1,
&pygrpc_CallCredentials_type, &creds2)) {
return NULL;
}
self = (CallCredentials *)type->tp_alloc(type, 0);
self->c_creds =
grpc_composite_call_credentials_create(
creds1->c_creds, creds2->c_creds, NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials");
return NULL;
}
return self;
}
CallCredentials *pygrpc_CallCredentials_compute_engine(
PyTypeObject *type, PyObject *ignored) {
CallCredentials *self = (CallCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_google_compute_engine_credentials_create(NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
"couldn't create compute engine credentials");
return NULL;
}
return self;
}
/* TODO: Rename this credentials to something like service_account_jwt_access */
CallCredentials *pygrpc_CallCredentials_jwt(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
CallCredentials *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 = (CallCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_service_account_jwt_access_credentials_create(
json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials");
return NULL;
}
return self;
}
CallCredentials *pygrpc_CallCredentials_refresh_token(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
CallCredentials *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 = (CallCredentials *)type->tp_alloc(type, 0);
self->c_creds =
grpc_google_refresh_token_credentials_create(json_refresh_token, NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
"couldn't create credentials from refresh token");
return NULL;
}
return self;
}
CallCredentials *pygrpc_CallCredentials_iam(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
CallCredentials *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 = (CallCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_google_iam_credentials_create(authorization_token,
authority_selector, NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials");
return NULL;
}
return self;
}

@ -1,187 +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/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
PyMethodDef pygrpc_Channel_methods[] = {
{"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""},
{"check_connectivity_state", (PyCFunction)pygrpc_Channel_check_connectivity_state, METH_KEYWORDS, ""},
{"watch_connectivity_state", (PyCFunction)pygrpc_Channel_watch_connectivity_state, METH_KEYWORDS, ""},
{"target", (PyCFunction)pygrpc_Channel_target, METH_NOARGS, ""},
{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;
ChannelCredentials *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_ChannelCredentials_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, NULL);
} else {
self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL);
}
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!szd: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, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host,
pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
return call;
}
PyObject *pygrpc_Channel_check_connectivity_state(
Channel *self, PyObject *args, PyObject *kwargs) {
PyObject *py_try_to_connect;
int try_to_connect;
char *keywords[] = {"try_to_connect", NULL};
grpc_connectivity_state state;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:connectivity_state", keywords,
&py_try_to_connect)) {
return NULL;
}
if (!PyBool_Check(py_try_to_connect)) {
Py_XDECREF(py_try_to_connect);
return NULL;
}
try_to_connect = Py_True == py_try_to_connect;
Py_DECREF(py_try_to_connect);
state = grpc_channel_check_connectivity_state(self->c_chan, try_to_connect);
return PyInt_FromLong(state);
}
PyObject *pygrpc_Channel_watch_connectivity_state(
Channel *self, PyObject *args, PyObject *kwargs) {
PyObject *tag;
double deadline;
int last_observed_state;
CompletionQueue *completion_queue;
char *keywords[] = {"last_observed_state", "deadline",
"completion_queue", "tag", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "idO!O:watch_connectivity_state", keywords,
&last_observed_state, &deadline, &pygrpc_CompletionQueue_type,
&completion_queue, &tag)) {
return NULL;
}
grpc_channel_watch_connectivity_state(
self->c_chan, (grpc_connectivity_state)last_observed_state,
pygrpc_cast_double_to_gpr_timespec(deadline), completion_queue->c_cq,
pygrpc_produce_channel_state_change_tag(tag));
Py_RETURN_NONE;
}
PyObject *pygrpc_Channel_target(Channel *self) {
char *target = grpc_channel_get_target(self->c_chan);
PyObject *py_target = PyString_FromString(target);
gpr_free(target);
return py_target;
}

@ -1,165 +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/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
PyMethodDef pygrpc_ChannelCredentials_methods[] = {
{"google_default", (PyCFunction)pygrpc_ChannelCredentials_google_default,
METH_CLASS|METH_NOARGS, ""},
{"ssl", (PyCFunction)pygrpc_ChannelCredentials_ssl,
METH_CLASS|METH_KEYWORDS, ""},
{"composite", (PyCFunction)pygrpc_ChannelCredentials_composite,
METH_CLASS|METH_KEYWORDS, ""},
{NULL}
};
const char pygrpc_ChannelCredentials_doc[] = "";
PyTypeObject pygrpc_ChannelCredentials_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"ChannelCredentials", /* tp_name */
sizeof(ChannelCredentials), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_ChannelCredentials_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_ChannelCredentials_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_ChannelCredentials_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_ChannelCredentials_dealloc(ChannelCredentials *self) {
grpc_channel_credentials_release(self->c_creds);
self->ob_type->tp_free((PyObject *)self);
}
ChannelCredentials *pygrpc_ChannelCredentials_google_default(
PyTypeObject *type, PyObject *ignored) {
ChannelCredentials *self = (ChannelCredentials *)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;
}
ChannelCredentials *pygrpc_ChannelCredentials_ssl(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ChannelCredentials *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 = (ChannelCredentials *)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, NULL);
} else {
self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL);
}
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials");
return NULL;
}
return self;
}
ChannelCredentials *pygrpc_ChannelCredentials_composite(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ChannelCredentials *self;
ChannelCredentials *creds1;
CallCredentials *creds2;
static char *keywords[] = {"creds1", "creds2", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
&pygrpc_ChannelCredentials_type, &creds1,
&pygrpc_CallCredentials_type, &creds2)) {
return NULL;
}
self = (ChannelCredentials *)type->tp_alloc(type, 0);
self->c_creds =
grpc_composite_channel_credentials_create(
creds1->c_creds, creds2->c_creds, NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(
PyExc_RuntimeError, "couldn't create composite credentials");
return NULL;
}
return self;
}

@ -1,124 +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/_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(NULL);
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), NULL);
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;
}

@ -1,196 +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/_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, ""},
{"cancel_all_calls", (PyCFunction)pygrpc_Server_cancel_all_calls,
METH_NOARGS, ""},
{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:Server", 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, NULL);
grpc_server_register_completion_queue(self->c_serv, cq->c_cq, NULL);
pygrpc_discard_channel_args(c_args);
self->cq = cq;
Py_INCREF(self->cq);
self->shutdown_called = 0;
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_insecure_http2_port(self->c_serv, addr);
}
return PyInt_FromLong(port);
}
PyObject *pygrpc_Server_start(Server *self, PyObject *ignored) {
grpc_server_start(self->c_serv);
self->shutdown_called = 0;
Py_RETURN_NONE;
}
PyObject *pygrpc_Server_shutdown(
Server *self, PyObject *args, PyObject *kwargs) {
PyObject *user_tag;
pygrpc_tag *tag;
static char *keywords[] = {"tag", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &user_tag)) {
return NULL;
}
tag = pygrpc_produce_server_shutdown_tag(user_tag);
grpc_server_shutdown_and_notify(self->c_serv, self->cq->c_cq, tag);
self->shutdown_called = 1;
Py_RETURN_NONE;
}
PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused) {
if (!self->shutdown_called) {
PyErr_SetString(
PyExc_RuntimeError,
"shutdown must have been called prior to calling cancel_all_calls!");
return NULL;
}
grpc_server_cancel_all_calls(self->c_serv);
Py_RETURN_NONE;
}

@ -1,137 +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/_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, ""},
{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;
int force_client_auth;
size_t num_key_cert_pairs;
size_t i;
static char *keywords[] = {
"root_certs", "key_cert_pairs", "force_client_auth", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zOi:ssl", keywords,
&root_certs, &py_key_cert_pairs, &force_client_auth)) {
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, force_client_auth, NULL);
gpr_free(key_cert_pairs);
return self;
}

@ -1,524 +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 <math.h>
#include <string.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/alloc.h>
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
#include <grpc/support/string_util.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;
}
pygrpc_tag *pygrpc_produce_channel_state_change_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_pyseq(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 ? (PyObject*)tag->call : Py_None, 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 = 6;
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;
static const int WRITE_FLAGS_INDEX = 5;
int type;
Py_ssize_t message_size;
char *message;
char *status_details;
gpr_slice message_slice;
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;
gpr_asprintf(&buf, "expected tuple op of length %d", OP_TUPLE_SIZE);
PyErr_SetString(PyExc_ValueError, buf);
gpr_free(buf);
return 0;
}
type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX));
if (PyErr_Occurred()) {
return 0;
}
c_op.op = type;
c_op.reserved = NULL;
c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX));
if (PyErr_Occurred()) {
return 0;
}
switch (type) {
case GRPC_OP_SEND_INITIAL_METADATA:
if (!pygrpc_cast_pyseq_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_raw_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_pyseq_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;
gpr_asprintf(&buf, "expected tuple status in op of length %d",
STATUS_TUPLE_SIZE);
PyErr_SetString(PyExc_ValueError, buf);
gpr_free(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) {
size_t i;
switch(op.op) {
case GRPC_OP_SEND_INITIAL_METADATA:
/* Whenever we produce send-metadata, we allocate new strings (to handle
arbitrary sequence input as opposed to just lists or just tuples). We
thus must free those elements. */
for (i = 0; i < op.data.send_initial_metadata.count; ++i) {
gpr_free((void *)op.data.send_initial_metadata.metadata[i].key);
gpr_free((void *)op.data.send_initial_metadata.metadata[i].value);
}
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:
/* Whenever we produce send-metadata, we allocate new strings (to handle
arbitrary sequence input as opposed to just lists or just tuples). We
thus must free those elements. */
for (i = 0; i < op.data.send_status_from_server.trailing_metadata_count;
++i) {
gpr_free(
(void *)op.data.send_status_from_server.trailing_metadata[i].key);
gpr_free(
(void *)op.data.send_status_from_server.trailing_metadata[i].value);
}
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) {
timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME);
return timespec.tv_sec + 1e-9*timespec.tv_nsec;
}
/* Because C89 doesn't have a way to check for infinity... */
static int pygrpc_isinf(double x) {
return x * 0 != 0;
}
gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) {
gpr_timespec result;
if (pygrpc_isinf(seconds)) {
result = seconds > 0.0 ? gpr_inf_future(GPR_CLOCK_REALTIME)
: gpr_inf_past(GPR_CLOCK_REALTIME);
} else {
result.tv_sec = (time_t)seconds;
result.tv_nsec = ((seconds - result.tv_sec) * 1e9);
result.clock_type = GPR_CLOCK_REALTIME;
}
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;
args.num_args = num_args;
args.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_pyseq_to_send_metadata(
PyObject *pyseq, grpc_metadata **metadata, size_t *count) {
size_t i;
Py_ssize_t value_length;
char *key;
char *value;
if (!PySequence_Check(pyseq)) {
return 0;
}
*count = PySequence_Size(pyseq);
*metadata = gpr_malloc(sizeof(grpc_metadata) * *count);
for (i = 0; i < *count; ++i) {
PyObject *item = PySequence_GetItem(pyseq, i);
if (!PyArg_ParseTuple(item, "ss#", &key, &value, &value_length)) {
Py_DECREF(item);
gpr_free(*metadata);
*count = 0;
*metadata = NULL;
return 0;
} else {
(*metadata)[i].key = gpr_strdup(key);
(*metadata)[i].value = gpr_malloc(value_length);
memcpy((void *)(*metadata)[i].value, value, value_length);
Py_DECREF(item);
}
(*metadata)[i].value_length = value_length;
}
return 1;
}
PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata) {
PyObject *result = PyTuple_New(metadata.count);
size_t i;
for (i = 0; i < metadata.count; ++i) {
PyTuple_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;
gpr_slice slice;
char *read_result = NULL;
size_t size = 0;
grpc_byte_buffer_reader_init(&reader, buffer);
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);
}
*result_size = size;
*result = read_result;
}

@ -27,29 +27,22 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time import collections
import unittest
from grpc._adapter import _c from grpc.beta import interfaces
from grpc._adapter import _types
class AuthMetadataContext(collections.namedtuple(
'AuthMetadataContext', [
'service_url',
'method_name'
]), interfaces.GRPCAuthMetadataContext):
pass
class CTypeSmokeTest(unittest.TestCase):
def testCompletionQueueUpDown(self): class AuthMetadataPluginCallback(interfaces.GRPCAuthMetadataContext):
completion_queue = _c.CompletionQueue()
del completion_queue
def testServerUpDown(self): def __init__(self, callback):
completion_queue = _c.CompletionQueue() self._callback = callback
serv = _c.Server(completion_queue, [])
del serv
del completion_queue
def testChannelUpDown(self): def __call__(self, metadata, error):
channel = _c.Channel('[::]:0', []) self._callback(metadata, error)
del channel
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -115,16 +115,20 @@ class Call(object):
return call return call
def invoke(self, completion_queue, metadata_tag, finish_tag): def invoke(self, completion_queue, metadata_tag, finish_tag):
err0 = self._internal.start_batch([ err = self._internal.start_batch([
_types.OpArgs.send_initial_metadata(self._metadata) _types.OpArgs.send_initial_metadata(self._metadata)
], _IGNORE_ME_TAG) ], _IGNORE_ME_TAG)
err1 = self._internal.start_batch([ if err != _types.CallError.OK:
return err
err = self._internal.start_batch([
_types.OpArgs.recv_initial_metadata() _types.OpArgs.recv_initial_metadata()
], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED)) ], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED))
err2 = self._internal.start_batch([ if err != _types.CallError.OK:
return err
err = self._internal.start_batch([
_types.OpArgs.recv_status_on_client() _types.OpArgs.recv_status_on_client()
], _TagAdapter(finish_tag, Event.Kind.FINISH)) ], _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 return err
def write(self, message, tag, flags): def write(self, message, tag, flags):
return self._internal.start_batch([ return self._internal.start_batch([
@ -158,7 +162,8 @@ class Call(object):
def status(self, status, tag): def status(self, status, tag):
return self._internal.start_batch([ return self._internal.start_batch([
_types.OpArgs.send_status_from_server(self._metadata, status.code, status.details) _types.OpArgs.send_status_from_server(
self._metadata, status.code, status.details)
], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED)) ], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED))
def cancel(self): def cancel(self):
@ -168,20 +173,17 @@ class Call(object):
return self._internal.peer() return self._internal.peer()
def set_credentials(self, creds): def set_credentials(self, creds):
return self._internal.set_credentials(creds._internal) return self._internal.set_credentials(creds)
class Channel(object): class Channel(object):
"""Adapter from old _low.Channel interface to new _low.Channel.""" """Adapter from old _low.Channel interface to new _low.Channel."""
def __init__(self, hostport, client_credentials, server_host_override=None): def __init__(self, hostport, channel_credentials, server_host_override=None):
args = [] args = []
if server_host_override: if server_host_override:
args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override)) args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override))
creds = None self._internal = _low.Channel(hostport, args, channel_credentials)
if client_credentials:
creds = client_credentials._internal
self._internal = _low.Channel(hostport, args, creds)
class CompletionQueue(object): class CompletionQueue(object):
@ -192,7 +194,7 @@ class CompletionQueue(object):
def get(self, deadline=None): def get(self, deadline=None):
if deadline is None: if deadline is None:
ev = self._internal.next() ev = self._internal.next(float('+inf'))
else: else:
ev = self._internal.next(deadline) ev = self._internal.next(deadline)
if ev is None: if ev is None:
@ -240,7 +242,7 @@ class Server(object):
if server_credentials is None: if server_credentials is None:
return self._internal.add_http2_port(addr, None) return self._internal.add_http2_port(addr, None)
else: else:
return self._internal.add_http2_port(addr, server_credentials._internal) return self._internal.add_http2_port(addr, server_credentials)
def start(self): def start(self):
return self._internal.start() return self._internal.start()
@ -248,20 +250,9 @@ class Server(object):
def service(self, tag): def service(self, tag):
return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED)) return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED))
def cancel_all_calls(self):
self._internal.cancel_all_calls()
def stop(self): def stop(self):
return self._internal.shutdown(_TagAdapter(None, Event.Kind.STOP)) return self._internal.shutdown(_TagAdapter(None, Event.Kind.STOP))
class ClientCredentials(object):
"""Adapter from old _low.ClientCredentials interface to new _low.ChannelCredentials."""
def __init__(self, root_certificates, private_key, certificate_chain):
self._internal = _low.ChannelCredentials.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, force_client_auth):
self._internal = _low.ServerCredentials.ssl(
root_credentials, list(pair_sequence), force_client_auth)

@ -27,36 +27,157 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import threading
from grpc import _grpcio_metadata from grpc import _grpcio_metadata
from grpc._adapter import _c from grpc._cython import cygrpc
from grpc._adapter import _implementations
from grpc._adapter import _types from grpc._adapter import _types
_USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__) _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
ChannelCredentials = _c.ChannelCredentials ChannelCredentials = cygrpc.ChannelCredentials
CallCredentials = _c.CallCredentials CallCredentials = cygrpc.CallCredentials
ServerCredentials = _c.ServerCredentials ServerCredentials = cygrpc.ServerCredentials
channel_credentials_composite = cygrpc.channel_credentials_composite
call_credentials_composite = cygrpc.call_credentials_composite
def server_credentials_ssl(root_credentials, pair_sequence, force_client_auth):
return cygrpc.server_credentials_ssl(
root_credentials,
[cygrpc.SslPemKeyCertPair(key, pem) for key, pem in pair_sequence],
force_client_auth)
def channel_credentials_ssl(
root_certificates, private_key, certificate_chain):
pair = None
if private_key is not None or certificate_chain is not None:
pair = cygrpc.SslPemKeyCertPair(private_key, certificate_chain)
return cygrpc.channel_credentials_ssl(root_certificates, pair)
class _WrappedCygrpcCallback(object):
def __init__(self, cygrpc_callback):
self.is_called = False
self.error = None
self.is_called_lock = threading.Lock()
self.cygrpc_callback = cygrpc_callback
def _invoke_failure(self, error):
# TODO(atash) translate different Exception superclasses into different
# status codes.
self.cygrpc_callback(
cygrpc.Metadata([]), cygrpc.StatusCode.internal, error.message)
def _invoke_success(self, metadata):
try:
cygrpc_metadata = cygrpc.Metadata(
cygrpc.Metadatum(key, value)
for key, value in metadata)
except Exception as error:
self._invoke_failure(error)
return
self.cygrpc_callback(cygrpc_metadata, cygrpc.StatusCode.ok, '')
def __call__(self, metadata, error):
with self.is_called_lock:
if self.is_called:
raise RuntimeError('callback should only ever be invoked once')
if self.error:
self._invoke_failure(self.error)
return
self.is_called = True
if error is None:
self._invoke_success(metadata)
else:
self._invoke_failure(error)
def notify_failure(self, error):
with self.is_called_lock:
if not self.is_called:
self.error = error
class _WrappedPlugin(object):
def __init__(self, plugin):
self.plugin = plugin
def __call__(self, context, cygrpc_callback):
wrapped_cygrpc_callback = _WrappedCygrpcCallback(cygrpc_callback)
wrapped_context = _implementations.AuthMetadataContext(context.service_url,
context.method_name)
try:
self.plugin(
wrapped_context,
_implementations.AuthMetadataPluginCallback(wrapped_cygrpc_callback))
except Exception as error:
wrapped_cygrpc_callback.notify_failure(error)
raise
def call_credentials_metadata_plugin(plugin, name):
"""
Args:
plugin: A callable accepting a _types.AuthMetadataContext
object and a callback (itself accepting a list of metadata key/value
2-tuples and a None-able exception value). The callback must be eventually
called, but need not be called in plugin's invocation.
plugin's invocation must be non-blocking.
"""
return cygrpc.call_credentials_metadata_plugin(
cygrpc.CredentialsMetadataPlugin(_WrappedPlugin(plugin), name))
class CompletionQueue(_types.CompletionQueue): class CompletionQueue(_types.CompletionQueue):
def __init__(self): def __init__(self):
self.completion_queue = _c.CompletionQueue() self.completion_queue = cygrpc.CompletionQueue()
def next(self, deadline=float('+inf')): def next(self, deadline=float('+inf')):
raw_event = self.completion_queue.next(deadline) raw_event = self.completion_queue.poll(cygrpc.Timespec(deadline))
if raw_event is None: if raw_event.type == cygrpc.CompletionType.queue_timeout:
return None return None
event = _types.Event(*raw_event) event_type = raw_event.type
if event.call is not None: event_tag = raw_event.tag
event = event._replace(call=Call(event.call)) event_call = Call(raw_event.operation_call)
if event.call_details is not None: if raw_event.request_call_details:
event = event._replace(call_details=_types.CallDetails(*event.call_details)) event_call_details = _types.CallDetails(
if event.results is not None: raw_event.request_call_details.method,
new_results = [_types.OpResult(*r) for r in event.results] raw_event.request_call_details.host,
new_results = [r if r.status is None else r._replace(status=_types.Status(_types.StatusCode(r.status[0]), r.status[1])) for r in new_results] float(raw_event.request_call_details.deadline))
event = event._replace(results=new_results) else:
return event event_call_details = None
event_success = raw_event.success
event_results = []
if raw_event.is_new_request:
event_results.append(_types.OpResult(
_types.OpType.RECV_INITIAL_METADATA, raw_event.request_metadata,
None, None, None, None))
else:
if raw_event.batch_operations:
for operation in raw_event.batch_operations:
result_type = operation.type
result_initial_metadata = operation.received_metadata_or_none
result_trailing_metadata = operation.received_metadata_or_none
result_message = operation.received_message_or_none
if result_message is not None:
result_message = result_message.bytes()
result_cancelled = operation.received_cancelled_or_none
if operation.has_status:
result_status = _types.Status(
operation.received_status_code_or_none,
operation.received_status_details_or_none)
else:
result_status = None
event_results.append(
_types.OpResult(result_type, result_initial_metadata,
result_trailing_metadata, result_message,
result_status, result_cancelled))
return _types.Event(event_type, event_tag, event_call, event_call_details,
event_results, event_success)
def shutdown(self): def shutdown(self):
self.completion_queue.shutdown() self.completion_queue.shutdown()
@ -68,7 +189,36 @@ class Call(_types.Call):
self.call = call self.call = call
def start_batch(self, ops, tag): def start_batch(self, ops, tag):
return self.call.start_batch(ops, tag) translated_ops = []
for op in ops:
if op.type == _types.OpType.SEND_INITIAL_METADATA:
translated_op = cygrpc.operation_send_initial_metadata(
cygrpc.Metadata(
cygrpc.Metadatum(key, value)
for key, value in op.initial_metadata))
elif op.type == _types.OpType.SEND_MESSAGE:
translated_op = cygrpc.operation_send_message(op.message)
elif op.type == _types.OpType.SEND_CLOSE_FROM_CLIENT:
translated_op = cygrpc.operation_send_close_from_client()
elif op.type == _types.OpType.SEND_STATUS_FROM_SERVER:
translated_op = cygrpc.operation_send_status_from_server(
cygrpc.Metadata(
cygrpc.Metadatum(key, value)
for key, value in op.trailing_metadata),
op.status.code,
op.status.details)
elif op.type == _types.OpType.RECV_INITIAL_METADATA:
translated_op = cygrpc.operation_receive_initial_metadata()
elif op.type == _types.OpType.RECV_MESSAGE:
translated_op = cygrpc.operation_receive_message()
elif op.type == _types.OpType.RECV_STATUS_ON_CLIENT:
translated_op = cygrpc.operation_receive_status_on_client()
elif op.type == _types.OpType.RECV_CLOSE_ON_SERVER:
translated_op = cygrpc.operation_receive_close_on_server()
else:
raise ValueError('unexpected operation type {}'.format(op.type))
translated_ops.append(translated_op)
return self.call.start_batch(cygrpc.Operations(translated_ops), tag)
def cancel(self, code=None, details=None): def cancel(self, code=None, details=None):
if code is None and details is None: if code is None and details is None:
@ -86,14 +236,20 @@ class Call(_types.Call):
class Channel(_types.Channel): class Channel(_types.Channel):
def __init__(self, target, args, creds=None): def __init__(self, target, args, creds=None):
args = list(args) + [(_c.PRIMARY_USER_AGENT_KEY, _USER_AGENT)] args = list(args) + [
(cygrpc.ChannelArgKey.primary_user_agent_string, _USER_AGENT)]
args = cygrpc.ChannelArgs(
cygrpc.ChannelArg(key, value) for key, value in args)
if creds is None: if creds is None:
self.channel = _c.Channel(target, args) self.channel = cygrpc.Channel(target, args)
else: else:
self.channel = _c.Channel(target, args, creds) self.channel = cygrpc.Channel(target, args, creds)
def create_call(self, completion_queue, method, host, deadline=None): def create_call(self, completion_queue, method, host, deadline=None):
return Call(self.channel.create_call(completion_queue.completion_queue, method, host, deadline)) internal_call = self.channel.create_call(
None, 0, completion_queue.completion_queue, method, host,
cygrpc.Timespec(deadline))
return Call(internal_call)
def check_connectivity_state(self, try_to_connect): def check_connectivity_state(self, try_to_connect):
return self.channel.check_connectivity_state(try_to_connect) return self.channel.check_connectivity_state(try_to_connect)
@ -101,7 +257,8 @@ class Channel(_types.Channel):
def watch_connectivity_state(self, last_observed_state, deadline, def watch_connectivity_state(self, last_observed_state, deadline,
completion_queue, tag): completion_queue, tag):
self.channel.watch_connectivity_state( self.channel.watch_connectivity_state(
last_observed_state, deadline, completion_queue.completion_queue, tag) last_observed_state, cygrpc.Timespec(deadline),
completion_queue.completion_queue, tag)
def target(self): def target(self):
return self.channel.target() return self.channel.target()
@ -112,7 +269,11 @@ _NO_TAG = object()
class Server(_types.Server): class Server(_types.Server):
def __init__(self, completion_queue, args): def __init__(self, completion_queue, args):
self.server = _c.Server(completion_queue.completion_queue, args) args = cygrpc.ChannelArgs(
cygrpc.ChannelArg(key, value) for key, value in args)
self.server = cygrpc.Server(args)
self.server.register_completion_queue(completion_queue.completion_queue)
self.server_queue = completion_queue
def add_http2_port(self, addr, creds=None): def add_http2_port(self, addr, creds=None):
if creds is None: if creds is None:
@ -124,10 +285,11 @@ class Server(_types.Server):
return self.server.start() return self.server.start()
def shutdown(self, tag=None): def shutdown(self, tag=None):
return self.server.shutdown(tag) return self.server.shutdown(self.server_queue.completion_queue, tag)
def request_call(self, completion_queue, tag): def request_call(self, completion_queue, tag):
return self.server.request_call(completion_queue.completion_queue, tag) return self.server.request_call(completion_queue.completion_queue,
self.server_queue.completion_queue, tag)
def cancel_all_calls(self): def cancel_all_calls(self):
return self.server.cancel_all_calls() return self.server.cancel_all_calls()

@ -31,6 +31,8 @@ import abc
import collections import collections
import enum import enum
from grpc._cython import cygrpc
class GrpcChannelArgumentKeys(enum.Enum): class GrpcChannelArgumentKeys(enum.Enum):
"""Mirrors keys used in grpc_channel_args for GRPC-specific arguments.""" """Mirrors keys used in grpc_channel_args for GRPC-specific arguments."""
@ -40,77 +42,77 @@ class GrpcChannelArgumentKeys(enum.Enum):
@enum.unique @enum.unique
class CallError(enum.IntEnum): class CallError(enum.IntEnum):
"""Mirrors grpc_call_error in the C core.""" """Mirrors grpc_call_error in the C core."""
OK = 0 OK = cygrpc.CallError.ok
ERROR = 1 ERROR = cygrpc.CallError.error
ERROR_NOT_ON_SERVER = 2 ERROR_NOT_ON_SERVER = cygrpc.CallError.not_on_server
ERROR_NOT_ON_CLIENT = 3 ERROR_NOT_ON_CLIENT = cygrpc.CallError.not_on_client
ERROR_ALREADY_ACCEPTED = 4 ERROR_ALREADY_ACCEPTED = cygrpc.CallError.already_accepted
ERROR_ALREADY_INVOKED = 5 ERROR_ALREADY_INVOKED = cygrpc.CallError.already_invoked
ERROR_NOT_INVOKED = 6 ERROR_NOT_INVOKED = cygrpc.CallError.not_invoked
ERROR_ALREADY_FINISHED = 7 ERROR_ALREADY_FINISHED = cygrpc.CallError.already_finished
ERROR_TOO_MANY_OPERATIONS = 8 ERROR_TOO_MANY_OPERATIONS = cygrpc.CallError.too_many_operations
ERROR_INVALID_FLAGS = 9 ERROR_INVALID_FLAGS = cygrpc.CallError.invalid_flags
ERROR_INVALID_METADATA = 10 ERROR_INVALID_METADATA = cygrpc.CallError.invalid_metadata
@enum.unique @enum.unique
class StatusCode(enum.IntEnum): class StatusCode(enum.IntEnum):
"""Mirrors grpc_status_code in the C core.""" """Mirrors grpc_status_code in the C core."""
OK = 0 OK = cygrpc.StatusCode.ok
CANCELLED = 1 CANCELLED = cygrpc.StatusCode.cancelled
UNKNOWN = 2 UNKNOWN = cygrpc.StatusCode.unknown
INVALID_ARGUMENT = 3 INVALID_ARGUMENT = cygrpc.StatusCode.invalid_argument
DEADLINE_EXCEEDED = 4 DEADLINE_EXCEEDED = cygrpc.StatusCode.deadline_exceeded
NOT_FOUND = 5 NOT_FOUND = cygrpc.StatusCode.not_found
ALREADY_EXISTS = 6 ALREADY_EXISTS = cygrpc.StatusCode.already_exists
PERMISSION_DENIED = 7 PERMISSION_DENIED = cygrpc.StatusCode.permission_denied
RESOURCE_EXHAUSTED = 8 RESOURCE_EXHAUSTED = cygrpc.StatusCode.resource_exhausted
FAILED_PRECONDITION = 9 FAILED_PRECONDITION = cygrpc.StatusCode.failed_precondition
ABORTED = 10 ABORTED = cygrpc.StatusCode.aborted
OUT_OF_RANGE = 11 OUT_OF_RANGE = cygrpc.StatusCode.out_of_range
UNIMPLEMENTED = 12 UNIMPLEMENTED = cygrpc.StatusCode.unimplemented
INTERNAL = 13 INTERNAL = cygrpc.StatusCode.internal
UNAVAILABLE = 14 UNAVAILABLE = cygrpc.StatusCode.unavailable
DATA_LOSS = 15 DATA_LOSS = cygrpc.StatusCode.data_loss
UNAUTHENTICATED = 16 UNAUTHENTICATED = cygrpc.StatusCode.unauthenticated
@enum.unique @enum.unique
class OpWriteFlags(enum.IntEnum): class OpWriteFlags(enum.IntEnum):
"""Mirrors defined write-flag constants in the C core.""" """Mirrors defined write-flag constants in the C core."""
WRITE_BUFFER_HINT = 1 WRITE_BUFFER_HINT = cygrpc.WriteFlag.buffer_hint
WRITE_NO_COMPRESS = 2 WRITE_NO_COMPRESS = cygrpc.WriteFlag.no_compress
@enum.unique @enum.unique
class OpType(enum.IntEnum): class OpType(enum.IntEnum):
"""Mirrors grpc_op_type in the C core.""" """Mirrors grpc_op_type in the C core."""
SEND_INITIAL_METADATA = 0 SEND_INITIAL_METADATA = cygrpc.OperationType.send_initial_metadata
SEND_MESSAGE = 1 SEND_MESSAGE = cygrpc.OperationType.send_message
SEND_CLOSE_FROM_CLIENT = 2 SEND_CLOSE_FROM_CLIENT = cygrpc.OperationType.send_close_from_client
SEND_STATUS_FROM_SERVER = 3 SEND_STATUS_FROM_SERVER = cygrpc.OperationType.send_status_from_server
RECV_INITIAL_METADATA = 4 RECV_INITIAL_METADATA = cygrpc.OperationType.receive_initial_metadata
RECV_MESSAGE = 5 RECV_MESSAGE = cygrpc.OperationType.receive_message
RECV_STATUS_ON_CLIENT = 6 RECV_STATUS_ON_CLIENT = cygrpc.OperationType.receive_status_on_client
RECV_CLOSE_ON_SERVER = 7 RECV_CLOSE_ON_SERVER = cygrpc.OperationType.receive_close_on_server
@enum.unique @enum.unique
class EventType(enum.IntEnum): class EventType(enum.IntEnum):
"""Mirrors grpc_completion_type in the C core.""" """Mirrors grpc_completion_type in the C core."""
QUEUE_SHUTDOWN = 0 QUEUE_SHUTDOWN = cygrpc.CompletionType.queue_shutdown
QUEUE_TIMEOUT = 1 # if seen on the Python side, something went horridly wrong QUEUE_TIMEOUT = cygrpc.CompletionType.queue_timeout
OP_COMPLETE = 2 OP_COMPLETE = cygrpc.CompletionType.operation_complete
@enum.unique @enum.unique
class ConnectivityState(enum.IntEnum): class ConnectivityState(enum.IntEnum):
"""Mirrors grpc_connectivity_state in the C core.""" """Mirrors grpc_connectivity_state in the C core."""
IDLE = 0 IDLE = cygrpc.ConnectivityState.idle
CONNECTING = 1 CONNECTING = cygrpc.ConnectivityState.connecting
READY = 2 READY = cygrpc.ConnectivityState.ready
TRANSIENT_FAILURE = 3 TRANSIENT_FAILURE = cygrpc.ConnectivityState.transient_failure
FATAL_FAILURE = 4 FATAL_FAILURE = cygrpc.ConnectivityState.fatal_failure
class Status(collections.namedtuple( class Status(collections.namedtuple(

@ -53,24 +53,24 @@ cdef class Call:
self.c_call, cy_operations.c_ops, cy_operations.c_nops, self.c_call, cy_operations.c_ops, cy_operations.c_nops,
<cpython.PyObject *>operation_tag, NULL) <cpython.PyObject *>operation_tag, NULL)
def cancel(self, def cancel(
grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE, self, grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
details=None): details=None):
if not self.is_valid: if not self.is_valid:
raise ValueError("invalid call object cannot be used from Python") raise ValueError("invalid call object cannot be used from Python")
if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE): if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE):
raise ValueError("if error_code is specified, so must details " raise ValueError("if error_code is specified, so must details "
"(and vice-versa)") "(and vice-versa)")
if error_code != grpc.GRPC_STATUS__DO_NOT_USE:
if isinstance(details, bytes): if isinstance(details, bytes):
pass pass
elif isinstance(details, basestring): elif isinstance(details, basestring):
details = details.encode() details = details.encode()
else: else:
raise TypeError("expected details to be str or bytes") raise TypeError("expected details to be str or bytes")
if error_code != grpc.GRPC_STATUS__DO_NOT_USE:
self.references.append(details) self.references.append(details)
return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details, return grpc.grpc_call_cancel_with_status(
NULL) self.c_call, error_code, details, NULL)
else: else:
return grpc.grpc_call_cancel(self.c_call, NULL) return grpc.grpc_call_cancel(self.c_call, NULL)
@ -79,6 +79,12 @@ cdef class Call:
return grpc.grpc_call_set_credentials( return grpc.grpc_call_set_credentials(
self.c_call, call_credentials.c_credentials) self.c_call, call_credentials.c_credentials)
def peer(self):
cdef char *peer = grpc.grpc_call_get_peer(self.c_call)
result = <bytes>peer
grpc.gpr_free(peer)
return result
def __dealloc__(self): def __dealloc__(self):
if self.c_call != NULL: if self.c_call != NULL:
grpc.grpc_call_destroy(self.c_call) grpc.grpc_call_destroy(self.c_call)

@ -27,6 +27,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cimport cpython
from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport call
from grpc._cython._cygrpc cimport completion_queue from grpc._cython._cygrpc cimport completion_queue
from grpc._cython._cygrpc cimport credentials from grpc._cython._cygrpc cimport credentials
@ -70,12 +72,16 @@ cdef class Channel:
method = method.encode() method = method.encode()
else: else:
raise TypeError("expected method to be str or bytes") raise TypeError("expected method to be str or bytes")
if isinstance(host, bytes): cdef char *host_c_string = NULL
if host is None:
pass pass
elif isinstance(host, bytes):
host_c_string = host
elif isinstance(host, basestring): elif isinstance(host, basestring):
host = host.encode() host = host.encode()
host_c_string = host
else: else:
raise TypeError("expected host to be str or bytes") raise TypeError("expected host to be str, bytes, or None")
cdef call.Call operation_call = call.Call() cdef call.Call operation_call = call.Call()
operation_call.references = [self, method, host, queue] operation_call.references = [self, method, host, queue]
cdef grpc.grpc_call *parent_call = NULL cdef grpc.grpc_call *parent_call = NULL
@ -83,10 +89,29 @@ cdef class Channel:
parent_call = parent.c_call parent_call = parent.c_call
operation_call.c_call = grpc.grpc_channel_create_call( operation_call.c_call = grpc.grpc_channel_create_call(
self.c_channel, parent_call, flags, self.c_channel, parent_call, flags,
queue.c_completion_queue, method, host, deadline.c_time, queue.c_completion_queue, method, host_c_string, deadline.c_time,
NULL) NULL)
return operation_call return operation_call
def check_connectivity_state(self, bint try_to_connect):
return grpc.grpc_channel_check_connectivity_state(self.c_channel,
try_to_connect)
def watch_connectivity_state(
self, last_observed_state, records.Timespec deadline not None,
completion_queue.CompletionQueue queue not None, tag):
cdef records.OperationTag operation_tag = records.OperationTag(tag)
cpython.Py_INCREF(operation_tag)
grpc.grpc_channel_watch_connectivity_state(
self.c_channel, last_observed_state, deadline.c_time,
queue.c_completion_queue, <cpython.PyObject *>operation_tag)
def target(self):
cdef char * target = grpc.grpc_channel_get_target(self.c_channel)
result = <bytes>target
grpc.gpr_free(target)
return result
def __dealloc__(self): def __dealloc__(self):
if self.c_channel != NULL: if self.c_channel != NULL:
grpc.grpc_channel_destroy(self.c_channel) grpc.grpc_channel_destroy(self.c_channel)

@ -62,6 +62,8 @@ cdef class CompletionQueue:
cdef grpc.grpc_event event cdef grpc.grpc_event event
# Poll within a critical section # Poll within a critical section
# TODO consider making queue polling contention a hard error to enable
# easier bug discovery
with self.poll_condition: with self.poll_condition:
while self.is_polling: while self.is_polling:
self.poll_condition.wait(float(deadline) - time.time()) self.poll_condition.wait(float(deadline) - time.time())
@ -74,10 +76,12 @@ cdef class CompletionQueue:
self.poll_condition.notify() self.poll_condition.notify()
if event.type == grpc.GRPC_QUEUE_TIMEOUT: if event.type == grpc.GRPC_QUEUE_TIMEOUT:
return records.Event(event.type, False, None, None, None, None, None) return records.Event(
event.type, False, None, None, None, None, False, None)
elif event.type == grpc.GRPC_QUEUE_SHUTDOWN: elif event.type == grpc.GRPC_QUEUE_SHUTDOWN:
self.is_shutdown = True self.is_shutdown = True
return records.Event(event.type, True, None, None, None, None, None) return records.Event(
event.type, True, None, None, None, None, False, None)
else: else:
if event.tag != NULL: if event.tag != NULL:
tag = <records.OperationTag>event.tag tag = <records.OperationTag>event.tag
@ -97,7 +101,8 @@ cdef class CompletionQueue:
operation_call.references.extend(tag.references) operation_call.references.extend(tag.references)
return records.Event( return records.Event(
event.type, event.success, user_tag, operation_call, event.type, event.success, user_tag, operation_call,
request_call_details, request_metadata, batch_operations) request_call_details, request_metadata, tag.is_new_request,
batch_operations)
def shutdown(self): def shutdown(self):
grpc.grpc_completion_queue_shutdown(self.c_completion_queue) grpc.grpc_completion_queue_shutdown(self.c_completion_queue)

@ -27,7 +27,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cimport cpython
from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport grpc
from grpc._cython._cygrpc cimport records
cdef class ChannelCredentials: cdef class ChannelCredentials:
@ -49,3 +52,23 @@ cdef class ServerCredentials:
cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
cdef size_t c_ssl_pem_key_cert_pairs_count cdef size_t c_ssl_pem_key_cert_pairs_count
cdef list references cdef list references
cdef class CredentialsMetadataPlugin:
cdef object plugin_callback
cdef str plugin_name
cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self)
cdef class AuthMetadataContext:
cdef grpc.grpc_auth_metadata_context context
cdef void plugin_get_metadata(
void *state, grpc.grpc_auth_metadata_context context,
grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil
cdef void plugin_destroy_c_plugin_state(void *state)

@ -27,6 +27,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cimport cpython
from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport grpc
from grpc._cython._cygrpc cimport records from grpc._cython._cygrpc cimport records
@ -71,12 +73,73 @@ cdef class ServerCredentials:
def __cinit__(self): def __cinit__(self):
self.c_credentials = NULL self.c_credentials = NULL
self.references = []
def __dealloc__(self): def __dealloc__(self):
if self.c_credentials != NULL: if self.c_credentials != NULL:
grpc.grpc_server_credentials_release(self.c_credentials) grpc.grpc_server_credentials_release(self.c_credentials)
cdef class CredentialsMetadataPlugin:
def __cinit__(self, object plugin_callback, str name):
"""
Args:
plugin_callback (callable): Callback accepting a service URL (str/bytes)
and callback object (accepting a records.Metadata,
grpc.grpc_status_code, and a str/bytes error message). This argument
when called should be non-blocking and eventually call the callback
object with the appropriate status code/details and metadata (if
successful).
name (str): Plugin name.
"""
if not callable(plugin_callback):
raise ValueError('expected callable plugin_callback')
self.plugin_callback = plugin_callback
self.plugin_name = name
@staticmethod
cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self):
cdef grpc.grpc_metadata_credentials_plugin result
result.get_metadata = plugin_get_metadata
result.destroy = plugin_destroy_c_plugin_state
result.state = <void *>self
result.type = self.plugin_name
cpython.Py_INCREF(self)
return result
cdef class AuthMetadataContext:
def __cinit__(self):
self.context.service_url = NULL
self.context.method_name = NULL
@property
def service_url(self):
return self.context.service_url
@property
def method_name(self):
return self.context.method_name
cdef void plugin_get_metadata(
void *state, grpc.grpc_auth_metadata_context context,
grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
def python_callback(
records.Metadata metadata, grpc.grpc_status_code status,
const char *error_details):
cb(user_data, metadata.c_metadata_array.metadata,
metadata.c_metadata_array.count, status, error_details)
cdef CredentialsMetadataPlugin self = <CredentialsMetadataPlugin>state
cdef AuthMetadataContext cy_context = AuthMetadataContext()
cy_context.context = context
self.plugin_callback(cy_context, python_callback)
cdef void plugin_destroy_c_plugin_state(void *state):
cpython.Py_DECREF(<CredentialsMetadataPlugin>state)
def channel_credentials_google_default(): def channel_credentials_google_default():
cdef ChannelCredentials credentials = ChannelCredentials(); cdef ChannelCredentials credentials = ChannelCredentials();
credentials.c_credentials = grpc.grpc_google_default_credentials_create() credentials.c_credentials = grpc.grpc_google_default_credentials_create()
@ -104,6 +167,7 @@ def channel_credentials_ssl(pem_root_certificates,
else: else:
credentials.c_credentials = grpc.grpc_ssl_credentials_create( credentials.c_credentials = grpc.grpc_ssl_credentials_create(
c_pem_root_certificates, NULL, NULL) c_pem_root_certificates, NULL, NULL)
return credentials
def channel_credentials_composite( def channel_credentials_composite(
ChannelCredentials credentials_1 not None, ChannelCredentials credentials_1 not None,
@ -135,7 +199,6 @@ def call_credentials_google_compute_engine():
grpc.grpc_google_compute_engine_credentials_create(NULL)) grpc.grpc_google_compute_engine_credentials_create(NULL))
return credentials return credentials
#TODO rename to something like client_credentials_service_account_jwt_access.
def call_credentials_service_account_jwt_access( def call_credentials_service_account_jwt_access(
json_key, records.Timespec token_lifetime not None): json_key, records.Timespec token_lifetime not None):
if isinstance(json_key, bytes): if isinstance(json_key, bytes):
@ -184,14 +247,25 @@ def call_credentials_google_iam(authorization_token, authority_selector):
credentials.references.append(authority_selector) credentials.references.append(authority_selector)
return credentials return credentials
def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin):
cdef CallCredentials credentials = CallCredentials()
credentials.c_credentials = (
grpc.grpc_metadata_credentials_create_from_plugin(plugin.make_c_plugin(),
NULL))
# TODO(atash): the following held reference is *probably* never necessary
credentials.references.append(plugin)
return credentials
def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs, def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
bint force_client_auth): bint force_client_auth):
cdef char *c_pem_root_certs = NULL
if pem_root_certs is None: if pem_root_certs is None:
pass pass
elif isinstance(pem_root_certs, bytes): elif isinstance(pem_root_certs, bytes):
pass c_pem_root_certs = pem_root_certs
elif isinstance(pem_root_certs, basestring): elif isinstance(pem_root_certs, basestring):
pem_root_certs = pem_root_certs.encode() pem_root_certs = pem_root_certs.encode()
c_pem_root_certs = pem_root_certs
else: else:
raise TypeError("expected pem_root_certs to be str or bytes") raise TypeError("expected pem_root_certs to be str or bytes")
pem_key_cert_pairs = list(pem_key_cert_pairs) pem_key_cert_pairs = list(pem_key_cert_pairs)
@ -212,7 +286,7 @@ def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
credentials.c_ssl_pem_key_cert_pairs[i] = ( credentials.c_ssl_pem_key_cert_pairs[i] = (
(<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair) (<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
credentials.c_credentials = grpc.grpc_ssl_server_credentials_create( credentials.c_credentials = grpc.grpc_ssl_server_credentials_create(
pem_root_certs, credentials.c_ssl_pem_key_cert_pairs, c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
credentials.c_ssl_pem_key_cert_pairs_count, force_client_auth, NULL) credentials.c_ssl_pem_key_cert_pairs_count, force_client_auth, NULL)
return credentials return credentials

@ -132,6 +132,20 @@ cdef extern from "grpc/byte_buffer.h":
cdef extern from "grpc/grpc.h": cdef extern from "grpc/grpc.h":
const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
const char *GRPC_ARG_ENABLE_CENSUS
const char *GRPC_ARG_MAX_CONCURRENT_STREAMS
const char *GRPC_ARG_MAX_MESSAGE_LENGTH
const char *GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
const char *GRPC_ARG_DEFAULT_AUTHORITY
const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
const char *GRPC_ARG_SECONDARY_USER_AGENT_STRING
const char *GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
const int GRPC_WRITE_BUFFER_HINT
const int GRPC_WRITE_NO_COMPRESS
const int GRPC_WRITE_USED_MASK
ctypedef struct grpc_completion_queue: ctypedef struct grpc_completion_queue:
# We don't care about the internals (and in fact don't know them) # We don't care about the internals (and in fact don't know them)
pass pass
@ -149,9 +163,9 @@ cdef extern from "grpc/grpc.h":
pass pass
ctypedef enum grpc_arg_type: ctypedef enum grpc_arg_type:
grpc_arg_string "GRPC_ARG_STRING" GRPC_ARG_STRING
grpc_arg_integer "GRPC_ARG_INTEGER" GRPC_ARG_INTEGER
grpc_arg_pointer "GRPC_ARG_POINTER" GRPC_ARG_POINTER
ctypedef struct grpc_arg_value_pointer: ctypedef struct grpc_arg_value_pointer:
void *address "p" void *address "p"
@ -185,6 +199,13 @@ cdef extern from "grpc/grpc.h":
GRPC_CALL_ERROR_INVALID_FLAGS GRPC_CALL_ERROR_INVALID_FLAGS
GRPC_CALL_ERROR_INVALID_METADATA GRPC_CALL_ERROR_INVALID_METADATA
ctypedef enum grpc_connectivity_state:
GRPC_CHANNEL_IDLE
GRPC_CHANNEL_CONNECTING
GRPC_CHANNEL_READY
GRPC_CHANNEL_TRANSIENT_FAILURE
GRPC_CHANNEL_FATAL_FAILURE
ctypedef struct grpc_metadata: ctypedef struct grpc_metadata:
const char *key const char *key
const char *value const char *value
@ -279,9 +300,9 @@ cdef extern from "grpc/grpc.h":
grpc_status_code status, grpc_status_code status,
const char *description, const char *description,
void *reserved) void *reserved)
char *grpc_call_get_peer(grpc_call *call)
void grpc_call_destroy(grpc_call *call) void grpc_call_destroy(grpc_call *call)
grpc_channel *grpc_insecure_channel_create(const char *target, grpc_channel *grpc_insecure_channel_create(const char *target,
const grpc_channel_args *args, const grpc_channel_args *args,
void *reserved) void *reserved)
@ -291,6 +312,12 @@ cdef extern from "grpc/grpc.h":
grpc_completion_queue *completion_queue, grpc_completion_queue *completion_queue,
const char *method, const char *host, const char *method, const char *host,
gpr_timespec deadline, void *reserved) gpr_timespec deadline, void *reserved)
grpc_connectivity_state grpc_channel_check_connectivity_state(
grpc_channel *channel, int try_to_connect)
void grpc_channel_watch_connectivity_state(
grpc_channel *channel, grpc_connectivity_state last_observed_state,
gpr_timespec deadline, grpc_completion_queue *cq, void *tag)
char *grpc_channel_get_target(grpc_channel *channel)
void grpc_channel_destroy(grpc_channel *channel) void grpc_channel_destroy(grpc_channel *channel)
grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved)
@ -367,3 +394,27 @@ cdef extern from "grpc/grpc_security.h":
grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_call_error grpc_call_set_credentials(grpc_call *call,
grpc_call_credentials *creds) grpc_call_credentials *creds)
ctypedef struct grpc_auth_context:
# We don't care about the internals (and in fact don't know them)
pass
ctypedef struct grpc_auth_metadata_context:
const char *service_url
const char *method_name
const grpc_auth_context *channel_auth_context
ctypedef void (*grpc_credentials_plugin_metadata_cb)(
void *user_data, const grpc_metadata *creds_md, size_t num_creds_md,
grpc_status_code status, const char *error_details)
ctypedef struct grpc_metadata_credentials_plugin:
void (*get_metadata)(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data)
void (*destroy)(void *state)
void *state
const char *type
grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin, void *reserved)

@ -66,6 +66,7 @@ cdef class Event:
cdef readonly call.Call operation_call cdef readonly call.Call operation_call
# For Server.request_call # For Server.request_call
cdef readonly bint is_new_request
cdef readonly CallDetails request_call_details cdef readonly CallDetails request_call_details
cdef readonly Metadata request_metadata cdef readonly Metadata request_metadata

@ -32,6 +32,30 @@ from grpc._cython._cygrpc cimport call
from grpc._cython._cygrpc cimport server from grpc._cython._cygrpc cimport server
class ConnectivityState:
idle = grpc.GRPC_CHANNEL_IDLE
connecting = grpc.GRPC_CHANNEL_CONNECTING
ready = grpc.GRPC_CHANNEL_READY
transient_failure = grpc.GRPC_CHANNEL_TRANSIENT_FAILURE
fatal_failure = grpc.GRPC_CHANNEL_FATAL_FAILURE
class ChannelArgKey:
enable_census = grpc.GRPC_ARG_ENABLE_CENSUS
max_concurrent_streams = grpc.GRPC_ARG_MAX_CONCURRENT_STREAMS
max_message_length = grpc.GRPC_ARG_MAX_MESSAGE_LENGTH
http2_initial_sequence_number = grpc.GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
default_authority = grpc.GRPC_ARG_DEFAULT_AUTHORITY
primary_user_agent_string = grpc.GRPC_ARG_PRIMARY_USER_AGENT_STRING
secondary_user_agent_string = grpc.GRPC_ARG_SECONDARY_USER_AGENT_STRING
ssl_target_name_override = grpc.GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
class WriteFlag:
buffer_hint = grpc.GRPC_WRITE_BUFFER_HINT
no_compress = grpc.GRPC_WRITE_NO_COMPRESS
class StatusCode: class StatusCode:
ok = grpc.GRPC_STATUS_OK ok = grpc.GRPC_STATUS_OK
cancelled = grpc.GRPC_STATUS_CANCELLED cancelled = grpc.GRPC_STATUS_CANCELLED
@ -88,7 +112,10 @@ cdef class Timespec:
def __cinit__(self, time): def __cinit__(self, time):
if time is None: if time is None:
self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME) self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME)
elif isinstance(time, float): return
if isinstance(time, int):
time = float(time)
if isinstance(time, float):
if time == float("+inf"): if time == float("+inf"):
self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME) self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME)
elif time == float("-inf"): elif time == float("-inf"):
@ -97,8 +124,11 @@ cdef class Timespec:
self.c_time.seconds = time self.c_time.seconds = time
self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9 self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9
self.c_time.clock_type = grpc.GPR_CLOCK_REALTIME self.c_time.clock_type = grpc.GPR_CLOCK_REALTIME
elif isinstance(time, Timespec):
self.c_time = (<Timespec>time).c_time
else: else:
raise TypeError("expected time to be float") raise TypeError("expected time to be float, int, or Timespec, not {}"
.format(type(time)))
@property @property
def seconds(self): def seconds(self):
@ -166,6 +196,7 @@ cdef class Event:
object tag, call.Call operation_call, object tag, call.Call operation_call,
CallDetails request_call_details, CallDetails request_call_details,
Metadata request_metadata, Metadata request_metadata,
bint is_new_request,
Operations batch_operations): Operations batch_operations):
self.type = type self.type = type
self.success = success self.success = success
@ -174,6 +205,7 @@ cdef class Event:
self.request_call_details = request_call_details self.request_call_details = request_call_details
self.request_metadata = request_metadata self.request_metadata = request_metadata
self.batch_operations = batch_operations self.batch_operations = batch_operations
self.is_new_request = is_new_request
cdef class ByteBuffer: cdef class ByteBuffer:
@ -186,8 +218,14 @@ cdef class ByteBuffer:
pass pass
elif isinstance(data, basestring): elif isinstance(data, basestring):
data = data.encode() data = data.encode()
elif isinstance(data, ByteBuffer):
data = (<ByteBuffer>data).bytes()
if data is None:
self.c_byte_buffer = NULL
return
else: else:
raise TypeError("expected value to be of type str or bytes") raise TypeError("expected value to be of type str, bytes, or "
"ByteBuffer, not {}".format(type(data)))
cdef char *c_data = data cdef char *c_data = data
data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data)) data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data))
@ -409,12 +447,22 @@ cdef class Operation:
def type(self): def type(self):
return self.c_op.type return self.c_op.type
@property
def has_status(self):
return self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
@property @property
def received_message(self): def received_message(self):
if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE: if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
raise TypeError("self must be an operation receiving a message") raise TypeError("self must be an operation receiving a message")
return self._received_message return self._received_message
@property
def received_message_or_none(self):
if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
return None
return self._received_message
@property @property
def received_metadata(self): def received_metadata(self):
if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
@ -422,12 +470,25 @@ cdef class Operation:
raise TypeError("self must be an operation receiving metadata") raise TypeError("self must be an operation receiving metadata")
return self._received_metadata return self._received_metadata
@property
def received_metadata_or_none(self):
if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
return None
return self._received_metadata
@property @property
def received_status_code(self): def received_status_code(self):
if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
raise TypeError("self must be an operation receiving a status code") raise TypeError("self must be an operation receiving a status code")
return self._received_status_code return self._received_status_code
@property
def received_status_code_or_none(self):
if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
return None
return self._received_status_code
@property @property
def received_status_details(self): def received_status_details(self):
if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
@ -437,6 +498,15 @@ cdef class Operation:
else: else:
return None return None
@property
def received_status_details_or_none(self):
if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
return None
if self._received_status_details:
return self._received_status_details
else:
return None
@property @property
def received_cancelled(self): def received_cancelled(self):
if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER: if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
@ -444,6 +514,12 @@ cdef class Operation:
"information") "information")
return False if self._received_cancelled == 0 else True return False if self._received_cancelled == 0 else True
@property
def received_cancelled_or_none(self):
if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
return None
return False if self._received_cancelled == 0 else True
def __dealloc__(self): def __dealloc__(self):
# We *almost* don't need to do anything; most of the objects are handled by # We *almost* don't need to do anything; most of the objects are handled by
# Python. The remaining one(s) are primitive fields filled in by GRPC core. # Python. The remaining one(s) are primitive fields filled in by GRPC core.

@ -132,7 +132,7 @@ cdef class Server:
def cancel_all_calls(self): def cancel_all_calls(self):
if not self.is_shutting_down: if not self.is_shutting_down:
raise ValueError("the server must be shutting down to cancel all calls") raise RuntimeError("the server must be shutting down to cancel all calls")
elif self.is_shutdown: elif self.is_shutdown:
return return
else: else:

@ -1,102 +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.
# Adapter from grpc._cython.types to the surface expected by
# grpc._adapter._intermediary_low.
#
# TODO(atash): Once this is plugged into grpc._adapter._intermediary_low, remove
# both grpc._adapter._intermediary_low and this file. The fore and rear links in
# grpc._adapter should be able to use grpc._cython.types directly.
from grpc._adapter import _types as type_interfaces
from grpc._cython import cygrpc
class ClientCredentials(object):
def __init__(self):
raise NotImplementedError()
@staticmethod
def google_default():
raise NotImplementedError()
@staticmethod
def ssl():
raise NotImplementedError()
@staticmethod
def composite():
raise NotImplementedError()
@staticmethod
def compute_engine():
raise NotImplementedError()
@staticmethod
def jwt():
raise NotImplementedError()
@staticmethod
def refresh_token():
raise NotImplementedError()
@staticmethod
def iam():
raise NotImplementedError()
class ServerCredentials(object):
def __init__(self):
raise NotImplementedError()
@staticmethod
def ssl():
raise NotImplementedError()
class CompletionQueue(type_interfaces.CompletionQueue):
def __init__(self):
raise NotImplementedError()
class Call(type_interfaces.Call):
def __init__(self):
raise NotImplementedError()
class Channel(type_interfaces.Channel):
def __init__(self):
raise NotImplementedError()
class Server(type_interfaces.Server):
def __init__(self):
raise NotImplementedError()

@ -44,6 +44,9 @@ from grpc._cython._cygrpc import completion_queue
from grpc._cython._cygrpc import records from grpc._cython._cygrpc import records
from grpc._cython._cygrpc import server from grpc._cython._cygrpc import server
ConnectivityState = records.ConnectivityState
ChannelArgKey = records.ChannelArgKey
WriteFlag = records.WriteFlag
StatusCode = records.StatusCode StatusCode = records.StatusCode
CallError = records.CallError CallError = records.CallError
CompletionType = records.CompletionType CompletionType = records.CompletionType
@ -73,6 +76,8 @@ Operations = records.Operations
CallCredentials = credentials.CallCredentials CallCredentials = credentials.CallCredentials
ChannelCredentials = credentials.ChannelCredentials ChannelCredentials = credentials.ChannelCredentials
ServerCredentials = credentials.ServerCredentials ServerCredentials = credentials.ServerCredentials
CredentialsMetadataPlugin = credentials.CredentialsMetadataPlugin
AuthMetadataContext = credentials.AuthMetadataContext
channel_credentials_google_default = ( channel_credentials_google_default = (
credentials.channel_credentials_google_default) credentials.channel_credentials_google_default)
@ -88,6 +93,7 @@ call_credentials_jwt_access = (
call_credentials_refresh_token = ( call_credentials_refresh_token = (
credentials.call_credentials_google_refresh_token) credentials.call_credentials_google_refresh_token)
call_credentials_google_iam = credentials.call_credentials_google_iam call_credentials_google_iam = credentials.call_credentials_google_iam
call_credentials_metadata_plugin = credentials.call_credentials_metadata_plugin
server_credentials_ssl = credentials.server_credentials_ssl server_credentials_ssl = credentials.server_credentials_ssl
CompletionQueue = completion_queue.CompletionQueue CompletionQueue = completion_queue.CompletionQueue

@ -182,15 +182,15 @@ class _Kernel(object):
def _on_finish_event(self, operation_id, event, rpc_state): def _on_finish_event(self, operation_id, event, rpc_state):
_no_longer_due(_FINISH, rpc_state, operation_id, self._rpc_states) _no_longer_due(_FINISH, rpc_state, operation_id, self._rpc_states)
if event.status.code is _intermediary_low.Code.OK: if event.status.code == _intermediary_low.Code.OK:
termination = links.Ticket.Termination.COMPLETION termination = links.Ticket.Termination.COMPLETION
elif event.status.code is _intermediary_low.Code.CANCELLED: elif event.status.code == _intermediary_low.Code.CANCELLED:
termination = links.Ticket.Termination.CANCELLATION termination = links.Ticket.Termination.CANCELLATION
elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED: elif event.status.code == _intermediary_low.Code.DEADLINE_EXCEEDED:
termination = links.Ticket.Termination.EXPIRATION termination = links.Ticket.Termination.EXPIRATION
elif event.status.code is _intermediary_low.Code.UNIMPLEMENTED: elif event.status.code == _intermediary_low.Code.UNIMPLEMENTED:
termination = links.Ticket.Termination.REMOTE_FAILURE termination = links.Ticket.Termination.REMOTE_FAILURE
elif event.status.code is _intermediary_low.Code.UNKNOWN: elif event.status.code == _intermediary_low.Code.UNKNOWN:
termination = links.Ticket.Termination.LOCAL_FAILURE termination = links.Ticket.Termination.LOCAL_FAILURE
else: else:
termination = links.Ticket.Termination.TRANSMISSION_FAILURE termination = links.Ticket.Termination.TRANSMISSION_FAILURE
@ -262,7 +262,7 @@ class _Kernel(object):
self._channel, self._completion_queue, '/%s/%s' % (group, method), self._channel, self._completion_queue, '/%s/%s' % (group, method),
self._host, time.time() + timeout) self._host, time.time() + timeout)
if options is not None and options.credentials is not None: if options is not None and options.credentials is not None:
call.set_credentials(options.credentials._intermediary_low_credentials) call.set_credentials(options.credentials._low_credentials)
if transformed_initial_metadata is not None: if transformed_initial_metadata is not None:
for metadata_key, metadata_value in transformed_initial_metadata: for metadata_key, metadata_value in transformed_initial_metadata:
call.add_metadata(metadata_key, metadata_value) call.add_metadata(metadata_key, metadata_value)

@ -254,12 +254,12 @@ class _Kernel(object):
rpc_state = self._rpc_states[call] rpc_state = self._rpc_states[call]
_no_longer_due(_FINISH, rpc_state, call, self._rpc_states) _no_longer_due(_FINISH, rpc_state, call, self._rpc_states)
code = event.status.code code = event.status.code
if code is _intermediary_low.Code.OK: if code == _intermediary_low.Code.OK:
return return
if code is _intermediary_low.Code.CANCELLED: if code == _intermediary_low.Code.CANCELLED:
termination = links.Ticket.Termination.CANCELLATION termination = links.Ticket.Termination.CANCELLATION
elif code is _intermediary_low.Code.DEADLINE_EXCEEDED: elif code == _intermediary_low.Code.DEADLINE_EXCEEDED:
termination = links.Ticket.Termination.EXPIRATION termination = links.Ticket.Termination.EXPIRATION
else: else:
termination = links.Ticket.Termination.TRANSMISSION_FAILURE termination = links.Ticket.Termination.TRANSMISSION_FAILURE

@ -170,7 +170,7 @@ class _Server(interfaces.Server):
with self._lock: with self._lock:
if self._end_link is None: if self._end_link is None:
return self._grpc_link.add_port( return self._grpc_link.add_port(
address, server_credentials._intermediary_low_credentials) # pylint: disable=protected-access address, server_credentials._low_credentials) # pylint: disable=protected-access
else: else:
raise ValueError('Can\'t add port to serving server!') raise ValueError('Can\'t add port to serving server!')

@ -36,6 +36,7 @@ import threading # pylint: disable=unused-import
# cardinality and face are referenced from specification in this module. # cardinality and face are referenced from specification in this module.
from grpc._adapter import _intermediary_low from grpc._adapter import _intermediary_low
from grpc._adapter import _low
from grpc._adapter import _types from grpc._adapter import _types
from grpc.beta import _connectivity_channel from grpc.beta import _connectivity_channel
from grpc.beta import _server from grpc.beta import _server
@ -48,7 +49,7 @@ _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
'Exception calling channel subscription callback!') 'Exception calling channel subscription callback!')
class ClientCredentials(object): class ChannelCredentials(object):
"""A value encapsulating the data required to create a secure Channel. """A value encapsulating the data required to create a secure Channel.
This class and its instances have no supported interface - it exists to define This class and its instances have no supported interface - it exists to define
@ -56,13 +57,12 @@ class ClientCredentials(object):
functions. functions.
""" """
def __init__(self, low_credentials, intermediary_low_credentials): def __init__(self, low_credentials):
self._low_credentials = low_credentials self._low_credentials = low_credentials
self._intermediary_low_credentials = intermediary_low_credentials
def ssl_client_credentials(root_certificates, private_key, certificate_chain): def ssl_channel_credentials(root_certificates, private_key, certificate_chain):
"""Creates a ClientCredentials for use with an SSL-enabled Channel. """Creates a ChannelCredentials for use with an SSL-enabled Channel.
Args: Args:
root_certificates: The PEM-encoded root certificates or None to ask for root_certificates: The PEM-encoded root certificates or None to ask for
@ -73,12 +73,73 @@ def ssl_client_credentials(root_certificates, private_key, certificate_chain):
certificate chain should be used. certificate chain should be used.
Returns: Returns:
A ClientCredentials for use with an SSL-enabled Channel. A ChannelCredentials for use with an SSL-enabled Channel.
""" """
intermediary_low_credentials = _intermediary_low.ClientCredentials( return ChannelCredentials(_low.channel_credentials_ssl(
root_certificates, private_key, certificate_chain) root_certificates, private_key, certificate_chain))
return ClientCredentials(
intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access
class CallCredentials(object):
"""A value encapsulating data asserting an identity over an *established*
channel. May be composed with ChannelCredentials to always assert identity for
every call over that channel.
This class and its instances have no supported interface - it exists to define
the type of its instances and its instances exist to be passed to other
functions.
"""
def __init__(self, low_credentials):
self._low_credentials = low_credentials
def metadata_call_credentials(metadata_plugin, name=None):
"""Construct CallCredentials from an interfaces.GRPCAuthMetadataPlugin.
Args:
metadata_plugin: An interfaces.GRPCAuthMetadataPlugin to use in constructing
the CallCredentials object.
Returns:
A CallCredentials object for use in a GRPCCallOptions object.
"""
if name is None:
name = metadata_plugin.__name__
return CallCredentials(
_low.call_credentials_metadata_plugin(metadata_plugin, name))
def composite_call_credentials(call_credentials, additional_call_credentials):
"""Compose two CallCredentials to make a new one.
Args:
call_credentials: A CallCredentials object.
additional_call_credentials: Another CallCredentials object to compose on
top of call_credentials.
Returns:
A CallCredentials object for use in a GRPCCallOptions object.
"""
return CallCredentials(
_low.call_credentials_composite(
call_credentials._low_credentials,
additional_call_credentials._low_credentials))
def composite_channel_credentials(channel_credentials,
additional_call_credentials):
"""Compose ChannelCredentials on top of client credentials to make a new one.
Args:
channel_credentials: A ChannelCredentials object.
additional_call_credentials: A CallCredentials object to compose on
top of channel_credentials.
Returns:
A ChannelCredentials object for use in a GRPCCallOptions object.
"""
return ChannelCredentials(
_low.channel_credentials_composite(
channel_credentials._low_credentials,
additional_call_credentials._low_credentials))
class Channel(object): class Channel(object):
@ -135,19 +196,19 @@ def insecure_channel(host, port):
return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
def secure_channel(host, port, client_credentials): def secure_channel(host, port, channel_credentials):
"""Creates a secure Channel to a remote host. """Creates a secure Channel to a remote host.
Args: Args:
host: The name of the remote host to which to connect. host: The name of the remote host to which to connect.
port: The port of the remote host to which to connect. port: The port of the remote host to which to connect.
client_credentials: A ClientCredentials. channel_credentials: A ChannelCredentials.
Returns: Returns:
A secure Channel to the remote host through which RPCs may be conducted. A secure Channel to the remote host through which RPCs may be conducted.
""" """
intermediary_low_channel = _intermediary_low.Channel( intermediary_low_channel = _intermediary_low.Channel(
'%s:%d' % (host, port), client_credentials._intermediary_low_credentials) '%s:%d' % (host, port), channel_credentials._low_credentials)
return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
@ -251,9 +312,8 @@ class ServerCredentials(object):
functions. functions.
""" """
def __init__(self, low_credentials, intermediary_low_credentials): def __init__(self, low_credentials):
self._low_credentials = low_credentials self._low_credentials = low_credentials
self._intermediary_low_credentials = intermediary_low_credentials
def ssl_server_credentials( def ssl_server_credentials(
@ -282,11 +342,9 @@ def ssl_server_credentials(
raise ValueError( raise ValueError(
'Illegal to require client auth without providing root certificates!') 'Illegal to require client auth without providing root certificates!')
else: else:
intermediary_low_credentials = _intermediary_low.ServerCredentials( return ServerCredentials(_low.server_credentials_ssl(
root_certificates, private_key_certificate_chain_pairs, root_certificates, private_key_certificate_chain_pairs,
require_client_auth) require_client_auth))
return ServerCredentials(
intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access
class ServerOptions(object): class ServerOptions(object):

@ -100,14 +100,55 @@ def grpc_call_options(disable_compression=False, credentials=None):
disable_compression: A boolean indicating whether or not compression should disable_compression: A boolean indicating whether or not compression should
be disabled for the request object of the RPC. Only valid for be disabled for the request object of the RPC. Only valid for
request-unary RPCs. request-unary RPCs.
credentials: Reserved for gRPC per-call credentials. The type for this does credentials: A CallCredentials object to use for the invoked RPC.
not exist yet at the Python level.
""" """
if credentials is not None:
raise ValueError('`credentials` is a reserved argument')
return GRPCCallOptions(disable_compression, None, credentials) return GRPCCallOptions(disable_compression, None, credentials)
class GRPCAuthMetadataContext(object):
"""Provides information to call credentials metadata plugins.
Attributes:
service_url: A string URL of the service being called into.
method_name: A string of the fully qualified method name being called.
"""
__metaclass__ = abc.ABCMeta
class GRPCAuthMetadataPluginCallback(object):
"""Callback object received by a metadata plugin."""
__metaclass__ = abc.ABCMeta
def __call__(self, metadata, error):
"""Inform the gRPC runtime of the metadata to construct a CallCredentials.
Args:
metadata: An iterable of 2-sequences (e.g. tuples) of metadata key/value
pairs.
error: An Exception to indicate error or None to indicate success.
"""
raise NotImplementedError()
class GRPCAuthMetadataPlugin(object):
"""
"""
__metaclass__ = abc.ABCMeta
def __call__(self, context, callback):
"""Invoke the plugin.
Must not block. Need only be called by the gRPC runtime.
Args:
context: A GRPCAuthMetadataContext providing information on what the
plugin is being used for.
callback: A GRPCAuthMetadataPluginCallback to be invoked either
synchronously or asynchronously.
"""
raise NotImplementedError()
class GRPCServicerContext(object): class GRPCServicerContext(object):
"""Exposes gRPC-specific options and behaviors to code servicing RPCs.""" """Exposes gRPC-specific options and behaviors to code servicing RPCs."""
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta

@ -57,19 +57,6 @@ ENABLE_CYTHON_TRACING = os.environ.get(
# the installation. # the installation.
INSTALL_TESTS = os.environ.get('GRPC_PYTHON_INSTALL_TESTS', False) INSTALL_TESTS = os.environ.get('GRPC_PYTHON_INSTALL_TESTS', False)
C_EXTENSION_SOURCES = (
'grpc/_adapter/_c/module.c',
'grpc/_adapter/_c/types.c',
'grpc/_adapter/_c/utility.c',
'grpc/_adapter/_c/types/call_credentials.c',
'grpc/_adapter/_c/types/channel_credentials.c',
'grpc/_adapter/_c/types/server_credentials.c',
'grpc/_adapter/_c/types/completion_queue.c',
'grpc/_adapter/_c/types/call.c',
'grpc/_adapter/_c/types/channel.c',
'grpc/_adapter/_c/types/server.c',
)
CYTHON_EXTENSION_PACKAGE_NAMES = () CYTHON_EXTENSION_PACKAGE_NAMES = ()
CYTHON_EXTENSION_MODULE_NAMES = ( CYTHON_EXTENSION_MODULE_NAMES = (
@ -94,14 +81,6 @@ if not "darwin" in sys.platform:
EXTENSION_LIBRARIES += ('rt',) EXTENSION_LIBRARIES += ('rt',)
C_EXTENSION_MODULE = _core.Extension(
'grpc._adapter._c', sources=list(C_EXTENSION_SOURCES),
include_dirs=list(EXTENSION_INCLUDE_DIRECTORIES),
libraries=list(EXTENSION_LIBRARIES)
)
EXTENSION_MODULES = [C_EXTENSION_MODULE]
def cython_extensions(package_names, module_names, include_dirs, libraries, def cython_extensions(package_names, module_names, include_dirs, libraries,
build_with_cython=False): build_with_cython=False):
file_extension = 'pyx' if build_with_cython else 'c' file_extension = 'pyx' if build_with_cython else 'c'
@ -185,7 +164,7 @@ else:
setuptools.setup( setuptools.setup(
name='grpcio', name='grpcio',
version='0.11.0b2', version='0.11.0b2',
ext_modules=EXTENSION_MODULES + CYTHON_EXTENSION_MODULES, ext_modules=CYTHON_EXTENSION_MODULES,
packages=list(PACKAGES), packages=list(PACKAGES),
package_dir=PACKAGE_DIRECTORIES, package_dir=PACKAGE_DIRECTORIES,
install_requires=INSTALL_REQUIRES, install_requires=INSTALL_REQUIRES,

@ -55,7 +55,7 @@ class SecureInteropTest(
self.server.start() self.server.start()
self.stub = test_pb2.beta_create_TestService_stub( self.stub = test_pb2.beta_create_TestService_stub(
test_utilities.not_really_secure_channel( test_utilities.not_really_secure_channel(
'[::]', port, implementations.ssl_client_credentials( '[::]', port, implementations.ssl_channel_credentials(
resources.test_root_certificates(), None, None), resources.test_root_certificates(), None, None),
_SERVER_HOST_OVERRIDE)) _SERVER_HOST_OVERRIDE))

@ -94,7 +94,7 @@ def _stub(args):
channel = test_utilities.not_really_secure_channel( channel = test_utilities.not_really_secure_channel(
args.server_host, args.server_port, args.server_host, args.server_port,
implementations.ssl_client_credentials(root_certificates, None, None), implementations.ssl_channel_credentials(root_certificates, None, None),
args.server_host_override) args.server_host_override)
stub = test_pb2.beta_create_TestService_stub( stub = test_pb2.beta_create_TestService_stub(
channel, metadata_transformer=metadata_transformer) channel, metadata_transformer=metadata_transformer)

@ -115,6 +115,7 @@ class EchoTest(unittest.TestCase):
def tearDown(self): def tearDown(self):
self.server.stop() self.server.stop()
self.server.cancel_all_calls()
self.server_completion_queue.stop() self.server_completion_queue.stop()
self.client_completion_queue.stop() self.client_completion_queue.stop()
self.server_completion_queue_thread.join() self.server_completion_queue_thread.join()
@ -286,11 +287,6 @@ class EchoTest(unittest.TestCase):
set((server_trailing_metadata_key, set((server_trailing_metadata_key,
server_trailing_binary_metadata_key,))) 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, server_data)
self.assertSequenceEqual(test_data, client_data) self.assertSequenceEqual(test_data, client_data)
@ -335,6 +331,7 @@ class CancellationTest(unittest.TestCase):
def tearDown(self): def tearDown(self):
self.server.stop() self.server.stop()
self.server.cancel_all_calls()
self.server_completion_queue.stop() self.server_completion_queue.stop()
self.client_completion_queue.stop() self.client_completion_queue.stop()
self.server_completion_queue_thread.join() self.server_completion_queue_thread.join()
@ -413,11 +410,6 @@ class CancellationTest(unittest.TestCase):
self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'), self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
finish_event.status) 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, server_data)
self.assertSequenceEqual(test_data, client_data) self.assertSequenceEqual(test_data, client_data)

@ -80,11 +80,11 @@ class InsecureServerInsecureClient(unittest.TestCase):
del self.client_channel del self.client_channel
self.client_completion_queue.shutdown() self.client_completion_queue.shutdown()
while (self.client_completion_queue.next().type != while (self.client_completion_queue.next(float('+inf')).type !=
_types.EventType.QUEUE_SHUTDOWN): _types.EventType.QUEUE_SHUTDOWN):
pass pass
self.server_completion_queue.shutdown() self.server_completion_queue.shutdown()
while (self.server_completion_queue.next().type != while (self.server_completion_queue.next(float('+inf')).type !=
_types.EventType.QUEUE_SHUTDOWN): _types.EventType.QUEUE_SHUTDOWN):
pass pass
@ -294,8 +294,12 @@ class HangingServerShutdown(unittest.TestCase):
# Now try to shutdown the server and expect that we see server shutdown # Now try to shutdown the server and expect that we see server shutdown
# almost immediately after calling cancel_all_calls. # almost immediately after calling cancel_all_calls.
# First attempt to cancel all calls before shutting down, and expect
# our state machine to catch the erroneous API use.
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
self.server.cancel_all_calls() self.server.cancel_all_calls()
shutdown_tag = object() shutdown_tag = object()
self.server.shutdown(shutdown_tag) self.server.shutdown(shutdown_tag)
pre_cancel_timestamp = time.time() pre_cancel_timestamp = time.time()

@ -1,187 +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.
# Fork of grpc._adapter._low_test; the grpc._cython.types adapter in
# grpc._cython.low should transparently support the semantics expected of
# grpc._adapter._low.
import time
import unittest
from grpc._adapter import _types
from grpc._cython import adapter_low as _low
class InsecureServerInsecureClient(unittest.TestCase):
def setUp(self):
self.server_completion_queue = _low.CompletionQueue()
self.server = _low.Server(self.server_completion_queue, [])
self.port = self.server.add_http2_port('[::]:0')
self.client_completion_queue = _low.CompletionQueue()
self.client_channel = _low.Channel('localhost:%d'%self.port, [])
self.server.start()
def tearDown(self):
self.server.shutdown()
del self.client_channel
self.client_completion_queue.shutdown()
while (self.client_completion_queue.next().type !=
_types.EventType.QUEUE_SHUTDOWN):
pass
self.server_completion_queue.shutdown()
while (self.server_completion_queue.next().type !=
_types.EventType.QUEUE_SHUTDOWN):
pass
del self.client_completion_queue
del self.server_completion_queue
del self.server
@unittest.skip('TODO(atash): implement grpc._cython.adapter_low')
def testEcho(self):
DEADLINE = time.time()+5
DEADLINE_TOLERANCE = 0.25
CLIENT_METADATA_ASCII_KEY = 'key'
CLIENT_METADATA_ASCII_VALUE = 'val'
CLIENT_METADATA_BIN_KEY = 'key-bin'
CLIENT_METADATA_BIN_VALUE = b'\0'*1000
SERVER_INITIAL_METADATA_KEY = 'init_me_me_me'
SERVER_INITIAL_METADATA_VALUE = 'whodawha?'
SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought'
SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
SERVER_STATUS_CODE = _types.StatusCode.OK
SERVER_STATUS_DETAILS = 'our work is never over'
REQUEST = 'in death a member of project mayhem has a name'
RESPONSE = 'his name is robert paulson'
METHOD = 'twinkies'
HOST = 'hostess'
server_request_tag = object()
request_call_result = self.server.request_call(self.server_completion_queue,
server_request_tag)
self.assertEqual(_types.CallError.OK, request_call_result)
client_call_tag = object()
client_call = self.client_channel.create_call(self.client_completion_queue,
METHOD, HOST, DEADLINE)
client_initial_metadata = [
(CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE),
(CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)]
client_start_batch_result = client_call.start_batch([
_types.OpArgs.send_initial_metadata(client_initial_metadata),
_types.OpArgs.send_message(REQUEST),
_types.OpArgs.send_close_from_client(),
_types.OpArgs.recv_initial_metadata(),
_types.OpArgs.recv_message(),
_types.OpArgs.recv_status_on_client()
], client_call_tag)
self.assertEqual(_types.CallError.OK, client_start_batch_result)
request_event = self.server_completion_queue.next(DEADLINE)
self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type)
self.assertIsInstance(request_event.call, _low.Call)
self.assertIs(server_request_tag, request_event.tag)
self.assertEqual(1, len(request_event.results))
self.assertEqual(dict(client_initial_metadata),
dict(request_event.results[0].initial_metadata))
self.assertEqual(METHOD, request_event.call_details.method)
self.assertEqual(HOST, request_event.call_details.host)
self.assertLess(abs(DEADLINE - request_event.call_details.deadline),
DEADLINE_TOLERANCE)
server_call_tag = object()
server_call = request_event.call
server_initial_metadata = [
(SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)]
server_trailing_metadata = [
(SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)]
server_start_batch_result = server_call.start_batch([
_types.OpArgs.send_initial_metadata(server_initial_metadata),
_types.OpArgs.recv_message(),
_types.OpArgs.send_message(RESPONSE),
_types.OpArgs.recv_close_on_server(),
_types.OpArgs.send_status_from_server(
server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
], server_call_tag)
self.assertEqual(_types.CallError.OK, server_start_batch_result)
client_event = self.client_completion_queue.next(DEADLINE)
server_event = self.server_completion_queue.next(DEADLINE)
self.assertEqual(6, len(client_event.results))
found_client_op_types = set()
for client_result in client_event.results:
# we expect each op type to be unique
self.assertNotIn(client_result.type, found_client_op_types)
found_client_op_types.add(client_result.type)
if client_result.type == _types.OpType.RECV_INITIAL_METADATA:
self.assertEqual(dict(server_initial_metadata),
dict(client_result.initial_metadata))
elif client_result.type == _types.OpType.RECV_MESSAGE:
self.assertEqual(RESPONSE, client_result.message)
elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT:
self.assertEqual(dict(server_trailing_metadata),
dict(client_result.trailing_metadata))
self.assertEqual(SERVER_STATUS_DETAILS, client_result.status.details)
self.assertEqual(SERVER_STATUS_CODE, client_result.status.code)
self.assertEqual(set([
_types.OpType.SEND_INITIAL_METADATA,
_types.OpType.SEND_MESSAGE,
_types.OpType.SEND_CLOSE_FROM_CLIENT,
_types.OpType.RECV_INITIAL_METADATA,
_types.OpType.RECV_MESSAGE,
_types.OpType.RECV_STATUS_ON_CLIENT
]), found_client_op_types)
self.assertEqual(5, len(server_event.results))
found_server_op_types = set()
for server_result in server_event.results:
self.assertNotIn(client_result.type, found_server_op_types)
found_server_op_types.add(server_result.type)
if server_result.type == _types.OpType.RECV_MESSAGE:
self.assertEqual(REQUEST, server_result.message)
elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER:
self.assertFalse(server_result.cancelled)
self.assertEqual(set([
_types.OpType.SEND_INITIAL_METADATA,
_types.OpType.RECV_MESSAGE,
_types.OpType.SEND_MESSAGE,
_types.OpType.RECV_CLOSE_ON_SERVER,
_types.OpType.SEND_STATUS_FROM_SERVER
]), found_server_op_types)
del client_call
del server_call
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -28,11 +28,24 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time import time
import threading
import unittest import unittest
from grpc._cython import cygrpc from grpc._cython import cygrpc
from tests.unit._cython import test_utilities from tests.unit._cython import test_utilities
from tests.unit import test_common from tests.unit import test_common
from tests.unit import resources
_SSL_HOST_OVERRIDE = 'foo.test.google.fr'
_CALL_CREDENTIALS_METADATA_KEY = 'call-creds-key'
_CALL_CREDENTIALS_METADATA_VALUE = 'call-creds-value'
def _metadata_plugin_callback(context, callback):
callback(cygrpc.Metadata(
[cygrpc.Metadatum(_CALL_CREDENTIALS_METADATA_KEY,
_CALL_CREDENTIALS_METADATA_VALUE)]),
cygrpc.StatusCode.ok, '')
class TypeSmokeTest(unittest.TestCase): class TypeSmokeTest(unittest.TestCase):
@ -89,7 +102,17 @@ class TypeSmokeTest(unittest.TestCase):
channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([])) channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([]))
del channel del channel
@unittest.skip('TODO(atash): undo skip after #2229 is merged') def testCredentialsMetadataPluginUpDown(self):
plugin = cygrpc.CredentialsMetadataPlugin(
lambda ignored_a, ignored_b: None, '')
del plugin
def testCallCredentialsFromPluginUpDown(self):
plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '')
call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
del plugin
del call_credentials
def testServerStartNoExplicitShutdown(self): def testServerStartNoExplicitShutdown(self):
server = cygrpc.Server() server = cygrpc.Server()
completion_queue = cygrpc.CompletionQueue() completion_queue = cygrpc.CompletionQueue()
@ -99,7 +122,6 @@ class TypeSmokeTest(unittest.TestCase):
server.start() server.start()
del server del server
@unittest.skip('TODO(atash): undo skip after #2229 is merged')
def testServerStartShutdown(self): def testServerStartShutdown(self):
completion_queue = cygrpc.CompletionQueue() completion_queue = cygrpc.CompletionQueue()
server = cygrpc.Server() server = cygrpc.Server()
@ -262,5 +284,169 @@ class InsecureServerInsecureClient(unittest.TestCase):
del server_call del server_call
class SecureServerSecureClient(unittest.TestCase):
def setUp(self):
server_credentials = cygrpc.server_credentials_ssl(
None, [cygrpc.SslPemKeyCertPair(resources.private_key(),
resources.certificate_chain())], False)
channel_credentials = cygrpc.channel_credentials_ssl(
resources.test_root_certificates(), None)
self.server_completion_queue = cygrpc.CompletionQueue()
self.server = cygrpc.Server()
self.server.register_completion_queue(self.server_completion_queue)
self.port = self.server.add_http2_port('[::]:0', server_credentials)
self.server.start()
self.client_completion_queue = cygrpc.CompletionQueue()
client_channel_arguments = cygrpc.ChannelArgs([
cygrpc.ChannelArg(cygrpc.ChannelArgKey.ssl_target_name_override,
_SSL_HOST_OVERRIDE)])
self.client_channel = cygrpc.Channel(
'localhost:{}'.format(self.port), client_channel_arguments,
channel_credentials)
def tearDown(self):
del self.server
del self.client_completion_queue
del self.server_completion_queue
def testEcho(self):
DEADLINE = time.time()+5
DEADLINE_TOLERANCE = 0.25
CLIENT_METADATA_ASCII_KEY = b'key'
CLIENT_METADATA_ASCII_VALUE = b'val'
CLIENT_METADATA_BIN_KEY = b'key-bin'
CLIENT_METADATA_BIN_VALUE = b'\0'*1000
SERVER_INITIAL_METADATA_KEY = b'init_me_me_me'
SERVER_INITIAL_METADATA_VALUE = b'whodawha?'
SERVER_TRAILING_METADATA_KEY = b'california_is_in_a_drought'
SERVER_TRAILING_METADATA_VALUE = b'zomg it is'
SERVER_STATUS_CODE = cygrpc.StatusCode.ok
SERVER_STATUS_DETAILS = b'our work is never over'
REQUEST = b'in death a member of project mayhem has a name'
RESPONSE = b'his name is robert paulson'
METHOD = b'/twinkies'
HOST = None # Default host
cygrpc_deadline = cygrpc.Timespec(DEADLINE)
server_request_tag = object()
request_call_result = self.server.request_call(
self.server_completion_queue, self.server_completion_queue,
server_request_tag)
self.assertEqual(cygrpc.CallError.ok, request_call_result)
plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '')
call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
client_call_tag = object()
client_call = self.client_channel.create_call(
None, 0, self.client_completion_queue, METHOD, HOST, cygrpc_deadline)
client_call.set_credentials(call_credentials)
client_initial_metadata = cygrpc.Metadata([
cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY,
CLIENT_METADATA_ASCII_VALUE),
cygrpc.Metadatum(CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)])
client_start_batch_result = client_call.start_batch(cygrpc.Operations([
cygrpc.operation_send_initial_metadata(client_initial_metadata),
cygrpc.operation_send_message(REQUEST),
cygrpc.operation_send_close_from_client(),
cygrpc.operation_receive_initial_metadata(),
cygrpc.operation_receive_message(),
cygrpc.operation_receive_status_on_client()
]), client_call_tag)
self.assertEqual(cygrpc.CallError.ok, client_start_batch_result)
client_event_future = test_utilities.CompletionQueuePollFuture(
self.client_completion_queue, cygrpc_deadline)
request_event = self.server_completion_queue.poll(cygrpc_deadline)
self.assertEqual(cygrpc.CompletionType.operation_complete,
request_event.type)
self.assertIsInstance(request_event.operation_call, cygrpc.Call)
self.assertIs(server_request_tag, request_event.tag)
self.assertEqual(0, len(request_event.batch_operations))
client_metadata_with_credentials = list(client_initial_metadata) + [
(_CALL_CREDENTIALS_METADATA_KEY, _CALL_CREDENTIALS_METADATA_VALUE)]
self.assertTrue(
test_common.metadata_transmitted(client_metadata_with_credentials,
request_event.request_metadata))
self.assertEqual(METHOD, request_event.request_call_details.method)
self.assertEqual(_SSL_HOST_OVERRIDE,
request_event.request_call_details.host)
self.assertLess(
abs(DEADLINE - float(request_event.request_call_details.deadline)),
DEADLINE_TOLERANCE)
server_call_tag = object()
server_call = request_event.operation_call
server_initial_metadata = cygrpc.Metadata([
cygrpc.Metadatum(SERVER_INITIAL_METADATA_KEY,
SERVER_INITIAL_METADATA_VALUE)])
server_trailing_metadata = cygrpc.Metadata([
cygrpc.Metadatum(SERVER_TRAILING_METADATA_KEY,
SERVER_TRAILING_METADATA_VALUE)])
server_start_batch_result = server_call.start_batch([
cygrpc.operation_send_initial_metadata(server_initial_metadata),
cygrpc.operation_receive_message(),
cygrpc.operation_send_message(RESPONSE),
cygrpc.operation_receive_close_on_server(),
cygrpc.operation_send_status_from_server(
server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
], server_call_tag)
self.assertEqual(cygrpc.CallError.ok, server_start_batch_result)
client_event = client_event_future.result()
server_event = self.server_completion_queue.poll(cygrpc_deadline)
self.assertEqual(6, len(client_event.batch_operations))
found_client_op_types = set()
for client_result in client_event.batch_operations:
# we expect each op type to be unique
self.assertNotIn(client_result.type, found_client_op_types)
found_client_op_types.add(client_result.type)
if client_result.type == cygrpc.OperationType.receive_initial_metadata:
self.assertTrue(
test_common.metadata_transmitted(server_initial_metadata,
client_result.received_metadata))
elif client_result.type == cygrpc.OperationType.receive_message:
self.assertEqual(RESPONSE, client_result.received_message.bytes())
elif client_result.type == cygrpc.OperationType.receive_status_on_client:
self.assertTrue(
test_common.metadata_transmitted(server_trailing_metadata,
client_result.received_metadata))
self.assertEqual(SERVER_STATUS_DETAILS,
client_result.received_status_details)
self.assertEqual(SERVER_STATUS_CODE, client_result.received_status_code)
self.assertEqual(set([
cygrpc.OperationType.send_initial_metadata,
cygrpc.OperationType.send_message,
cygrpc.OperationType.send_close_from_client,
cygrpc.OperationType.receive_initial_metadata,
cygrpc.OperationType.receive_message,
cygrpc.OperationType.receive_status_on_client
]), found_client_op_types)
self.assertEqual(5, len(server_event.batch_operations))
found_server_op_types = set()
for server_result in server_event.batch_operations:
self.assertNotIn(client_result.type, found_server_op_types)
found_server_op_types.add(server_result.type)
if server_result.type == cygrpc.OperationType.receive_message:
self.assertEqual(REQUEST, server_result.received_message.bytes())
elif server_result.type == cygrpc.OperationType.receive_close_on_server:
self.assertFalse(server_result.received_cancelled)
self.assertEqual(set([
cygrpc.OperationType.send_initial_metadata,
cygrpc.OperationType.receive_message,
cygrpc.OperationType.send_message,
cygrpc.OperationType.receive_close_on_server,
cygrpc.OperationType.send_status_from_server
]), found_server_op_types)
del client_call
del server_call
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(verbosity=2) unittest.main(verbosity=2)

@ -42,6 +42,9 @@ from tests.unit.framework.common import test_constants
_SERVER_HOST_OVERRIDE = 'foo.test.google.fr' _SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
_PER_RPC_CREDENTIALS_METADATA_KEY = 'my-call-credentials-metadata-key'
_PER_RPC_CREDENTIALS_METADATA_VALUE = 'my-call-credentials-metadata-value'
_GROUP = 'group' _GROUP = 'group'
_UNARY_UNARY = 'unary-unary' _UNARY_UNARY = 'unary-unary'
_UNARY_STREAM = 'unary-stream' _UNARY_STREAM = 'unary-stream'
@ -63,6 +66,7 @@ class _Servicer(object):
with self._condition: with self._condition:
self._request = request self._request = request
self._peer = context.protocol_context().peer() self._peer = context.protocol_context().peer()
self._invocation_metadata = context.invocation_metadata()
context.protocol_context().disable_next_response_compression() context.protocol_context().disable_next_response_compression()
self._serviced = True self._serviced = True
self._condition.notify_all() self._condition.notify_all()
@ -72,6 +76,7 @@ class _Servicer(object):
with self._condition: with self._condition:
self._request = request self._request = request
self._peer = context.protocol_context().peer() self._peer = context.protocol_context().peer()
self._invocation_metadata = context.invocation_metadata()
context.protocol_context().disable_next_response_compression() context.protocol_context().disable_next_response_compression()
self._serviced = True self._serviced = True
self._condition.notify_all() self._condition.notify_all()
@ -83,6 +88,7 @@ class _Servicer(object):
self._request = request self._request = request
with self._condition: with self._condition:
self._peer = context.protocol_context().peer() self._peer = context.protocol_context().peer()
self._invocation_metadata = context.invocation_metadata()
context.protocol_context().disable_next_response_compression() context.protocol_context().disable_next_response_compression()
self._serviced = True self._serviced = True
self._condition.notify_all() self._condition.notify_all()
@ -95,6 +101,7 @@ class _Servicer(object):
context.protocol_context().disable_next_response_compression() context.protocol_context().disable_next_response_compression()
yield _RESPONSE yield _RESPONSE
with self._condition: with self._condition:
self._invocation_metadata = context.invocation_metadata()
self._serviced = True self._serviced = True
self._condition.notify_all() self._condition.notify_all()
@ -137,6 +144,11 @@ class _BlockingIterator(object):
self._condition.notify_all() self._condition.notify_all()
def _metadata_plugin(context, callback):
callback([(_PER_RPC_CREDENTIALS_METADATA_KEY,
_PER_RPC_CREDENTIALS_METADATA_VALUE)], None)
class BetaFeaturesTest(unittest.TestCase): class BetaFeaturesTest(unittest.TestCase):
def setUp(self): def setUp(self):
@ -167,10 +179,12 @@ class BetaFeaturesTest(unittest.TestCase):
[(resources.private_key(), resources.certificate_chain(),),]) [(resources.private_key(), resources.certificate_chain(),),])
port = self._server.add_secure_port('[::]:0', server_credentials) port = self._server.add_secure_port('[::]:0', server_credentials)
self._server.start() self._server.start()
self._client_credentials = implementations.ssl_client_credentials( self._channel_credentials = implementations.ssl_channel_credentials(
resources.test_root_certificates(), None, None) resources.test_root_certificates(), None, None)
self._call_credentials = implementations.metadata_call_credentials(
_metadata_plugin)
channel = test_utilities.not_really_secure_channel( channel = test_utilities.not_really_secure_channel(
'localhost', port, self._client_credentials, _SERVER_HOST_OVERRIDE) 'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE)
stub_options = implementations.stub_options( stub_options = implementations.stub_options(
thread_pool_size=test_constants.POOL_SIZE) thread_pool_size=test_constants.POOL_SIZE)
self._dynamic_stub = implementations.dynamic_stub( self._dynamic_stub = implementations.dynamic_stub(
@ -181,21 +195,36 @@ class BetaFeaturesTest(unittest.TestCase):
self._server.stop(test_constants.SHORT_TIMEOUT).wait() self._server.stop(test_constants.SHORT_TIMEOUT).wait()
def test_unary_unary(self): def test_unary_unary(self):
call_options = interfaces.grpc_call_options(disable_compression=True) call_options = interfaces.grpc_call_options(
disable_compression=True, credentials=self._call_credentials)
response = getattr(self._dynamic_stub, _UNARY_UNARY)( response = getattr(self._dynamic_stub, _UNARY_UNARY)(
_REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
self.assertEqual(_RESPONSE, response) self.assertEqual(_RESPONSE, response)
self.assertIsNotNone(self._servicer.peer()) self.assertIsNotNone(self._servicer.peer())
invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
self._servicer._invocation_metadata]
self.assertIn(
(_PER_RPC_CREDENTIALS_METADATA_KEY,
_PER_RPC_CREDENTIALS_METADATA_VALUE),
invocation_metadata)
def test_unary_stream(self): def test_unary_stream(self):
call_options = interfaces.grpc_call_options(disable_compression=True) call_options = interfaces.grpc_call_options(
disable_compression=True, credentials=self._call_credentials)
response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)( response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)(
_REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
self._servicer.block_until_serviced() self._servicer.block_until_serviced()
self.assertIsNotNone(self._servicer.peer()) self.assertIsNotNone(self._servicer.peer())
invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
self._servicer._invocation_metadata]
self.assertIn(
(_PER_RPC_CREDENTIALS_METADATA_KEY,
_PER_RPC_CREDENTIALS_METADATA_VALUE),
invocation_metadata)
def test_stream_unary(self): def test_stream_unary(self):
call_options = interfaces.grpc_call_options() call_options = interfaces.grpc_call_options(
credentials=self._call_credentials)
request_iterator = _BlockingIterator(iter((_REQUEST,))) request_iterator = _BlockingIterator(iter((_REQUEST,)))
response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future( response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future(
request_iterator, test_constants.LONG_TIMEOUT, request_iterator, test_constants.LONG_TIMEOUT,
@ -207,9 +236,16 @@ class BetaFeaturesTest(unittest.TestCase):
self._servicer.block_until_serviced() self._servicer.block_until_serviced()
self.assertIsNotNone(self._servicer.peer()) self.assertIsNotNone(self._servicer.peer())
self.assertEqual(_RESPONSE, response_future.result()) self.assertEqual(_RESPONSE, response_future.result())
invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
self._servicer._invocation_metadata]
self.assertIn(
(_PER_RPC_CREDENTIALS_METADATA_KEY,
_PER_RPC_CREDENTIALS_METADATA_VALUE),
invocation_metadata)
def test_stream_stream(self): def test_stream_stream(self):
call_options = interfaces.grpc_call_options() call_options = interfaces.grpc_call_options(
credentials=self._call_credentials)
request_iterator = _BlockingIterator(iter((_REQUEST,))) request_iterator = _BlockingIterator(iter((_REQUEST,)))
response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)( response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)(
request_iterator, test_constants.SHORT_TIMEOUT, request_iterator, test_constants.SHORT_TIMEOUT,
@ -222,6 +258,12 @@ class BetaFeaturesTest(unittest.TestCase):
self._servicer.block_until_serviced() self._servicer.block_until_serviced()
self.assertIsNotNone(self._servicer.peer()) self.assertIsNotNone(self._servicer.peer())
self.assertEqual(_RESPONSE, response) self.assertEqual(_RESPONSE, response)
invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
self._servicer._invocation_metadata]
self.assertIn(
(_PER_RPC_CREDENTIALS_METADATA_KEY,
_PER_RPC_CREDENTIALS_METADATA_VALUE),
invocation_metadata)
class ContextManagementAndLifecycleTest(unittest.TestCase): class ContextManagementAndLifecycleTest(unittest.TestCase):
@ -250,7 +292,7 @@ class ContextManagementAndLifecycleTest(unittest.TestCase):
thread_pool_size=test_constants.POOL_SIZE) thread_pool_size=test_constants.POOL_SIZE)
self._server_credentials = implementations.ssl_server_credentials( self._server_credentials = implementations.ssl_server_credentials(
[(resources.private_key(), resources.certificate_chain(),),]) [(resources.private_key(), resources.certificate_chain(),),])
self._client_credentials = implementations.ssl_client_credentials( self._channel_credentials = implementations.ssl_channel_credentials(
resources.test_root_certificates(), None, None) resources.test_root_certificates(), None, None)
self._stub_options = implementations.stub_options( self._stub_options = implementations.stub_options(
thread_pool_size=test_constants.POOL_SIZE) thread_pool_size=test_constants.POOL_SIZE)
@ -262,7 +304,7 @@ class ContextManagementAndLifecycleTest(unittest.TestCase):
server.start() server.start()
channel = test_utilities.not_really_secure_channel( channel = test_utilities.not_really_secure_channel(
'localhost', port, self._client_credentials, _SERVER_HOST_OVERRIDE) 'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE)
dynamic_stub = implementations.dynamic_stub( dynamic_stub = implementations.dynamic_stub(
channel, _GROUP, self._cardinalities, options=self._stub_options) channel, _GROUP, self._cardinalities, options=self._stub_options)
for _ in range(100): for _ in range(100):

@ -91,10 +91,10 @@ class _Implementation(test_interfaces.Implementation):
[(resources.private_key(), resources.certificate_chain(),),]) [(resources.private_key(), resources.certificate_chain(),),])
port = server.add_secure_port('[::]:0', server_credentials) port = server.add_secure_port('[::]:0', server_credentials)
server.start() server.start()
client_credentials = implementations.ssl_client_credentials( channel_credentials = implementations.ssl_channel_credentials(
resources.test_root_certificates(), None, None) resources.test_root_certificates(), None, None)
channel = test_utilities.not_really_secure_channel( channel = test_utilities.not_really_secure_channel(
'localhost', port, client_credentials, _SERVER_HOST_OVERRIDE) 'localhost', port, channel_credentials, _SERVER_HOST_OVERRIDE)
stub_options = implementations.stub_options( stub_options = implementations.stub_options(
request_serializers=serialization_behaviors.request_serializers, request_serializers=serialization_behaviors.request_serializers,
response_deserializers=serialization_behaviors.response_deserializers, response_deserializers=serialization_behaviors.response_deserializers,

@ -34,13 +34,13 @@ from grpc.beta import implementations
def not_really_secure_channel( def not_really_secure_channel(
host, port, client_credentials, server_host_override): host, port, channel_credentials, server_host_override):
"""Creates an insecure Channel to a remote host. """Creates an insecure Channel to a remote host.
Args: Args:
host: The name of the remote host to which to connect. host: The name of the remote host to which to connect.
port: The port of the remote host to which to connect. port: The port of the remote host to which to connect.
client_credentials: The implementations.ClientCredentials with which to channel_credentials: The implementations.ChannelCredentials with which to
connect. connect.
server_host_override: The target name used for SSL host name checking. server_host_override: The target name used for SSL host name checking.
@ -50,7 +50,7 @@ def not_really_secure_channel(
""" """
hostport = '%s:%d' % (host, port) hostport = '%s:%d' % (host, port)
intermediary_low_channel = _intermediary_low.Channel( intermediary_low_channel = _intermediary_low.Channel(
hostport, client_credentials._intermediary_low_credentials, hostport, channel_credentials._low_credentials,
server_host_override=server_host_override) server_host_override=server_host_override)
return implementations.Channel( return implementations.Channel(
intermediary_low_channel._internal, intermediary_low_channel) intermediary_low_channel._internal, intermediary_low_channel)

Loading…
Cancel
Save