Merge branch 'master' of github.com:grpc/grpc into lr_hook

pull/5901/head
David Garcia Quintas 9 years ago
commit 580987abf0
  1. 4
      BUILD
  2. 2
      Makefile
  3. 2
      binding.gyp
  4. 2
      build.yaml
  5. 2
      config.m4
  6. 15
      doc/fail_fast.md
  7. 2
      examples/cpp/helloworld/Makefile
  8. 2
      examples/cpp/route_guide/Makefile
  9. 11
      examples/python/README.md
  10. 2
      gRPC.podspec
  11. 1
      grpc.def
  12. 2
      grpc.gemspec
  13. 3
      include/grpc/grpc.h
  14. 39
      include/grpc/impl/codegen/port_platform.h
  15. 2
      package.xml
  16. 10
      src/compiler/config.h
  17. 129
      src/compiler/csharp_generator.cc
  18. 4
      src/compiler/csharp_generator.h
  19. 24
      src/compiler/csharp_plugin.cc
  20. 6
      src/compiler/objective_c_generator.cc
  21. 6
      src/compiler/objective_c_plugin.cc
  22. 10
      src/compiler/python_generator.cc
  23. 6
      src/core/ext/census/grpc_filter.c
  24. 4
      src/core/ext/client_config/client_channel.c
  25. 6
      src/core/ext/client_config/subchannel.c
  26. 2
      src/core/ext/load_reporting/load_reporting_filter.c
  27. 729
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  28. 65
      src/core/ext/transport/chttp2/transport/internal.h
  29. 8
      src/core/ext/transport/chttp2/transport/stream_lists.c
  30. 6
      src/core/lib/channel/channel_stack.c
  31. 11
      src/core/lib/channel/channel_stack.h
  32. 25
      src/core/lib/channel/compress_filter.c
  33. 2
      src/core/lib/channel/compress_filter.h
  34. 6
      src/core/lib/channel/connected_channel.c
  35. 3
      src/core/lib/channel/http_client_filter.c
  36. 16
      src/core/lib/channel/http_server_filter.c
  37. 1
      src/core/lib/iomgr/ev_posix.c
  38. 6
      src/core/lib/iomgr/iomgr.c
  39. 28
      src/core/lib/iomgr/tcp_server_windows.c
  40. 16
      src/core/lib/iomgr/tcp_windows.c
  41. 3
      src/core/lib/security/client_auth_filter.c
  42. 3
      src/core/lib/security/server_auth_filter.c
  43. 44
      src/core/lib/support/env_win32.c
  44. 4
      src/core/lib/support/log_linux.c
  45. 18
      src/core/lib/support/log_win32.c
  46. 94
      src/core/lib/support/string_util_win32.c
  47. 32
      src/core/lib/support/string_win32.c
  48. 4
      src/core/lib/support/time_win32.c
  49. 73
      src/core/lib/support/tmpfile_msys.c
  50. 4
      src/core/lib/support/tmpfile_posix.c
  51. 4
      src/core/lib/support/tmpfile_win32.c
  52. 42
      src/core/lib/surface/call.c
  53. 4
      src/core/lib/surface/completion_queue.c
  54. 3
      src/core/lib/surface/init.c
  55. 5
      src/core/lib/surface/lame_client.c
  56. 3
      src/core/lib/surface/server.c
  57. 5
      src/core/lib/transport/transport.c
  58. 12
      src/core/lib/transport/transport.h
  59. 2
      src/core/lib/transport/transport_impl.h
  60. 186
      src/csharp/Grpc.Examples/MathGrpc.cs
  61. 56
      src/csharp/Grpc.HealthCheck/HealthGrpc.cs
  62. 3
      src/csharp/Grpc.IntegrationTesting/InteropClient.cs
  63. 116
      src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
  64. 304
      src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
  65. 326
      src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
  66. 35
      src/node/ext/node_grpc.cc
  67. 4
      src/node/ext/server_credentials.cc
  68. 7
      src/node/index.js
  69. 3
      src/node/src/client.js
  70. 34
      src/node/src/server.js
  71. 56
      src/node/test/surface_test.js
  72. 54
      src/node/tools/bin/protoc_plugin.js
  73. 4
      src/node/tools/package.json
  74. 56
      src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
  75. 66
      src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m
  76. 12
      src/objective-c/GRPCClient/GRPCCall+Tests.m
  77. 12
      src/objective-c/GRPCClient/private/GRPCChannel.h
  78. 52
      src/objective-c/GRPCClient/private/GRPCChannel.m
  79. 7
      src/objective-c/GRPCClient/private/GRPCHost.h
  80. 92
      src/objective-c/GRPCClient/private/GRPCHost.m
  81. 13
      src/python/grpcio/README.rst
  82. 363
      src/python/grpcio/grpc/_adapter/fore.py
  83. 395
      src/python/grpcio/grpc/_adapter/rear.py
  84. 2
      src/python/grpcio/grpc/_cython/imports.generated.c
  85. 3
      src/python/grpcio/grpc/_cython/imports.generated.h
  86. 35
      src/python/grpcio/grpc/early_adopter/__init__.py
  87. 262
      src/python/grpcio/grpc/early_adopter/implementations.py
  88. 35
      src/python/grpcio/grpc/framework/alpha/__init__.py
  89. 183
      src/python/grpcio/grpc/framework/alpha/_face_utilities.py
  90. 205
      src/python/grpcio/grpc/framework/alpha/_reexport.py
  91. 384
      src/python/grpcio/grpc/framework/alpha/interfaces.py
  92. 269
      src/python/grpcio/grpc/framework/alpha/utilities.py
  93. 35
      src/python/grpcio/grpc/framework/base/__init__.py
  94. 99
      src/python/grpcio/grpc/framework/base/_context.py
  95. 125
      src/python/grpcio/grpc/framework/base/_emission.py
  96. 399
      src/python/grpcio/grpc/framework/base/_ends.py
  97. 158
      src/python/grpcio/grpc/framework/base/_expiration.py
  98. 443
      src/python/grpcio/grpc/framework/base/_ingestion.py
  99. 266
      src/python/grpcio/grpc/framework/base/_interfaces.py
  100. 400
      src/python/grpcio/grpc/framework/base/_reception.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -84,6 +84,7 @@ cc_library(
"src/core/lib/support/stack_lockfree.c",
"src/core/lib/support/string.c",
"src/core/lib/support/string_posix.c",
"src/core/lib/support/string_util_win32.c",
"src/core/lib/support/string_win32.c",
"src/core/lib/support/subprocess_posix.c",
"src/core/lib/support/subprocess_windows.c",
@ -98,6 +99,7 @@ cc_library(
"src/core/lib/support/time_precise.c",
"src/core/lib/support/time_win32.c",
"src/core/lib/support/tls_pthread.c",
"src/core/lib/support/tmpfile_msys.c",
"src/core/lib/support/tmpfile_posix.c",
"src/core/lib/support/tmpfile_win32.c",
"src/core/lib/support/wrap_memcpy.c",
@ -1223,6 +1225,7 @@ objc_library(
"src/core/lib/support/stack_lockfree.c",
"src/core/lib/support/string.c",
"src/core/lib/support/string_posix.c",
"src/core/lib/support/string_util_win32.c",
"src/core/lib/support/string_win32.c",
"src/core/lib/support/subprocess_posix.c",
"src/core/lib/support/subprocess_windows.c",
@ -1237,6 +1240,7 @@ objc_library(
"src/core/lib/support/time_precise.c",
"src/core/lib/support/time_win32.c",
"src/core/lib/support/tls_pthread.c",
"src/core/lib/support/tmpfile_msys.c",
"src/core/lib/support/tmpfile_posix.c",
"src/core/lib/support/tmpfile_win32.c",
"src/core/lib/support/wrap_memcpy.c",

@ -2350,6 +2350,7 @@ LIBGPR_SRC = \
src/core/lib/support/stack_lockfree.c \
src/core/lib/support/string.c \
src/core/lib/support/string_posix.c \
src/core/lib/support/string_util_win32.c \
src/core/lib/support/string_win32.c \
src/core/lib/support/subprocess_posix.c \
src/core/lib/support/subprocess_windows.c \
@ -2364,6 +2365,7 @@ LIBGPR_SRC = \
src/core/lib/support/time_precise.c \
src/core/lib/support/time_win32.c \
src/core/lib/support/tls_pthread.c \
src/core/lib/support/tmpfile_msys.c \
src/core/lib/support/tmpfile_posix.c \
src/core/lib/support/tmpfile_win32.c \
src/core/lib/support/wrap_memcpy.c \

@ -522,6 +522,7 @@
'src/core/lib/support/stack_lockfree.c',
'src/core/lib/support/string.c',
'src/core/lib/support/string_posix.c',
'src/core/lib/support/string_util_win32.c',
'src/core/lib/support/string_win32.c',
'src/core/lib/support/subprocess_posix.c',
'src/core/lib/support/subprocess_windows.c',
@ -536,6 +537,7 @@
'src/core/lib/support/time_precise.c',
'src/core/lib/support/time_win32.c',
'src/core/lib/support/tls_pthread.c',
'src/core/lib/support/tmpfile_msys.c',
'src/core/lib/support/tmpfile_posix.c',
'src/core/lib/support/tmpfile_win32.c',
'src/core/lib/support/wrap_memcpy.c',

@ -103,6 +103,7 @@ filegroups:
- src/core/lib/support/stack_lockfree.c
- src/core/lib/support/string.c
- src/core/lib/support/string_posix.c
- src/core/lib/support/string_util_win32.c
- src/core/lib/support/string_win32.c
- src/core/lib/support/subprocess_posix.c
- src/core/lib/support/subprocess_windows.c
@ -117,6 +118,7 @@ filegroups:
- src/core/lib/support/time_precise.c
- src/core/lib/support/time_win32.c
- src/core/lib/support/tls_pthread.c
- src/core/lib/support/tmpfile_msys.c
- src/core/lib/support/tmpfile_posix.c
- src/core/lib/support/tmpfile_win32.c
- src/core/lib/support/wrap_memcpy.c

@ -63,6 +63,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/support/stack_lockfree.c \
src/core/lib/support/string.c \
src/core/lib/support/string_posix.c \
src/core/lib/support/string_util_win32.c \
src/core/lib/support/string_win32.c \
src/core/lib/support/subprocess_posix.c \
src/core/lib/support/subprocess_windows.c \
@ -77,6 +78,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/support/time_precise.c \
src/core/lib/support/time_win32.c \
src/core/lib/support/tls_pthread.c \
src/core/lib/support/tmpfile_msys.c \
src/core/lib/support/tmpfile_posix.c \
src/core/lib/support/tmpfile_win32.c \
src/core/lib/support/wrap_memcpy.c \

@ -0,0 +1,15 @@
gRPC Fail Fast Semantics
========================
Fail fast requests allow terminating requests (with status UNAVAILABLE) prior
to the deadline of the request being met.
gRPC implementations of fail fast can terminate requests whenever a channel is
in the TRANSIENT_FAILURE or SHUTDOWN states. If the channel is in any other
state (CONNECTING, READY, or IDLE) the request should not be terminated.
Fail fast SHOULD be the default for gRPC implementations, with an option to
switch to non fail fast.
The opposite of fail fast is 'ignore connectivity'.

@ -32,7 +32,7 @@
CXX = g++
CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11
LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`

@ -32,7 +32,7 @@
CXX = g++
CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11
LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`

@ -8,12 +8,19 @@ For this sample, we've already generated the server and client stubs from
Install gRPC:
```sh
```sh
$ pip install grpcio
```
Or, to install it system wide:
```sh
$ sudo pip install grpcio
$ sudo pip install grpcio
```
If you're on Windows, make sure you installed the `pip.exe` component when you
installed Python. Invoke as above but with `pip.exe` instead of `pip` (you may
also need to invoke from a `cmd.exe` ran as administrator):
```sh
$ pip.exe install grpcio
```
Download the example

@ -144,6 +144,7 @@ Pod::Spec.new do |s|
'src/core/lib/support/stack_lockfree.c',
'src/core/lib/support/string.c',
'src/core/lib/support/string_posix.c',
'src/core/lib/support/string_util_win32.c',
'src/core/lib/support/string_win32.c',
'src/core/lib/support/subprocess_posix.c',
'src/core/lib/support/subprocess_windows.c',
@ -158,6 +159,7 @@ Pod::Spec.new do |s|
'src/core/lib/support/time_precise.c',
'src/core/lib/support/time_win32.c',
'src/core/lib/support/tls_pthread.c',
'src/core/lib/support/tmpfile_msys.c',
'src/core/lib/support/tmpfile_posix.c',
'src/core/lib/support/tmpfile_win32.c',
'src/core/lib/support/wrap_memcpy.c',

@ -86,6 +86,7 @@ EXPORTS
grpc_header_key_is_legal
grpc_header_nonbin_value_is_legal
grpc_is_binary_header
grpc_call_error_to_string
grpc_auth_property_iterator_next
grpc_auth_context_property_iterator
grpc_auth_context_peer_identity

@ -124,6 +124,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/stack_lockfree.c )
s.files += %w( src/core/lib/support/string.c )
s.files += %w( src/core/lib/support/string_posix.c )
s.files += %w( src/core/lib/support/string_util_win32.c )
s.files += %w( src/core/lib/support/string_win32.c )
s.files += %w( src/core/lib/support/subprocess_posix.c )
s.files += %w( src/core/lib/support/subprocess_windows.c )
@ -138,6 +139,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/time_precise.c )
s.files += %w( src/core/lib/support/time_win32.c )
s.files += %w( src/core/lib/support/tls_pthread.c )
s.files += %w( src/core/lib/support/tmpfile_msys.c )
s.files += %w( src/core/lib/support/tmpfile_posix.c )
s.files += %w( src/core/lib/support/tmpfile_win32.c )
s.files += %w( src/core/lib/support/wrap_memcpy.c )

@ -384,6 +384,9 @@ GRPCAPI int grpc_header_nonbin_value_is_legal(const char *value, size_t length);
/** Check whether a metadata key corresponds to a binary value */
GRPCAPI int grpc_is_binary_header(const char *key, size_t length);
/** Convert grpc_call_error values to a string */
GRPCAPI const char *grpc_call_error_to_string(grpc_call_error error);
#ifdef __cplusplus
}
#endif

@ -82,28 +82,31 @@
things. */
#if !defined(GPR_NO_AUTODETECT_PLATFORM)
#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
#if defined(_WIN64) || defined(WIN64)
#define GPR_PLATFORM_STRING "windows"
#define GPR_WIN32 1
#define GPR_ARCH_64 1
#define GPR_GETPID_IN_PROCESS_H 1
#define GPR_WINSOCK_SOCKET 1
#define GPR_WINDOWS_SUBPROCESS 1
#ifdef __GNUC__
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
#else
#define GPR_WIN32_ATOMIC 1
#define GPR_MSVC_TLS 1
#define GPR_ARCH_32 1
#endif
#define GPR_WINDOWS_CRASH_HANDLER 1
#elif defined(_WIN32) || defined(WIN32)
#define GPR_PLATFORM_STRING "windows"
#define GPR_ARCH_32 1
#define GPR_WIN32 1
#define GPR_GETPID_IN_PROCESS_H 1
#define GPR_WINSOCK_SOCKET 1
#define GPR_WINDOWS_SUBPROCESS 1
#define GPR_WIN32_ENV
#ifdef __MSYS__
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_MSYS_TMPFILE
#define GPR_POSIX_LOG
#define GPR_POSIX_STRING
#define GPR_POSIX_TIME
#else
#define GPR_GETPID_IN_PROCESS_H 1
#define GPR_WIN32_TMPFILE
#define GPR_WIN32_LOG
#define GPR_WINDOWS_CRASH_HANDLER 1
#define GPR_WIN32_STRING
#define GPR_WIN32_TIME
#endif
#ifdef __GNUC__
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
@ -111,7 +114,6 @@
#define GPR_WIN32_ATOMIC 1
#define GPR_MSVC_TLS 1
#endif
#define GPR_WINDOWS_CRASH_HANDLER 1
#elif defined(ANDROID) || defined(__ANDROID__)
#define GPR_PLATFORM_STRING "android"
#define GPR_ANDROID 1
@ -127,6 +129,8 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_LOG
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@ -153,6 +157,7 @@
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
#define GPR_LINUX 1
#define GPR_LINUX_LOG
#define GPR_LINUX_MULTIPOLL_WITH_EPOLL 1
#define GPR_POSIX_WAKEUP_FD 1
#define GPR_POSIX_SOCKET 1
@ -176,6 +181,7 @@
#define GPR_POSIX_SOCKETUTILS
#endif
#define GPR_POSIX_FILE 1
#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@ -214,6 +220,7 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@ -244,6 +251,7 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@ -281,6 +289,7 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1

@ -131,6 +131,7 @@
<file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string_util_win32.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string_win32.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/subprocess_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/subprocess_windows.c" role="src" />
@ -145,6 +146,7 @@
<file baseinstalldir="/" name="src/core/lib/support/time_precise.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/time_win32.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/tls_pthread.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/tmpfile_msys.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/tmpfile_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/tmpfile_win32.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/wrap_memcpy.c" role="src" />

@ -70,6 +70,11 @@
#define GRPC_CUSTOM_PLUGINMAIN ::google::protobuf::compiler::PluginMain
#endif
#ifndef GRPC_CUSTOM_PARSEGENERATORPARAMETER
#include <google/protobuf/compiler/code_generator.h>
#define GRPC_CUSTOM_PARSEGENERATORPARAMETER ::google::protobuf::compiler::ParseGeneratorParameter
#endif
namespace grpc {
namespace protobuf {
typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
@ -85,6 +90,11 @@ static inline int PluginMain(int argc, char* argv[],
const CodeGenerator* generator) {
return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator);
}
static inline void ParseGeneratorParameter(const string& parameter,
std::vector<std::pair<string, string> >* options) {
GRPC_CUSTOM_PARSEGENERATORPARAMETER(parameter, options);
}
} // namespace compiler
namespace io {
typedef GRPC_CUSTOM_PRINTER Printer;

@ -52,6 +52,7 @@ using grpc::protobuf::MethodDescriptor;
using grpc::protobuf::io::Printer;
using grpc::protobuf::io::StringOutputStream;
using grpc_generator::MethodType;
using grpc_generator::GetCppComments;
using grpc_generator::GetMethodType;
using grpc_generator::METHODTYPE_NO_STREAMING;
using grpc_generator::METHODTYPE_CLIENT_STREAMING;
@ -65,6 +66,56 @@ using std::vector;
namespace grpc_csharp_generator {
namespace {
// This function is a massaged version of
// https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
// Currently, we cannot easily reuse the functionality as
// google/protobuf/compiler/csharp/csharp_doc_comment.h is not a public header.
// TODO(jtattermusch): reuse the functionality from google/protobuf.
void GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer* printer, grpc::protobuf::SourceLocation location) {
grpc::string comments = location.leading_comments.empty() ?
location.trailing_comments : location.leading_comments;
if (comments.empty()) {
return;
}
// XML escaping... no need for apostrophes etc as the whole text is going to be a child
// node of a summary element, not part of an attribute.
comments = grpc_generator::StringReplace(comments, "&", "&amp;", true);
comments = grpc_generator::StringReplace(comments, "<", "&lt;", true);
std::vector<grpc::string> lines;
grpc_generator::Split(comments, '\n', &lines);
// TODO: We really should work out which part to put in the summary and which to put in the remarks...
// but that needs to be part of a bigger effort to understand the markdown better anyway.
printer->Print("/// <summary>\n");
bool last_was_empty = false;
// We squash multiple blank lines down to one, and remove any trailing blank lines. We need
// to preserve the blank lines themselves, as this is relevant in the markdown.
// Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
// (We don't skip "just whitespace" lines, either.)
for (std::vector<grpc::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
grpc::string line = *it;
if (line.empty()) {
last_was_empty = true;
} else {
if (last_was_empty) {
printer->Print("///\n");
}
last_was_empty = false;
printer->Print("/// $line$\n", "line", *it);
}
}
printer->Print("/// </summary>\n");
}
template <typename DescriptorType>
void GenerateDocCommentBody(
grpc::protobuf::io::Printer* printer, const DescriptorType* descriptor) {
grpc::protobuf::SourceLocation location;
if (descriptor->GetSourceLocation(&location)) {
GenerateDocCommentBodyImpl(printer, location);
}
}
std::string GetServiceClassName(const ServiceDescriptor* service) {
return service->name();
}
@ -123,6 +174,10 @@ std::string GetMethodRequestParamMaybe(const MethodDescriptor *method,
return GetClassName(method->input_type()) + " request, ";
}
std::string GetAccessLevel(bool internal_access) {
return internal_access ? "internal" : "public";
}
std::string GetMethodReturnTypeClient(const MethodDescriptor *method) {
switch (GetMethodType(method)) {
case METHODTYPE_NO_STREAMING:
@ -238,7 +293,7 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
std::ostringstream index;
index << service->index();
out->Print("// service descriptor\n");
out->Print("/// <summary>Service descriptor</summary>\n");
out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
out->Print("{\n");
out->Print(" get { return $umbrella$.Descriptor.Services[$index$]; }\n",
@ -249,7 +304,8 @@ void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *se
}
void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
out->Print("// client interface\n");
out->Print("/// <summary>Client for $servicename$</summary>\n",
"servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Client side interfaced will be removed "
"in the next release. Use client class directly.\")]\n");
out->Print("public interface $name$\n", "name",
@ -262,6 +318,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method->name(), "request",
@ -269,6 +326,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetClassName(method->output_type()));
// overload taking CallOptions as a param
GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, CallOptions options);\n",
"methodname", method->name(), "request",
@ -280,6 +338,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method_name, "request_maybe",
@ -287,6 +346,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetMethodReturnTypeClient(method));
// overload taking CallOptions as a param
GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$CallOptions options);\n",
"methodname", method_name, "request_maybe",
@ -299,7 +359,8 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
out->Print("// server-side interface\n");
out->Print("/// <summary>Interface of server-side implementations of $servicename$</summary>\n",
"servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Service implementations should inherit"
" from the generated abstract base class instead.\")]\n");
out->Print("public interface $name$\n", "name",
@ -308,6 +369,7 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context);\n",
@ -322,13 +384,15 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
out->Print("// server-side abstract class\n");
out->Print("/// <summary>Base class for server-side implementations of $servicename$</summary>\n",
"servicename", GetServiceClassName(service));
out->Print("public abstract class $name$\n", "name",
GetServerClassName(service));
out->Print("{\n");
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context)\n",
@ -349,7 +413,8 @@ void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
}
void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("// client stub\n");
out->Print("/// <summary>Client for $servicename$</summary>\n",
"servicename", GetServiceClassName(service));
out->Print("#pragma warning disable 0618\n");
out->Print(
"public class $name$ : ClientBase<$name$>, $interface$\n",
@ -388,6 +453,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@ -400,6 +466,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, CallOptions options)\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@ -416,6 +483,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method_name, "request_maybe",
@ -431,6 +499,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$CallOptions options)\n",
"methodname", method_name, "request_maybe",
@ -481,7 +550,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
bool use_server_class) {
out->Print(
"// creates service definition that can be registered with a server\n");
"/// <summary>Creates service definition that can be registered with a server</summary>\n");
out->Print("#pragma warning disable 0618\n");
out->Print(
"public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
@ -515,7 +584,8 @@ void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
}
void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
out->Print("// creates a new client\n");
out->Print("/// <summary>Creates a new client for $servicename$</summary>\n",
"servicename", GetServiceClassName(service));
out->Print("public static $classname$ NewClient(Channel channel)\n",
"classname", GetClientClassName(service));
out->Print("{\n");
@ -527,8 +597,12 @@ void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
out->Print("\n");
}
void GenerateService(Printer* out, const ServiceDescriptor *service) {
out->Print("public static class $classname$\n", "classname",
void GenerateService(Printer* out, const ServiceDescriptor *service,
bool generate_client, bool generate_server,
bool internal_access) {
GenerateDocCommentBody(out, service);
out->Print("$access_level$ static class $classname$\n", "access_level",
GetAccessLevel(internal_access), "classname",
GetServiceClassName(service));
out->Print("{\n");
out->Indent();
@ -542,13 +616,22 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
GenerateStaticMethodField(out, service->method(i));
}
GenerateServiceDescriptorProperty(out, service);
GenerateClientInterface(out, service);
GenerateServerInterface(out, service);
GenerateServerClass(out, service);
GenerateClientStub(out, service);
GenerateBindServiceMethod(out, service, false);
GenerateBindServiceMethod(out, service, true);
GenerateNewStubMethods(out, service);
if (generate_client) {
GenerateClientInterface(out, service);
}
if (generate_server) {
GenerateServerInterface(out, service);
GenerateServerClass(out, service);
}
if (generate_client) {
GenerateClientStub(out, service);
GenerateNewStubMethods(out, service);
}
if (generate_server) {
GenerateBindServiceMethod(out, service, false);
GenerateBindServiceMethod(out, service, true);
}
out->Outdent();
out->Print("}\n");
@ -556,7 +639,8 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
} // anonymous namespace
grpc::string GetServices(const FileDescriptor *file) {
grpc::string GetServices(const FileDescriptor *file, bool generate_client,
bool generate_server, bool internal_access) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@ -573,6 +657,14 @@ grpc::string GetServices(const FileDescriptor *file) {
// Write out a file header.
out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print("// source: $filename$\n", "filename", file->name());
// use C++ style as there are no file-level XML comments in .NET
grpc::string leading_comments = GetCppComments(file, true);
if (!leading_comments.empty()) {
out.Print("// Original file comments:\n");
out.Print(leading_comments.c_str());
}
out.Print("#region Designer generated code\n");
out.Print("\n");
out.Print("using System;\n");
@ -584,7 +676,8 @@ grpc::string GetServices(const FileDescriptor *file) {
out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));
out.Indent();
for (int i = 0; i < file->service_count(); i++) {
GenerateService(&out, file->service(i));
GenerateService(&out, file->service(i), generate_client, generate_server,
internal_access);
}
out.Outdent();
out.Print("}\n");

@ -40,7 +40,9 @@
namespace grpc_csharp_generator {
grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
grpc::string GetServices(const grpc::protobuf::FileDescriptor *file,
bool generate_client, bool generate_server,
bool internal_access);
} // namespace grpc_csharp_generator

@ -48,7 +48,29 @@ class CSharpGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
const grpc::string &parameter,
grpc::protobuf::compiler::GeneratorContext *context,
grpc::string *error) const {
grpc::string code = grpc_csharp_generator::GetServices(file);
std::vector<std::pair<grpc::string, grpc::string> > options;
grpc::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
bool generate_client = true;
bool generate_server = true;
bool internal_access = false;
for (size_t i = 0; i < options.size(); i++) {
if (options[i].first == "no_client") {
generate_client = false;
} else if (options[i].first == "no_server") {
generate_server = false;
} else if (options[i].first == "internal_access") {
internal_access = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
}
}
grpc::string code = grpc_csharp_generator::GetServices(file,
generate_client,
generate_server,
internal_access);
if (code.size() == 0) {
return true; // don't generate a file if there are no services
}

@ -75,11 +75,11 @@ void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
if (method->server_streaming()) {
printer->Print(vars,
" eventHandler:(void(^)(BOOL done, "
"$response_class$ *response, NSError *error))eventHandler");
"$response_class$ *_Nullable response, NSError *_Nullable error))eventHandler");
} else {
printer->Print(vars,
" handler:(void(^)($response_class$ *response, "
"NSError *error))handler");
" handler:(void(^)($response_class$ *_Nullable response, "
"NSError *_Nullable error))handler");
}
}

@ -81,8 +81,12 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
declarations += grpc_objective_c_generator::GetHeader(service);
}
static const ::grpc::string kNonNullBegin = "\nNS_ASSUME_NONNULL_BEGIN\n\n";
static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n";
Write(context, file_name + ".pbrpc.h",
imports + '\n' + proto_imports + '\n' + declarations);
imports + '\n' + proto_imports + '\n' + kNonNullBegin +
declarations + kNonNullEnd);
}
{

@ -190,7 +190,7 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
"Documentation", doc,
});
out->Print("\n");
out->Print(dict, "class Beta$Service$Servicer(six.with_metaclass(abc.ABCMeta, object)):\n");
out->Print(dict, "class Beta$Service$Servicer(object):\n");
{
IndentScope raii_class_indent(out);
out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@ -198,12 +198,11 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
auto meth = service->method(i);
grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
out->Print("@abc.abstractmethod\n");
out->Print("def $Method$(self, $ArgName$, context):\n",
"Method", meth->name(), "ArgName", arg_name);
{
IndentScope raii_method_indent(out);
out->Print("raise NotImplementedError()\n");
out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
}
}
}
@ -218,7 +217,7 @@ bool PrintBetaStub(const ServiceDescriptor* service,
"Documentation", doc,
});
out->Print("\n");
out->Print(dict, "class Beta$Service$Stub(six.with_metaclass(abc.ABCMeta, object)):\n");
out->Print(dict, "class Beta$Service$Stub(object):\n");
{
IndentScope raii_class_indent(out);
out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@ -227,7 +226,6 @@ bool PrintBetaStub(const ServiceDescriptor* service,
grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
out->Print("@abc.abstractmethod\n");
out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n");
{
IndentScope raii_method_indent(out);
@ -450,6 +448,8 @@ bool PrintPreamble(const FileDescriptor* file,
out->Print("import six\n");
out->Print("from $Package$ import implementations as beta_implementations\n",
"Package", config.beta_package_root);
out->Print("from $Package$ import interfaces as beta_interfaces\n",
"Package", config.beta_package_root);
out->Print("from grpc.framework.common import cardinality\n");
out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
return true;

@ -135,7 +135,8 @@ static void client_init_call_elem(grpc_exec_ctx *exec_ctx,
static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats *stats,
void *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
@ -154,7 +155,8 @@ static void server_init_call_elem(grpc_exec_ctx *exec_ctx,
static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats* stats,
void *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc server stats and census_tracing_end_op here */

@ -416,8 +416,10 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats *stats,
void *and_free_memory) {
grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
gpr_free(and_free_memory);
}
/* Constructor for channel_data */

@ -644,9 +644,9 @@ static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
bool success) {
grpc_subchannel_call *c = call;
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL);
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
gpr_free(c);
grpc_connected_subchannel *connection = c->connection;
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL, c);
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call");
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
}

@ -48,7 +48,7 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats *stats, void *ignored) {
channel_data *chand = elem->channel_data;
GPR_TIMER_BEGIN("load_reporting_filter", 0);
grpc_load_reporting_call(chand->lrd, stats);

File diff suppressed because it is too large Load Diff

@ -291,27 +291,44 @@ struct grpc_chttp2_transport_parsing {
int64_t outgoing_window;
};
typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s, void *arg);
typedef struct grpc_chttp2_executor_action_header {
grpc_chttp2_stream *stream;
grpc_chttp2_locked_action action;
struct grpc_chttp2_executor_action_header *next;
void *arg;
} grpc_chttp2_executor_action_header;
struct grpc_chttp2_transport {
grpc_transport base; /* must be first */
grpc_endpoint *ep;
gpr_refcount refs;
grpc_endpoint *ep;
char *peer_string;
/** when this drops to zero it's safe to shutdown the endpoint */
gpr_refcount shutdown_ep_refs;
gpr_mu mu;
struct {
gpr_mu mu;
/** is a thread currently in the global lock */
bool global_active;
/** is a thread currently writing */
bool writing_active;
/** is a thread currently parsing */
bool parsing_active;
grpc_chttp2_executor_action_header *pending_actions;
} executor;
/** is the transport destroying itself? */
uint8_t destroying;
/** has the upper layer closed the transport? */
uint8_t closed;
/** is a thread currently writing */
uint8_t writing_active;
/** is a thread currently parsing */
uint8_t parsing_active;
/** is there a read request to the endpoint outstanding? */
uint8_t endpoint_reading;
@ -338,8 +355,10 @@ struct grpc_chttp2_transport {
/** closure to execute writing */
grpc_closure writing_action;
/** closure to finish reading from the endpoint */
grpc_closure recv_data;
/** closure to start reading from the endpoint */
grpc_closure reading_action;
/** closure to actually do parsing */
grpc_closure parsing_action;
/** incoming read bytes */
gpr_slice_buffer read_buffer;
@ -397,21 +416,26 @@ typedef struct {
grpc_transport_stream_stats *collecting_stats;
grpc_transport_stream_stats stats;
/** number of streams that are currently being read */
gpr_refcount active_streams;
/** when the application requests writes be closed, the write_closed is
'queued'; when the close is flow controlled into the send path, we are
'sending' it; when the write has been performed it is 'sent' */
uint8_t write_closed;
bool write_closed;
/** is this stream reading half-closed (boolean) */
uint8_t read_closed;
bool read_closed;
/** are all published incoming byte streams closed */
bool all_incoming_byte_streams_finished;
/** is this stream in the stream map? (boolean) */
uint8_t in_stream_map;
bool in_stream_map;
/** has this stream seen an error? if 1, then pending incoming frames
can be thrown away */
uint8_t seen_error;
bool seen_error;
uint8_t published_initial_metadata;
uint8_t published_trailing_metadata;
uint8_t faked_trailing_metadata;
bool published_initial_metadata;
bool published_trailing_metadata;
bool faked_trailing_metadata;
grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
@ -570,6 +594,9 @@ int grpc_chttp2_list_pop_waiting_for_concurrency(
void grpc_chttp2_list_add_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
bool grpc_chttp2_list_remove_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
int grpc_chttp2_list_pop_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global);
@ -645,6 +672,12 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global,
grpc_closure **pclosure, int success);
void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *transport,
grpc_chttp2_stream *optional_stream,
grpc_chttp2_locked_action action,
void *arg, size_t sizeof_arg);
#define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
(sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1)

@ -305,6 +305,14 @@ void grpc_chttp2_list_add_check_read_ops(
GRPC_CHTTP2_LIST_CHECK_READ_OPS);
}
bool grpc_chttp2_list_remove_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_CHECK_READ_OPS);
}
int grpc_chttp2_list_pop_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global) {

@ -214,14 +214,16 @@ void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset) {}
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_stats *call_stats) {
const grpc_call_stats *call_stats,
void *and_free_memory) {
grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
size_t count = stack->count;
size_t i;
/* destroy per-filter data */
for (i = 0; i < count; i++) {
elems[i].filter->destroy_call_elem(exec_ctx, &elems[i], call_stats);
elems[i].filter->destroy_call_elem(exec_ctx, &elems[i], call_stats,
i == count - 1 ? and_free_memory : NULL);
}
}

@ -112,9 +112,13 @@ typedef struct {
void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_pollset *pollset);
/* Destroy per call data.
The filter does not need to do any chaining */
The filter does not need to do any chaining.
The bottom filter of a stack will be passed a non-NULL pointer to
\a and_free_memory that should be passed to gpr_free when destruction
is complete. */
void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats);
const grpc_call_stats *stats,
void *and_free_memory);
/* sizeof(per channel data) */
size_t sizeof_channel_data;
@ -233,7 +237,8 @@ void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
/* Destroy a call stack */
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_stats *call_stats);
const grpc_call_stats *call_stats,
void *and_free_memory);
/* Ignore set pollset - used by filters to implement the set_pollset method
if they don't care about pollsets at all. Does nothing. */

@ -47,6 +47,8 @@
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
int grpc_compress_filter_trace = 0;
typedef struct call_data {
gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
grpc_linked_mdelem compression_algorithm_storage;
@ -169,9 +171,29 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
did_compress =
grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp);
if (did_compress) {
if (grpc_compress_filter_trace) {
char *algo_name;
const size_t before_size = calld->slices.length;
const size_t after_size = tmp.length;
const float savings_ratio = 1.0f - (float)after_size / (float)before_size;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name));
gpr_log(GPR_DEBUG,
"Compressed[%s] %d bytes vs. %d bytes (%.2f%% savings)",
algo_name, before_size, after_size, 100 * savings_ratio);
}
gpr_slice_buffer_swap(&calld->slices, &tmp);
calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
} else {
if (grpc_compress_filter_trace) {
char *algo_name;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name));
gpr_log(GPR_DEBUG, "Algorithm '%s' enabled but decided not to compress.",
algo_name);
}
}
gpr_slice_buffer_destroy(&tmp);
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
@ -247,7 +269,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats *stats,
void *ignored) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
gpr_slice_buffer_destroy(&calld->slices);

@ -38,6 +38,8 @@
#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-encoding-request"
extern int grpc_compress_filter_trace;
/** Compression filter for outgoing data.
*
* See <grpc/compression.h> for the available compression settings.

@ -103,11 +103,13 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats *stats,
void *and_free_memory) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_transport_destroy_stream(exec_ctx, chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld));
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
and_free_memory);
}
/* Constructor for channel_data */

@ -156,7 +156,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {}
const grpc_call_stats *stats,
void *ignored) {}
static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
unsigned i;

@ -39,6 +39,9 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/transport/static_metadata.h"
#define EXPECTED_CONTENT_TYPE "application/grpc"
#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
typedef struct call_data {
uint8_t seen_path;
uint8_t seen_method;
@ -92,8 +95,11 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
require */
return NULL;
} else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) ==
0) {
const char *value_str = grpc_mdstr_as_c_string(md->value);
if (strncmp(value_str, EXPECTED_CONTENT_TYPE,
EXPECTED_CONTENT_TYPE_LENGTH) == 0 &&
(value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' ||
value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) {
/* Although the C implementation doesn't (currently) generate them,
any custom +-suffix is explicitly valid. */
/* TODO(klempner): We should consider preallocating common values such
@ -102,8 +108,7 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
} else {
/* TODO(klempner): We're currently allowing this, but we shouldn't
see it without a proxy so log for now. */
gpr_log(GPR_INFO, "Unexpected content-type %s",
grpc_mdstr_as_c_string(md->value));
gpr_log(GPR_INFO, "Unexpected content-type %s", value_str);
}
return NULL;
} else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
@ -221,7 +226,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {}
const grpc_call_stats *stats,
void *ignored) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,

@ -44,7 +44,6 @@
static const grpc_event_engine_vtable *g_event_engine;
grpc_poll_function_type grpc_poll_function = poll;
grpc_wakeup_fd grpc_global_wakeup_fd;
void grpc_event_engine_init(void) {
if ((g_event_engine = grpc_init_poll_and_epoll_posix())) {

@ -166,8 +166,10 @@ bool grpc_iomgr_abort_on_leaks(void) {
if (env == NULL) return false;
static const char *truthy[] = {"yes", "Yes", "YES", "true",
"True", "TRUE", "1"};
bool should_we = false;
for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == strcmp(env, truthy[i])) return true;
if (0 == strcmp(env, truthy[i])) should_we = true;
}
return false;
gpr_free(env);
return should_we;
}

@ -508,34 +508,6 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
}
}
unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
unsigned port_index) {
grpc_tcp_listener *sp;
for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index)
;
if (sp) {
return 1;
} else {
return 0;
}
}
int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
unsigned fd_index) {
grpc_tcp_listener *sp;
if (fd_index != 0) {
/* Windows implementation has only one fd per port_index. */
return -1;
}
for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index)
;
if (sp) {
return _open_osfhandle((intptr_t)sp->socket->socket, 0);
} else {
return -1;
}
}
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_pollset **pollset, size_t pollset_count,
grpc_tcp_server_cb on_accept_cb,

@ -35,6 +35,8 @@
#ifdef GPR_WINSOCK_SOCKET
#include <limits.h>
#include "src/core/lib/iomgr/sockaddr_win32.h"
#include <grpc/support/alloc.h>
@ -51,12 +53,20 @@
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/iomgr/timer.h"
#if defined(__MSYS__) && defined(GPR_ARCH_64)
/* Nasty workaround for nasty bug when using the 64 bits msys compiler
in conjunction with Microsoft Windows headers. */
#define GRPC_FIONBIO _IOW('f', 126, uint32_t)
#else
#define GRPC_FIONBIO FIONBIO
#endif
static int set_non_block(SOCKET sock) {
int status;
unsigned long param = 1;
uint32_t param = 1;
DWORD ret;
status =
WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret, NULL, NULL);
status = WSAIoctl(sock, GRPC_FIONBIO, &param, sizeof(param), NULL, 0, &ret,
NULL, NULL);
return status == 0;
}

@ -278,7 +278,8 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats *stats,
void *ignored) {
call_data *calld = elem->call_data;
grpc_call_credentials_unref(calld->creds);
if (calld->host != NULL) {

@ -225,7 +225,8 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {}
const grpc_call_stats *stats,
void *ignored) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,

@ -33,41 +33,47 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#ifdef GPR_WIN32_ENV
#include <windows.h>
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#ifdef __MINGW32__
errno_t getenv_s(size_t *size_needed, char *buffer, size_t size,
const char *varname);
#else
#include <stdlib.h>
#endif
#include "src/core/lib/support/string_win32.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
char *gpr_getenv(const char *name) {
size_t size;
char *result = NULL;
errno_t err;
DWORD size;
LPTSTR tresult = NULL;
LPTSTR tname = gpr_char_to_tchar(name);
DWORD ret;
err = getenv_s(&size, NULL, 0, name);
if (err || (size == 0)) return NULL;
result = gpr_malloc(size);
err = getenv_s(&size, result, size, name);
if (err) {
gpr_free(result);
ret = GetEnvironmentVariable(tname, NULL, 0);
if (ret == 0) return NULL;
size = ret * (DWORD)sizeof(TCHAR);
tresult = gpr_malloc(size);
ret = GetEnvironmentVariable(tname, tresult, size);
gpr_free(tname);
if (ret == 0) {
gpr_free(tresult);
return NULL;
}
result = gpr_tchar_to_char(tresult);
gpr_free(tresult);
return result;
}
void gpr_setenv(const char *name, const char *value) {
errno_t res = _putenv_s(name, value);
GPR_ASSERT(res == 0);
LPTSTR tname = gpr_char_to_tchar(name);
LPTSTR tvalue = gpr_char_to_tchar(value);
BOOL res = SetEnvironmentVariable(tname, tvalue);
gpr_free(tname);
gpr_free(tvalue);
GPR_ASSERT(res);
}
#endif /* GPR_WIN32 */
#endif /* GPR_WIN32_ENV */

@ -41,7 +41,7 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_LINUX
#ifdef GPR_LINUX_LOG
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@ -103,4 +103,4 @@ void gpr_default_log(gpr_log_func_args *args) {
gpr_free(prefix);
}
#endif
#endif /* GPR_LINUX_LOG */

@ -33,7 +33,7 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#ifdef GPR_WIN32_LOG
#include <stdarg.h>
#include <stdio.h>
@ -109,18 +109,4 @@ void gpr_default_log(gpr_log_func_args *args) {
fflush(stderr);
}
char *gpr_format_message(int messageid) {
LPTSTR tmessage;
char *message;
DWORD status = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, (DWORD)messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)(&tmessage), 0, NULL);
if (status == 0) return gpr_strdup("Unable to retrieve error string");
message = gpr_tchar_to_char(tmessage);
LocalFree(tmessage);
return message;
}
#endif /* GPR_WIN32 */
#endif /* GPR_WIN32_LOG */

@ -0,0 +1,94 @@
/*
*
* Copyright 2016, 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.
*
*/
/* Posix code for gpr snprintf support. */
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
/* Some platforms (namely msys) need wchar to be included BEFORE
anything else, especially strsafe.h. */
#include <wchar.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <strsafe.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/support/string.h"
#if defined UNICODE || defined _UNICODE
LPTSTR
gpr_char_to_tchar(LPCSTR input) {
LPTSTR ret;
int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
if (needed <= 0) return NULL;
ret = gpr_malloc((unsigned)needed * sizeof(TCHAR));
MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed);
return ret;
}
LPSTR
gpr_tchar_to_char(LPCTSTR input) {
LPSTR ret;
int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL);
if (needed <= 0) return NULL;
ret = gpr_malloc((unsigned)needed);
WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL);
return ret;
}
#else
char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); }
char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); }
#endif
char *gpr_format_message(int messageid) {
LPTSTR tmessage;
char *message;
DWORD status = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, (DWORD)messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)(&tmessage), 0, NULL);
if (status == 0) return gpr_strdup("Unable to retrieve error string");
message = gpr_tchar_to_char(tmessage);
LocalFree(tmessage);
return message;
}
#endif /* GPR_WIN32 */

@ -31,11 +31,11 @@
*
*/
/* Posix code for gpr snprintf support. */
/* Windows code for gpr snprintf support. */
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#ifdef GPR_WIN32_STRING
#include <stdarg.h>
#include <stdio.h>
@ -80,30 +80,4 @@ int gpr_asprintf(char **strp, const char *format, ...) {
return -1;
}
#if defined UNICODE || defined _UNICODE
LPTSTR
gpr_char_to_tchar(LPCSTR input) {
LPTSTR ret;
int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
if (needed <= 0) return NULL;
ret = gpr_malloc((unsigned)needed * sizeof(TCHAR));
MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed);
return ret;
}
LPSTR
gpr_tchar_to_char(LPCTSTR input) {
LPSTR ret;
int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL);
if (needed <= 0) return NULL;
ret = gpr_malloc((unsigned)needed);
WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL);
return ret;
}
#else
char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); }
char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); }
#endif
#endif /* GPR_WIN32 */
#endif /* GPR_WIN32_STRING */

@ -35,7 +35,7 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#ifdef GPR_WIN32_TIME
#include <grpc/support/log.h>
#include <grpc/support/time.h>
@ -107,4 +107,4 @@ void gpr_sleep_until(gpr_timespec until) {
}
}
#endif /* GPR_WIN32 */
#endif /* GPR_WIN32_TIME */

@ -0,0 +1,73 @@
/*
*
* 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/support/port_platform.h>
#ifdef GPR_MSYS_TMPFILE
#include <io.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/support/string_win32.h"
#include "src/core/lib/support/tmpfile.h"
FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) {
FILE *result = NULL;
char tmp_filename[MAX_PATH];
UINT success;
if (tmp_filename_out != NULL) *tmp_filename_out = NULL;
/* Generate a unique filename with our template + temporary path. */
success = GetTempFileNameA(".", prefix, 0, tmp_filename);
fprintf(stderr, "success = %d\n", success);
if (success) {
/* Open a file there. */
result = fopen(tmp_filename, "wb+");
fprintf(stderr, "result = %p\n", result);
}
if (result != NULL && tmp_filename_out) {
*tmp_filename_out = gpr_strdup(tmp_filename);
}
return result;
}
#endif /* GPR_MSYS_TMPFILE */

@ -33,7 +33,7 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_FILE
#ifdef GPR_POSIX_TMPFILE
#include "src/core/lib/support/tmpfile.h"
@ -82,4 +82,4 @@ end:
return result;
}
#endif /* GPR_POSIX_FILE */
#endif /* GPR_POSIX_TMPFILE */

@ -33,7 +33,7 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#ifdef GPR_WIN32_TMPFILE
#include <io.h>
#include <stdio.h>
@ -81,4 +81,4 @@ end:
return result;
}
#endif /* GPR_WIN32 */
#endif /* GPR_WIN32_TMPFILE */

@ -373,8 +373,6 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
if (c->receiving_stream != NULL) {
grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
}
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->stats);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call");
gpr_mu_destroy(&c->mu);
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
if (c->status[i].details) {
@ -392,7 +390,9 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
if (c->cq) {
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
}
gpr_free(c);
grpc_channel *channel = c->channel;
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->stats, c);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
GPR_TIMER_END("destroy_call", 0);
}
@ -1517,3 +1517,39 @@ grpc_compression_algorithm grpc_call_compression_for_level(
gpr_mu_unlock(&call->mu);
return grpc_compression_algorithm_for_level(level, accepted_encodings);
}
const char *grpc_call_error_to_string(grpc_call_error error) {
switch (error) {
case GRPC_CALL_ERROR:
return "GRPC_CALL_ERROR";
case GRPC_CALL_ERROR_ALREADY_ACCEPTED:
return "GRPC_CALL_ERROR_ALREADY_ACCEPTED";
case GRPC_CALL_ERROR_ALREADY_FINISHED:
return "GRPC_CALL_ERROR_ALREADY_FINISHED";
case GRPC_CALL_ERROR_ALREADY_INVOKED:
return "GRPC_CALL_ERROR_ALREADY_INVOKED";
case GRPC_CALL_ERROR_BATCH_TOO_BIG:
return "GRPC_CALL_ERROR_BATCH_TOO_BIG";
case GRPC_CALL_ERROR_INVALID_FLAGS:
return "GRPC_CALL_ERROR_INVALID_FLAGS";
case GRPC_CALL_ERROR_INVALID_MESSAGE:
return "GRPC_CALL_ERROR_INVALID_MESSAGE";
case GRPC_CALL_ERROR_INVALID_METADATA:
return "GRPC_CALL_ERROR_INVALID_METADATA";
case GRPC_CALL_ERROR_NOT_INVOKED:
return "GRPC_CALL_ERROR_NOT_INVOKED";
case GRPC_CALL_ERROR_NOT_ON_CLIENT:
return "GRPC_CALL_ERROR_NOT_ON_CLIENT";
case GRPC_CALL_ERROR_NOT_ON_SERVER:
return "GRPC_CALL_ERROR_NOT_ON_SERVER";
case GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE:
return "GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE";
case GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH:
return "GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH";
case GRPC_CALL_ERROR_TOO_MANY_OPERATIONS:
return "GRPC_CALL_ERROR_TOO_MANY_OPERATIONS";
case GRPC_CALL_OK:
return "GRPC_CALL_OK";
}
GPR_UNREACHABLE_CODE(return "GRPC_CALL_ERROR_UNKNOW");
}

@ -227,6 +227,10 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
#endif
GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
GRPC_API_TRACE(
"grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, success=%d, done=%p, "
"done_arg=%p, storage=%p)",
7, (exec_ctx, cc, tag, success, done, done_arg, storage));
storage->tag = tag;
storage->done = done;

@ -164,10 +164,10 @@ void grpc_init(void) {
grpc_register_tracer("channel_stack_builder",
&grpc_trace_channel_stack_builder);
grpc_register_tracer("http1", &grpc_http1_trace);
grpc_register_tracer("compression", &grpc_compress_filter_trace);
grpc_security_pre_init();
grpc_iomgr_init();
grpc_executor_init();
grpc_tracer_init("GRPC_TRACE");
gpr_timers_global_init();
grpc_cq_global_init();
for (i = 0; i < g_number_of_plugins; i++) {
@ -179,6 +179,7 @@ void grpc_init(void) {
* at the appropriate time */
grpc_register_security_filters();
register_builtin_channel_init();
grpc_tracer_init("GRPC_TRACE");
/* no more changes to channel init pipelines */
grpc_channel_init_finalize();
}

@ -108,7 +108,10 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {}
const grpc_call_stats *stats,
void *and_free_memory) {
gpr_free(and_free_memory);
}
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,

@ -821,7 +821,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats) {
const grpc_call_stats *stats,
void *ignored) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;

@ -133,8 +133,9 @@ void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
grpc_stream *stream) {
transport->vtable->destroy_stream(exec_ctx, transport, stream);
grpc_stream *stream, void *and_free_memory) {
transport->vtable->destroy_stream(exec_ctx, transport, stream,
and_free_memory);
}
char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,

@ -98,6 +98,11 @@ void grpc_transport_move_stats(grpc_transport_stream_stats *from,
/* Transport stream op: a set of operations to perform on a transport
against a single stream */
typedef struct grpc_transport_stream_op {
/** Should be enqueued when all requested operations (excluding recv_message
and recv_initial_metadata which have their own closures) in a given batch
have been completed. */
grpc_closure *on_complete;
/** Send initial metadata to the peer, from the provided metadata batch.
idempotent_request MUST be set if this is non-null */
grpc_metadata_batch *send_initial_metadata;
@ -129,11 +134,6 @@ typedef struct grpc_transport_stream_op {
/** Collect any stats into provided buffer, zero internal stat counters */
grpc_transport_stream_stats *collect_stats;
/** Should be enqueued when all requested operations (excluding recv_message
and recv_initial_metadata which have their own closures) in a given batch
have been completed. */
grpc_closure *on_complete;
/** If != GRPC_STATUS_OK, cancel this stream */
grpc_status_code cancel_with_status;
@ -213,7 +213,7 @@ void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
caller, but any child memory must be cleaned up) */
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
grpc_stream *stream);
grpc_stream *stream, void *and_free_memory);
void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op);

@ -63,7 +63,7 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_destroy_stream */
void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
grpc_stream *stream);
grpc_stream *stream, void *and_free_memory);
/* implementation of grpc_transport_destroy */
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self);

@ -1,5 +1,35 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: math.proto
// Original file comments:
// 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.
//
#region Designer generated code
using System;
@ -45,56 +75,140 @@ namespace Math {
__Marshaller_Num,
__Marshaller_Num);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Math.MathReflection.Descriptor.Services[0]; }
}
// client interface
/// <summary>Client for Math</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IMathClient
{
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options);
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options);
/// <summary>
/// DivMany accepts an arbitrary number of division args from the client stream
/// and sends back the results in the reply stream. The stream continues until
/// the client closes its end; the server does the same after sending all the
/// replies. The stream ends immediately if either end aborts.
/// </summary>
AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// DivMany accepts an arbitrary number of division args from the client stream
/// and sends back the results in the reply stream. The stream continues until
/// the client closes its end; the server does the same after sending all the
/// replies. The stream ends immediately if either end aborts.
/// </summary>
AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options);
/// <summary>
/// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options);
/// <summary>
/// Sum sums a stream of numbers, returning the final result once the stream
/// is closed.
/// </summary>
AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Sum sums a stream of numbers, returning the final result once the stream
/// is closed.
/// </summary>
AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of Math</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IMath
{
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context);
/// <summary>
/// DivMany accepts an arbitrary number of division args from the client stream
/// and sends back the results in the reply stream. The stream continues until
/// the client closes its end; the server does the same after sending all the
/// replies. The stream ends immediately if either end aborts.
/// </summary>
Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context);
/// <summary>
/// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context);
/// <summary>
/// Sum sums a stream of numbers, returning the final result once the stream
/// is closed.
/// </summary>
Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of Math</summary>
public abstract class MathBase
{
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
public virtual Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// DivMany accepts an arbitrary number of division args from the client stream
/// and sends back the results in the reply stream. The stream continues until
/// the client closes its end; the server does the same after sending all the
/// replies. The stream ends immediately if either end aborts.
/// </summary>
public virtual Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
public virtual Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// Sum sums a stream of numbers, returning the final result once the stream
/// is closed.
/// </summary>
public virtual Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@ -102,7 +216,7 @@ namespace Math {
}
// client stub
/// <summary>Client for Math</summary>
#pragma warning disable 0618
public class MathClient : ClientBase<MathClient>, IMathClient
#pragma warning restore 0618
@ -122,42 +236,88 @@ namespace Math {
{
}
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
public virtual global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return Div(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
public virtual global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request);
}
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return DivAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Div divides args.dividend by args.divisor and returns the quotient and
/// remainder.
/// </summary>
public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_Div, null, options, request);
}
/// <summary>
/// DivMany accepts an arbitrary number of division args from the client stream
/// and sends back the results in the reply stream. The stream continues until
/// the client closes its end; the server does the same after sending all the
/// replies. The stream ends immediately if either end aborts.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return DivMany(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// DivMany accepts an arbitrary number of division args from the client stream
/// and sends back the results in the reply stream. The stream continues until
/// the client closes its end; the server does the same after sending all the
/// replies. The stream ends immediately if either end aborts.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_DivMany, null, options);
}
/// <summary>
/// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return Fib(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options)
{
return CallInvoker.AsyncServerStreamingCall(__Method_Fib, null, options, request);
}
/// <summary>
/// Sum sums a stream of numbers, returning the final result once the stream
/// is closed.
/// </summary>
public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return Sum(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Sum sums a stream of numbers, returning the final result once the stream
/// is closed.
/// </summary>
public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options)
{
return CallInvoker.AsyncClientStreamingCall(__Method_Sum, null, options);
@ -168,7 +328,13 @@ namespace Math {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for Math</summary>
public static MathClient NewClient(Channel channel)
{
return new MathClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IMath serviceImpl)
#pragma warning restore 0618
@ -180,7 +346,7 @@ namespace Math {
.AddMethod(__Method_Sum, serviceImpl.Sum).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(MathBase serviceImpl)
#pragma warning restore 0618
@ -192,12 +358,6 @@ namespace Math {
.AddMethod(__Method_Sum, serviceImpl.Sum).Build();
}
// creates a new client
public static MathClient NewClient(Channel channel)
{
return new MathClient(channel);
}
}
}
#endregion

@ -1,5 +1,35 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: health.proto
// Original file comments:
// 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.
//
#region Designer generated code
using System;
@ -22,13 +52,13 @@ namespace Grpc.Health.V1 {
__Marshaller_HealthCheckRequest,
__Marshaller_HealthCheckResponse);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Health.V1.HealthReflection.Descriptor.Services[0]; }
}
// client interface
/// <summary>Client for Health</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IHealthClient
{
@ -38,14 +68,14 @@ namespace Grpc.Health.V1 {
AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of Health</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IHealth
{
Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of Health</summary>
public abstract class HealthBase
{
public virtual Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context)
@ -55,7 +85,7 @@ namespace Grpc.Health.V1 {
}
// client stub
/// <summary>Client for Health</summary>
#pragma warning disable 0618
public class HealthClient : ClientBase<HealthClient>, IHealthClient
#pragma warning restore 0618
@ -97,7 +127,13 @@ namespace Grpc.Health.V1 {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for Health</summary>
public static HealthClient NewClient(Channel channel)
{
return new HealthClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IHealth serviceImpl)
#pragma warning restore 0618
@ -106,7 +142,7 @@ namespace Grpc.Health.V1 {
.AddMethod(__Method_Check, serviceImpl.Check).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(HealthBase serviceImpl)
#pragma warning restore 0618
@ -115,12 +151,6 @@ namespace Grpc.Health.V1 {
.AddMethod(__Method_Check, serviceImpl.Check).Build();
}
// creates a new client
public static HealthClient NewClient(Channel channel)
{
return new HealthClient(channel);
}
}
}
#endregion

@ -494,7 +494,8 @@ namespace Grpc.IntegrationTesting
}
var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
Assert.AreEqual(StatusCode.DeadlineExceeded, ex.Status.StatusCode);
// We can't guarantee the status code always DeadlineExceeded. See issue #2685.
Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
}
Console.WriteLine("Passed!");
}

@ -1,5 +1,41 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/metrics.proto
// Original file comments:
// Copyright 2015-2016, 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.
//
// Contains the definitions for a metrics service and the type of metrics
// exposed by the service.
//
// Currently, 'Gauge' (i.e a metric that represents the measured value of
// something at an instant of time) is the only metric type supported by the
// service.
#region Designer generated code
using System;
@ -30,40 +66,74 @@ namespace Grpc.Testing {
__Marshaller_GaugeRequest,
__Marshaller_GaugeResponse);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.MetricsReflection.Descriptor.Services[0]; }
}
// client interface
/// <summary>Client for MetricsService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IMetricsServiceClient
{
/// <summary>
/// Returns the values of all the gauges that are currently being maintained by
/// the service
/// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Returns the values of all the gauges that are currently being maintained by
/// the service
/// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options);
/// <summary>
/// Returns the value of one gauge
/// </summary>
global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Returns the value of one gauge
/// </summary>
global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options);
/// <summary>
/// Returns the value of one gauge
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Returns the value of one gauge
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of MetricsService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IMetricsService
{
/// <summary>
/// Returns the values of all the gauges that are currently being maintained by
/// the service
/// </summary>
Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context);
/// <summary>
/// Returns the value of one gauge
/// </summary>
Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of MetricsService</summary>
public abstract class MetricsServiceBase
{
/// <summary>
/// Returns the values of all the gauges that are currently being maintained by
/// the service
/// </summary>
public virtual Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// Returns the value of one gauge
/// </summary>
public virtual Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@ -71,7 +141,7 @@ namespace Grpc.Testing {
}
// client stub
/// <summary>Client for MetricsService</summary>
#pragma warning disable 0618
public class MetricsServiceClient : ClientBase<MetricsServiceClient>, IMetricsServiceClient
#pragma warning restore 0618
@ -91,26 +161,46 @@ namespace Grpc.Testing {
{
}
/// <summary>
/// Returns the values of all the gauges that are currently being maintained by
/// the service
/// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return GetAllGauges(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Returns the values of all the gauges that are currently being maintained by
/// the service
/// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options)
{
return CallInvoker.AsyncServerStreamingCall(__Method_GetAllGauges, null, options, request);
}
/// <summary>
/// Returns the value of one gauge
/// </summary>
public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return GetGauge(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Returns the value of one gauge
/// </summary>
public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_GetGauge, null, options, request);
}
/// <summary>
/// Returns the value of one gauge
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return GetGaugeAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Returns the value of one gauge
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_GetGauge, null, options, request);
@ -121,7 +211,13 @@ namespace Grpc.Testing {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for MetricsService</summary>
public static MetricsServiceClient NewClient(Channel channel)
{
return new MetricsServiceClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IMetricsService serviceImpl)
#pragma warning restore 0618
@ -131,7 +227,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(MetricsServiceBase serviceImpl)
#pragma warning restore 0618
@ -141,12 +237,6 @@ namespace Grpc.Testing {
.AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
}
// creates a new client
public static MetricsServiceClient NewClient(Channel channel)
{
return new MetricsServiceClient(channel);
}
}
}
#endregion

@ -1,5 +1,37 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/services.proto
// Original file comments:
// 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.
//
// An integration test service that covers all the method signature permutations
// of unary/streaming requests/responses.
#region Designer generated code
using System;
@ -29,40 +61,80 @@ namespace Grpc.Testing {
__Marshaller_SimpleRequest,
__Marshaller_SimpleResponse);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[0]; }
}
// client interface
/// <summary>Client for BenchmarkService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IBenchmarkServiceClient
{
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of BenchmarkService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IBenchmarkService
{
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of BenchmarkService</summary>
public abstract class BenchmarkServiceBase
{
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@ -70,7 +142,7 @@ namespace Grpc.Testing {
}
// client stub
/// <summary>Client for BenchmarkService</summary>
#pragma warning disable 0618
public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>, IBenchmarkServiceClient
#pragma warning restore 0618
@ -90,26 +162,50 @@ namespace Grpc.Testing {
{
}
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
}
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
}
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return StreamingCall(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One request followed by one response.
/// The server returns the client payload as-is.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_StreamingCall, null, options);
@ -120,7 +216,13 @@ namespace Grpc.Testing {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for BenchmarkService</summary>
public static BenchmarkServiceClient NewClient(Channel channel)
{
return new BenchmarkServiceClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
#pragma warning restore 0618
@ -130,7 +232,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(BenchmarkServiceBase serviceImpl)
#pragma warning restore 0618
@ -140,12 +242,6 @@ namespace Grpc.Testing {
.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
}
// creates a new client
public static BenchmarkServiceClient NewClient(Channel channel)
{
return new BenchmarkServiceClient(channel);
}
}
public static class WorkerService
{
@ -187,58 +283,158 @@ namespace Grpc.Testing {
__Marshaller_Void,
__Marshaller_Void);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[1]; }
}
// client interface
/// <summary>Client for WorkerService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IWorkerServiceClient
{
/// <summary>
/// Start server with specified workload.
/// First request sent specifies the ServerConfig followed by ServerStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test server
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Start server with specified workload.
/// First request sent specifies the ServerConfig followed by ServerStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test server
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options);
/// <summary>
/// Start client with specified workload.
/// First request sent specifies the ClientConfig followed by ClientStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test client
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Start client with specified workload.
/// First request sent specifies the ClientConfig followed by ClientStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test client
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options);
/// <summary>
/// Just return the core count - unary call
/// </summary>
global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Just return the core count - unary call
/// </summary>
global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options);
/// <summary>
/// Just return the core count - unary call
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Just return the core count - unary call
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options);
/// <summary>
/// Quit this worker
/// </summary>
global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Quit this worker
/// </summary>
global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options);
/// <summary>
/// Quit this worker
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Quit this worker
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of WorkerService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IWorkerService
{
/// <summary>
/// Start server with specified workload.
/// First request sent specifies the ServerConfig followed by ServerStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test server
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
/// <summary>
/// Start client with specified workload.
/// First request sent specifies the ClientConfig followed by ClientStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test client
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
/// <summary>
/// Just return the core count - unary call
/// </summary>
Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context);
/// <summary>
/// Quit this worker
/// </summary>
Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of WorkerService</summary>
public abstract class WorkerServiceBase
{
/// <summary>
/// Start server with specified workload.
/// First request sent specifies the ServerConfig followed by ServerStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test server
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
public virtual Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// Start client with specified workload.
/// First request sent specifies the ClientConfig followed by ClientStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test client
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
public virtual Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// Just return the core count - unary call
/// </summary>
public virtual Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// Quit this worker
/// </summary>
public virtual Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@ -246,7 +442,7 @@ namespace Grpc.Testing {
}
// client stub
/// <summary>Client for WorkerService</summary>
#pragma warning disable 0618
public class WorkerServiceClient : ClientBase<WorkerServiceClient>, IWorkerServiceClient
#pragma warning restore 0618
@ -266,50 +462,106 @@ namespace Grpc.Testing {
{
}
/// <summary>
/// Start server with specified workload.
/// First request sent specifies the ServerConfig followed by ServerStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test server
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return RunServer(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Start server with specified workload.
/// First request sent specifies the ServerConfig followed by ServerStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test server
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_RunServer, null, options);
}
/// <summary>
/// Start client with specified workload.
/// First request sent specifies the ClientConfig followed by ClientStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test client
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return RunClient(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Start client with specified workload.
/// First request sent specifies the ClientConfig followed by ClientStatus
/// response. After that, a "Mark" can be sent anytime to request the latest
/// stats. Closing the stream will initiate shutdown of the test client
/// and once the shutdown has finished, the OK status is sent to terminate
/// this RPC.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_RunClient, null, options);
}
/// <summary>
/// Just return the core count - unary call
/// </summary>
public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return CoreCount(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Just return the core count - unary call
/// </summary>
public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_CoreCount, null, options, request);
}
/// <summary>
/// Just return the core count - unary call
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return CoreCountAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Just return the core count - unary call
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_CoreCount, null, options, request);
}
/// <summary>
/// Quit this worker
/// </summary>
public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return QuitWorker(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Quit this worker
/// </summary>
public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_QuitWorker, null, options, request);
}
/// <summary>
/// Quit this worker
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return QuitWorkerAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// Quit this worker
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_QuitWorker, null, options, request);
@ -320,7 +572,13 @@ namespace Grpc.Testing {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for WorkerService</summary>
public static WorkerServiceClient NewClient(Channel channel)
{
return new WorkerServiceClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
#pragma warning restore 0618
@ -332,7 +590,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(WorkerServiceBase serviceImpl)
#pragma warning restore 0618
@ -344,12 +602,6 @@ namespace Grpc.Testing {
.AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
}
// creates a new client
public static WorkerServiceClient NewClient(Channel channel)
{
return new WorkerServiceClient(channel);
}
}
}
#endregion

@ -1,5 +1,38 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/test.proto
// Original file comments:
// Copyright 2015-2016, 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.
//
// An integration test service that covers all the method signature permutations
// of unary/streaming requests/responses.
//
#region Designer generated code
using System;
@ -8,6 +41,10 @@ using System.Threading.Tasks;
using Grpc.Core;
namespace Grpc.Testing {
/// <summary>
/// A simple service to test the various types of RPCs and experiment with
/// performance with various types of payload.
/// </summary>
public static class TestService
{
static readonly string __ServiceName = "grpc.testing.TestService";
@ -62,74 +99,186 @@ namespace Grpc.Testing {
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[0]; }
}
// client interface
/// <summary>Client for TestService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface ITestServiceClient
{
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options);
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
/// <summary>
/// One request followed by one response.
/// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One request followed by one response.
/// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
/// <summary>
/// One request followed by one response.
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One request followed by one response.
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
/// <summary>
/// One request followed by a sequence of responses (streamed download).
/// The server returns the payload with client desired type and sizes.
/// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// One request followed by a sequence of responses (streamed download).
/// The server returns the payload with client desired type and sizes.
/// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options);
/// <summary>
/// A sequence of requests followed by one response (streamed upload).
/// The server returns the aggregated size of client payload as the result.
/// </summary>
AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// A sequence of requests followed by one response (streamed upload).
/// The server returns the aggregated size of client payload as the result.
/// </summary>
AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
/// <summary>
/// A sequence of requests with each request served by the server immediately.
/// As one request could lead to multiple responses, this interface
/// demonstrates the idea of full duplexing.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// A sequence of requests with each request served by the server immediately.
/// As one request could lead to multiple responses, this interface
/// demonstrates the idea of full duplexing.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
/// <summary>
/// A sequence of requests followed by a sequence of responses.
/// The server buffers all the client requests and then serves them in order. A
/// stream of responses are returned to the client when the server starts with
/// first request.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// A sequence of requests followed by a sequence of responses.
/// The server buffers all the client requests and then serves them in order. A
/// stream of responses are returned to the client when the server starts with
/// first request.
/// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of TestService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface ITestService
{
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context);
/// <summary>
/// One request followed by one response.
/// </summary>
Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
/// <summary>
/// One request followed by a sequence of responses (streamed download).
/// The server returns the payload with client desired type and sizes.
/// </summary>
Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
/// <summary>
/// A sequence of requests followed by one response (streamed upload).
/// The server returns the aggregated size of client payload as the result.
/// </summary>
Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
/// <summary>
/// A sequence of requests with each request served by the server immediately.
/// As one request could lead to multiple responses, this interface
/// demonstrates the idea of full duplexing.
/// </summary>
Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
/// <summary>
/// A sequence of requests followed by a sequence of responses.
/// The server buffers all the client requests and then serves them in order. A
/// stream of responses are returned to the client when the server starts with
/// first request.
/// </summary>
Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of TestService</summary>
public abstract class TestServiceBase
{
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
public virtual Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// One request followed by one response.
/// </summary>
public virtual Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// One request followed by a sequence of responses (streamed download).
/// The server returns the payload with client desired type and sizes.
/// </summary>
public virtual Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// A sequence of requests followed by one response (streamed upload).
/// The server returns the aggregated size of client payload as the result.
/// </summary>
public virtual Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// A sequence of requests with each request served by the server immediately.
/// As one request could lead to multiple responses, this interface
/// demonstrates the idea of full duplexing.
/// </summary>
public virtual Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
/// <summary>
/// A sequence of requests followed by a sequence of responses.
/// The server buffers all the client requests and then serves them in order. A
/// stream of responses are returned to the client when the server starts with
/// first request.
/// </summary>
public virtual Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@ -137,7 +286,7 @@ namespace Grpc.Testing {
}
// client stub
/// <summary>Client for TestService</summary>
#pragma warning disable 0618
public class TestServiceClient : ClientBase<TestServiceClient>, ITestServiceClient
#pragma warning restore 0618
@ -157,66 +306,128 @@ namespace Grpc.Testing {
{
}
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return EmptyCall(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_EmptyCall, null, options, request);
}
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return EmptyCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One empty request followed by one empty response.
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_EmptyCall, null, options, request);
}
/// <summary>
/// One request followed by one response.
/// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One request followed by one response.
/// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
}
/// <summary>
/// One request followed by one response.
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One request followed by one response.
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
}
/// <summary>
/// One request followed by a sequence of responses (streamed download).
/// The server returns the payload with client desired type and sizes.
/// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return StreamingOutputCall(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// One request followed by a sequence of responses (streamed download).
/// The server returns the payload with client desired type and sizes.
/// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options)
{
return CallInvoker.AsyncServerStreamingCall(__Method_StreamingOutputCall, null, options, request);
}
/// <summary>
/// A sequence of requests followed by one response (streamed upload).
/// The server returns the aggregated size of client payload as the result.
/// </summary>
public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return StreamingInputCall(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// A sequence of requests followed by one response (streamed upload).
/// The server returns the aggregated size of client payload as the result.
/// </summary>
public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
{
return CallInvoker.AsyncClientStreamingCall(__Method_StreamingInputCall, null, options);
}
/// <summary>
/// A sequence of requests with each request served by the server immediately.
/// As one request could lead to multiple responses, this interface
/// demonstrates the idea of full duplexing.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return FullDuplexCall(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// A sequence of requests with each request served by the server immediately.
/// As one request could lead to multiple responses, this interface
/// demonstrates the idea of full duplexing.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_FullDuplexCall, null, options);
}
/// <summary>
/// A sequence of requests followed by a sequence of responses.
/// The server buffers all the client requests and then serves them in order. A
/// stream of responses are returned to the client when the server starts with
/// first request.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return HalfDuplexCall(new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// A sequence of requests followed by a sequence of responses.
/// The server buffers all the client requests and then serves them in order. A
/// stream of responses are returned to the client when the server starts with
/// first request.
/// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_HalfDuplexCall, null, options);
@ -227,7 +438,13 @@ namespace Grpc.Testing {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for TestService</summary>
public static TestServiceClient NewClient(Channel channel)
{
return new TestServiceClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(ITestService serviceImpl)
#pragma warning restore 0618
@ -241,7 +458,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(TestServiceBase serviceImpl)
#pragma warning restore 0618
@ -255,13 +472,11 @@ namespace Grpc.Testing {
.AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
}
// creates a new client
public static TestServiceClient NewClient(Channel channel)
{
return new TestServiceClient(channel);
}
}
/// <summary>
/// A simple service NOT implemented at servers so clients can test for
/// that case.
/// </summary>
public static class UnimplementedService
{
static readonly string __ServiceName = "grpc.testing.UnimplementedService";
@ -275,32 +490,50 @@ namespace Grpc.Testing {
__Marshaller_Empty,
__Marshaller_Empty);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[1]; }
}
// client interface
/// <summary>Client for UnimplementedService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IUnimplementedServiceClient
{
/// <summary>
/// A call that no server should implement
/// </summary>
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// A call that no server should implement
/// </summary>
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
/// <summary>
/// A call that no server should implement
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// A call that no server should implement
/// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of UnimplementedService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IUnimplementedService
{
/// <summary>
/// A call that no server should implement
/// </summary>
Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of UnimplementedService</summary>
public abstract class UnimplementedServiceBase
{
/// <summary>
/// A call that no server should implement
/// </summary>
public virtual Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@ -308,7 +541,7 @@ namespace Grpc.Testing {
}
// client stub
/// <summary>Client for UnimplementedService</summary>
#pragma warning disable 0618
public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>, IUnimplementedServiceClient
#pragma warning restore 0618
@ -328,18 +561,30 @@ namespace Grpc.Testing {
{
}
/// <summary>
/// A call that no server should implement
/// </summary>
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnimplementedCall(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// A call that no server should implement
/// </summary>
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_UnimplementedCall, null, options, request);
}
/// <summary>
/// A call that no server should implement
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnimplementedCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
/// A call that no server should implement
/// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_UnimplementedCall, null, options, request);
@ -350,7 +595,13 @@ namespace Grpc.Testing {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for UnimplementedService</summary>
public static UnimplementedServiceClient NewClient(Channel channel)
{
return new UnimplementedServiceClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
#pragma warning restore 0618
@ -359,7 +610,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(UnimplementedServiceBase serviceImpl)
#pragma warning restore 0618
@ -368,13 +619,10 @@ namespace Grpc.Testing {
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
// creates a new client
public static UnimplementedServiceClient NewClient(Channel channel)
{
return new UnimplementedServiceClient(channel);
}
}
/// <summary>
/// A service used to control reconnect server.
/// </summary>
public static class ReconnectService
{
static readonly string __ServiceName = "grpc.testing.ReconnectService";
@ -397,13 +645,13 @@ namespace Grpc.Testing {
__Marshaller_Empty,
__Marshaller_ReconnectInfo);
// service descriptor
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[2]; }
}
// client interface
/// <summary>Client for ReconnectService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IReconnectServiceClient
{
@ -417,7 +665,7 @@ namespace Grpc.Testing {
AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
// server-side interface
/// <summary>Interface of server-side implementations of ReconnectService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IReconnectService
{
@ -425,7 +673,7 @@ namespace Grpc.Testing {
Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
}
// server-side abstract class
/// <summary>Base class for server-side implementations of ReconnectService</summary>
public abstract class ReconnectServiceBase
{
public virtual Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.ReconnectParams request, ServerCallContext context)
@ -440,7 +688,7 @@ namespace Grpc.Testing {
}
// client stub
/// <summary>Client for ReconnectService</summary>
#pragma warning disable 0618
public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>, IReconnectServiceClient
#pragma warning restore 0618
@ -498,7 +746,13 @@ namespace Grpc.Testing {
}
}
// creates service definition that can be registered with a server
/// <summary>Creates a new client for ReconnectService</summary>
public static ReconnectServiceClient NewClient(Channel channel)
{
return new ReconnectServiceClient(channel);
}
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
#pragma warning restore 0618
@ -508,7 +762,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
// creates service definition that can be registered with a server
/// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(ReconnectServiceBase serviceImpl)
#pragma warning restore 0618
@ -518,12 +772,6 @@ namespace Grpc.Testing {
.AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
// creates a new client
public static ReconnectServiceClient NewClient(Channel channel)
{
return new ReconnectServiceClient(channel);
}
}
}
#endregion

@ -35,6 +35,8 @@
#include <nan.h>
#include <v8.h>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/alloc.h"
#include "call.h"
#include "call_credentials.h"
@ -51,6 +53,8 @@ using v8::Object;
using v8::Uint32;
using v8::String;
static char *pem_root_certs = NULL;
void InitStatusConstants(Local<Object> exports) {
Nan::HandleScope scope;
Local<Object> status = Nan::New<Object>();
@ -268,9 +272,36 @@ NAN_METHOD(MetadataKeyIsBinary) {
grpc_is_binary_header(key_str, static_cast<size_t>(key->Length()))));
}
static grpc_ssl_roots_override_result get_ssl_roots_override(
char **pem_root_certs_ptr) {
*pem_root_certs_ptr = pem_root_certs;
if (pem_root_certs == NULL) {
return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
} else {
return GRPC_SSL_ROOTS_OVERRIDE_OK;
}
}
/* This should only be called once, and only before creating any
*ServerCredentials */
NAN_METHOD(SetDefaultRootsPem) {
if (!info[0]->IsString()) {
return Nan::ThrowTypeError(
"setDefaultRootsPem's argument must be a string");
}
Nan::Utf8String utf8_roots(info[0]);
size_t length = static_cast<size_t>(utf8_roots.length());
if (length > 0) {
const char *data = *utf8_roots;
pem_root_certs = (char *)gpr_malloc((length + 1) * sizeof(char));
memcpy(pem_root_certs, data, length + 1);
}
}
void init(Local<Object> exports) {
Nan::HandleScope scope;
grpc_init();
grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
InitStatusConstants(exports);
InitCallErrorConstants(exports);
InitOpTypeConstants(exports);
@ -298,6 +329,10 @@ void init(Local<Object> exports) {
Nan::GetFunction(
Nan::New<FunctionTemplate>(MetadataKeyIsBinary)
).ToLocalChecked());
Nan::Set(exports, Nan::New("setDefaultRootsPem").ToLocalChecked(),
Nan::GetFunction(
Nan::New<FunctionTemplate>(SetDefaultRootsPem)
).ToLocalChecked());
}
NODE_MODULE(grpc_node, init)

@ -146,7 +146,9 @@ NAN_METHOD(ServerCredentials::CreateSsl) {
"createSsl's second argument must be a list of objects");
}
grpc_ssl_client_certificate_request_type client_certificate_request;
// Default to not requesting the client certificate
grpc_ssl_client_certificate_request_type client_certificate_request =
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
if (info[2]->IsBoolean()) {
client_certificate_request =
Nan::To<bool>(info[2]).FromJust()

@ -34,13 +34,10 @@
'use strict';
var path = require('path');
var fs = require('fs');
var SSL_ROOTS_PATH = path.resolve(__dirname, '..', '..', 'etc', 'roots.pem');
if (!process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH) {
process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH = SSL_ROOTS_PATH;
}
var _ = require('lodash');
var ProtoBuf = require('protobufjs');
@ -53,6 +50,8 @@ var Metadata = require('./src/metadata.js');
var grpc = require('./src/grpc_extension');
grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
/**
* Load a gRPC object from an existing ProtoBuf.Reflect object.
* @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.

@ -815,8 +815,7 @@ exports.waitForClientReady = function(client, deadline, callback) {
* @return {function(string, Object)} New client constructor
*/
exports.makeProtobufClientConstructor = function(service, options) {
var method_attrs = common.getProtobufServiceAttrs(service, service.name,
options);
var method_attrs = common.getProtobufServiceAttrs(service, options);
var deprecatedArgumentOrder = false;
if (options) {
deprecatedArgumentOrder = options.deprecatedArgumentOrder;

@ -684,6 +684,26 @@ Server.prototype.register = function(name, handler, serialize, deserialize,
return true;
};
var unimplementedStatusResponse = {
code: grpc.status.UNIMPLEMENTED,
details: 'The server does not implement this method'
};
var defaultHandler = {
unary: function(call, callback) {
callback(unimplementedStatusResponse);
},
client_stream: function(call, callback) {
callback(unimplementedStatusResponse);
},
server_stream: function(call) {
call.emit('error', unimplementedStatusResponse);
},
bidi: function(call) {
call.emit('error', unimplementedStatusResponse);
}
};
/**
* Add a service to the server, with a corresponding implementation. If you are
* generating this from a proto file, you should instead use
@ -713,16 +733,18 @@ Server.prototype.addService = function(service, implementation) {
method_type = 'unary';
}
}
var impl;
if (implementation[name] === undefined) {
throw new Error('Method handler for ' + attrs.path +
' not provided.');
console.warn('Method handler for %s expected but not provided',
attrs.path);
impl = defaultHandler[method_type];
} else {
impl = _.bind(implementation[name], implementation);
}
var serialize = attrs.responseSerialize;
var deserialize = attrs.requestDeserialize;
var register_success = self.register(attrs.path,
_.bind(implementation[name],
implementation),
serialize, deserialize, method_type);
var register_success = self.register(attrs.path, impl, serialize,
deserialize, method_type);
if (!register_success) {
throw new Error('Method handler for ' + attrs.path +
' already provided.');

@ -143,21 +143,59 @@ describe('Server.prototype.addProtoService', function() {
server.addProtoService(mathService, dummyImpls);
});
});
it('Should fail with missing handlers', function() {
assert.throws(function() {
server.addProtoService(mathService, {
'div': function() {},
'divMany': function() {},
'fib': function() {}
});
}, /math.Math.Sum/);
});
it('Should fail if the server has been started', function() {
server.start();
assert.throws(function() {
server.addProtoService(mathService, dummyImpls);
});
});
describe('Default handlers', function() {
var client;
beforeEach(function() {
server.addProtoService(mathService, {});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(mathService);
client = new Client('localhost:' + port,
grpc.credentials.createInsecure());
server.start();
});
it('should respond to a unary call with UNIMPLEMENTED', function(done) {
client.div({divisor: 4, dividend: 3}, function(error, response) {
assert(error);
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
done();
});
});
it('should respond to a client stream with UNIMPLEMENTED', function(done) {
var call = client.sum(function(error, respones) {
assert(error);
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
done();
});
call.end();
});
it('should respond to a server stream with UNIMPLEMENTED', function(done) {
var call = client.fib({limit: 5});
call.on('data', function(value) {
assert.fail('No messages expected');
});
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
done();
});
});
it('should respond to a bidi call with UNIMPLEMENTED', function(done) {
var call = client.divMany();
call.on('data', function(value) {
assert.fail('No messages expected');
});
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
done();
});
call.end();
});
});
});
describe('Client constructor building', function() {
var illegal_service_attrs = {

@ -0,0 +1,54 @@
#!/usr/bin/env node
/*
*
* 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.
*
*/
/**
* This file is required because package.json cannot reference a file that
* is not distributed with the package, and we use node-pre-gyp to distribute
* the plugin binary
*/
'use strict';
var path = require('path');
var execFile = require('child_process').execFile;
var protoc = path.resolve(__dirname, 'grpc_node_plugin');
execFile(protoc, process.argv.slice(2), function(error, stdout, stderr) {
if (error) {
throw error;
}
console.log(stdout);
console.log(stderr);
});

@ -16,7 +16,8 @@
}
],
"bin": {
"grpc-tools-protoc": "./bin/protoc.js"
"grpc-tools-protoc": "./bin/protoc.js",
"grpc-tools-plugin": "./bin/protoc_plugin.js"
},
"scripts": {
"install": "./node_modules/.bin/node-pre-gyp install"
@ -32,6 +33,7 @@
"files": [
"index.js",
"bin/protoc.js",
"bin/protoc_plugin.js",
"LICENSE"
],
"main": "index.js"

@ -0,0 +1,56 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#import "GRPCCall.h"
/** Helpers for setting TLS Trusted Roots, Client Certificates, and Private Key */
@interface GRPCCall (ChannelCredentials)
/**
* Use the provided @c pemRootCert as the set of trusted root Certificate Authorities for @c host.
*/
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert
forHost:(nonnull NSString *)host
error:(NSError **)errorPtr;
/**
* Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate
* Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be
* used.
*/
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
withPrivateKey:(nullable NSString *)pemPrivateKey
withCertChain:(nullable NSString *)pemCertChain
forHost:(nonnull NSString *)host
error:(NSError **)errorPtr;
@end

@ -0,0 +1,66 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#import "GRPCCall+ChannelCredentials.h"
#import "private/GRPCHost.h"
@implementation GRPCCall (ChannelCredentials)
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
withPrivateKey:(nullable NSString *)pemPrivateKey
withCertChain:(nullable NSString *)pemCertChain
forHost:(nonnull NSString *)host
error:(NSError **)errorPtr {
if (!host) {
[NSException raise:NSInvalidArgumentException
format:@"host must be provided."];
}
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
return [hostConfig setTLSPEMRootCerts:pemRootCerts
withPrivateKey:pemPrivateKey
withCertChain:pemCertChain
error:errorPtr];
}
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
forHost:(nonnull NSString *)host
error:(NSError **)errorPtr {
return [GRPCCall setTLSPEMRootCerts:pemRootCerts
withPrivateKey:nil
withCertChain:nil
forHost:host
error:errorPtr];
}
@end

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,8 +43,16 @@
if (!host || !certsPath || !testName) {
[NSException raise:NSInvalidArgumentException format:@"host, path and name must be provided."];
}
NSError *error = nil;
NSString *certs = [NSString stringWithContentsOfFile:certsPath
encoding:NSUTF8StringEncoding
error:&error];
if (error != nil) {
[NSException raise:[error localizedDescription] format:@"failed to load certs"];
}
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.pathToCertificates = certsPath;
[hostConfig setTLSPEMRootCerts:certs withPrivateKey:nil withCertChain:nil error:nil];
hostConfig.hostNameOverride = testName;
}

@ -55,18 +55,6 @@ struct grpc_channel_credentials;
*/
+ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host;
/**
* Creates a secure channel to the specified @c host using the specified @c pathToCertificates and
* @c channelArgs. Only in tests should @c pathToCertificates be nil or
* @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. Passing nil for @c pathToCertificates
* results in using the default root certificates distributed with the library. If certificates
* could not be found in any case, then @c nil is returned.
*/
+ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
pathToCertificates:(nullable NSString *)pathToCertificates
channelArgs:(nullable NSDictionary *)channelArgs;
/**
* Creates a secure channel to the specified @c host using the specified @c credentials and
* @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set.

@ -40,26 +40,6 @@
#import "GRPCCompletionQueue.h"
/**
* Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
* be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
* details available describing what went wrong.
*/
static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
// Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
// issuer). Load them as UTF8 and produce an ASCII equivalent.
NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:errorPtr];
NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES];
if (!contentInASCII.bytes) {
// Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
return NULL;
}
return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
}
void freeChannelArgs(grpc_channel_args *channel_args) {
for (size_t i = 0; i < channel_args->num_args; ++i) {
grpc_arg *arg = &channel_args->args[i];
@ -157,38 +137,6 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL channelArgs:NULL];
}
+ (GRPCChannel *)secureChannelWithHost:(NSString *)host
pathToCertificates:(NSString *)path
channelArgs:(NSDictionary *)channelArgs {
// Load default SSL certificates once.
static grpc_channel_credentials *kDefaultCertificates;
static dispatch_once_t loading;
dispatch_once(&loading, ^{
NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
// Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
NSError *error;
kDefaultCertificates = CertificatesAtPath(path, &error);
NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
"certificates, is needed to establish secure (TLS) connections. Because the file is "
"distributed with the gRPC library, this error is usually a sign that the library "
"wasn't configured correctly for your project. Error: %@",
bundle.bundlePath, defaultPath, error);
});
//TODO(jcanizales): Add NSError** parameter to the initializer.
grpc_channel_credentials *certificates = path
? CertificatesAtPath(path, NULL)
: kDefaultCertificates;
return [[GRPCChannel alloc] initWithHost:host
secure:YES
credentials:certificates
channelArgs:channelArgs];
}
+ (GRPCChannel *)secureChannelWithHost:(NSString *)host
credentials:(struct grpc_channel_credentials *)credentials
channelArgs:(NSDictionary *)channelArgs {

@ -37,23 +37,28 @@ NS_ASSUME_NONNULL_BEGIN
@class GRPCCompletionQueue;
struct grpc_call;
struct grpc_channel_credentials;
@interface GRPCHost : NSObject
@property(nonatomic, readonly) NSString *address;
@property(nonatomic, copy, nullable) NSString *userAgentPrefix;
@property(nonatomic, nullable) struct grpc_channel_credentials *channelCreds;
/** The following properties should only be modified for testing: */
@property(nonatomic, getter=isSecure) BOOL secure;
@property(nonatomic, copy, nullable) NSString *pathToCertificates;
@property(nonatomic, copy, nullable) NSString *hostNameOverride;
- (nullable instancetype)init NS_UNAVAILABLE;
/** Host objects initialized with the same address are the same. */
+ (nullable instancetype)hostWithAddress:(NSString *)address;
- (nullable instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
- (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
withPrivateKey:(nullable NSString *)pemPrivateKey
withCertChain:(nullable NSString *)pemCertChain
error:(NSError **)errorPtr;
/** Create a grpc_call object to the provided path on this host. */
- (nullable struct grpc_call *)unmanagedCallWithPath:(NSString *)path

@ -34,6 +34,7 @@
#import "GRPCHost.h"
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#import <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCCall+ChannelArg.h>
@ -56,6 +57,12 @@ NS_ASSUME_NONNULL_BEGIN
return [[self alloc] initWithAddress:address];
}
- (void)dealloc {
if (_channelCreds != nil) {
grpc_channel_credentials_release(_channelCreds);
}
}
// Default initializer.
- (nullable instancetype)initWithAddress:(NSString *)address {
if (!address) {
@ -105,6 +112,75 @@ NS_ASSUME_NONNULL_BEGIN
return [channel unmanagedCallWithPath:path completionQueue:queue];
}
- (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
withPrivateKey:(nullable NSString *)pemPrivateKey
withCertChain:(nullable NSString *)pemCertChain
error:(NSError **)errorPtr {
static NSData *kDefaultRootsASCII;
static NSError *kDefaultRootsError;
static dispatch_once_t loading;
dispatch_once(&loading, ^{
NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
// Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
NSError *error;
// Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
// issuer). Load them as UTF8 and produce an ASCII equivalent.
NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:&error];
if (contentInUTF8 == nil) {
kDefaultRootsError = error;
return;
}
kDefaultRootsASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES];
});
NSData *rootsASCII;
if (pemRootCerts != nil) {
rootsASCII = [pemRootCerts dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES];
} else {
if (kDefaultRootsASCII == nil) {
if (errorPtr) {
*errorPtr = kDefaultRootsError;
}
NSAssert(kDefaultRootsASCII, @"Could not read gRPCCertificates.bundle/roots.pem. This file, "
"with the root certificates, is needed to establish secure (TLS) connections. "
"Because the file is distributed with the gRPC library, this error is usually a sign "
"that the library wasn't configured correctly for your project. Error: %@",
kDefaultRootsError);
return NO;
}
rootsASCII = kDefaultRootsASCII;
}
grpc_channel_credentials *creds;
if (pemPrivateKey == nil && pemCertChain == nil) {
creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL);
} else {
grpc_ssl_pem_key_cert_pair key_cert_pair;
NSData *privateKeyASCII = [pemPrivateKey dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES];
NSData *certChainASCII = [pemCertChain dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES];
key_cert_pair.private_key = privateKeyASCII.bytes;
key_cert_pair.cert_chain = certChainASCII.bytes;
creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL);
}
@synchronized(self) {
if (_channelCreds != nil) {
grpc_channel_credentials_release(_channelCreds);
}
_channelCreds = creds;
}
return YES;
}
- (NSDictionary *)channelArgs {
NSMutableDictionary *args = [NSMutableDictionary dictionary];
@ -125,9 +201,16 @@ NS_ASSUME_NONNULL_BEGIN
- (GRPCChannel *)newChannel {
NSDictionary *args = [self channelArgs];
if (_secure) {
return [GRPCChannel secureChannelWithHost:_address
pathToCertificates:_pathToCertificates
channelArgs:args];
GRPCChannel *channel;
@synchronized(self) {
if (_channelCreds == nil) {
[self setTLSPEMRootCerts:nil withPrivateKey:nil withCertChain:nil error:nil];
}
channel = [GRPCChannel secureChannelWithHost:_address
credentials:_channelCreds
channelArgs:args];
}
return channel;
} else {
return [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
}
@ -145,9 +228,6 @@ NS_ASSUME_NONNULL_BEGIN
}
}
// TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride|
// have been set. Don't let set either of the latter if |secure| has been set to |NO|.
@end
NS_ASSUME_NONNULL_END

@ -23,6 +23,16 @@ Else system wide (on Ubuntu)...
$ sudo pip install grpcio
If you're on Windows make sure that you installed the :code:`pip.exe` component
when you installed Python (if not go back and install it!) then invoke:
::
$ pip.exe install grpcio
Windows users may need to invoke :code:`pip.exe` from a command line ran as
administrator.
n.b. On Windows and on Mac OS X one *must* have a recent release of :code:`pip`
to retrieve the proper wheel from PyPI. Be sure to upgrade to the latest
version!
@ -43,6 +53,9 @@ package named :code:`python-dev`).
$ pip install -rrequirements.txt
$ GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install .
You cannot currently install Python from source on Windows. Things might work
out for you in MSYS2 (follow the Linux instructions), but it isn't officially
supported at the moment.
Troubleshooting
~~~~~~~~~~~~~~~

@ -1,363 +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.
"""The RPC-service-side bridge between RPC Framework and GRPC-on-the-wire."""
import enum
import logging
import threading
import time
from grpc._adapter import _common
from grpc._adapter import _intermediary_low as _low
from grpc.framework.base import interfaces as base_interfaces
from grpc.framework.base import null
from grpc.framework.foundation import activated
from grpc.framework.foundation import logging_pool
_THREAD_POOL_SIZE = 10
@enum.unique
class _LowWrite(enum.Enum):
"""The possible categories of low-level write state."""
OPEN = 'OPEN'
ACTIVE = 'ACTIVE'
CLOSED = 'CLOSED'
def _write(call, rpc_state, payload):
serialized_payload = rpc_state.serializer(payload)
if rpc_state.write.low is _LowWrite.OPEN:
call.write(serialized_payload, call, 0)
rpc_state.write.low = _LowWrite.ACTIVE
else:
rpc_state.write.pending.append(serialized_payload)
def _status(call, rpc_state):
call.status(_low.Status(_low.Code.OK, ''), call)
rpc_state.write.low = _LowWrite.CLOSED
class ForeLink(base_interfaces.ForeLink, activated.Activated):
"""A service-side bridge between RPC Framework and the C-ish _low code."""
def __init__(
self, pool, request_deserializers, response_serializers,
root_certificates, key_chain_pairs, port=None):
"""Constructor.
Args:
pool: A thread pool.
request_deserializers: A dict from RPC method names to request object
deserializer behaviors.
response_serializers: A dict from RPC method names to response object
serializer behaviors.
root_certificates: The PEM-encoded client root certificates as a
bytestring or None.
key_chain_pairs: A sequence of PEM-encoded private key-certificate chain
pairs.
port: The port on which to serve, or None to have a port selected
automatically.
"""
self._condition = threading.Condition()
self._pool = pool
self._request_deserializers = request_deserializers
self._response_serializers = response_serializers
self._root_certificates = root_certificates
self._key_chain_pairs = key_chain_pairs
self._requested_port = port
self._rear_link = null.NULL_REAR_LINK
self._completion_queue = None
self._server = None
self._rpc_states = {}
self._spinning = False
self._port = None
def _on_stop_event(self):
self._spinning = False
self._condition.notify_all()
def _on_service_acceptance_event(self, event, server):
"""Handle a service invocation event."""
service_acceptance = event.service_acceptance
if service_acceptance is None:
return
call = service_acceptance.call
call.accept(self._completion_queue, call)
# TODO(nathaniel): Metadata support.
call.premetadata()
call.read(call)
method = service_acceptance.method
self._rpc_states[call] = _common.CommonRPCState(
_common.WriteState(_LowWrite.OPEN, _common.HighWrite.OPEN, []), 1,
self._request_deserializers[method],
self._response_serializers[method])
ticket = base_interfaces.FrontToBackTicket(
call, 0, base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT, method,
base_interfaces.ServicedSubscription.Kind.FULL, None, None,
service_acceptance.deadline - time.time())
self._rear_link.accept_front_to_back_ticket(ticket)
server.service(None)
def _on_read_event(self, event):
"""Handle data arriving during an RPC."""
call = event.tag
rpc_state = self._rpc_states.get(call, None)
if rpc_state is None:
return
sequence_number = rpc_state.sequence_number
rpc_state.sequence_number += 1
if event.bytes is None:
ticket = base_interfaces.FrontToBackTicket(
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.COMPLETION, None, None, None,
None, None)
else:
call.read(call)
ticket = base_interfaces.FrontToBackTicket(
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.CONTINUATION, None, None,
None, rpc_state.deserializer(event.bytes), None)
self._rear_link.accept_front_to_back_ticket(ticket)
def _on_write_event(self, event):
call = event.tag
rpc_state = self._rpc_states.get(call, None)
if rpc_state is None:
return
if rpc_state.write.pending:
serialized_payload = rpc_state.write.pending.pop(0)
call.write(serialized_payload, call, 0)
elif rpc_state.write.high is _common.HighWrite.CLOSED:
_status(call, rpc_state)
else:
rpc_state.write.low = _LowWrite.OPEN
def _on_complete_event(self, event):
if not event.complete_accepted:
logging.error('Complete not accepted! %s', (event,))
call = event.tag
rpc_state = self._rpc_states.pop(call, None)
if rpc_state is None:
return
sequence_number = rpc_state.sequence_number
rpc_state.sequence_number += 1
ticket = base_interfaces.FrontToBackTicket(
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None,
None, None, None, None)
self._rear_link.accept_front_to_back_ticket(ticket)
def _on_finish_event(self, event):
"""Handle termination of an RPC."""
call = event.tag
rpc_state = self._rpc_states.pop(call, None)
if rpc_state is None:
return
code = event.status.code
if code is _low.Code.OK:
return
sequence_number = rpc_state.sequence_number
rpc_state.sequence_number += 1
if code is _low.Code.CANCELLED:
ticket = base_interfaces.FrontToBackTicket(
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.CANCELLATION, None, None,
None, None, None)
elif code is _low.Code.DEADLINE_EXCEEDED:
ticket = base_interfaces.FrontToBackTicket(
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.EXPIRATION, None, None, None,
None, None)
else:
# TODO(nathaniel): Better mapping of codes to ticket-categories
ticket = base_interfaces.FrontToBackTicket(
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None,
None, None, None, None)
self._rear_link.accept_front_to_back_ticket(ticket)
def _spin(self, completion_queue, server):
while True:
event = completion_queue.get(None)
with self._condition:
if event.kind is _low.Event.Kind.STOP:
self._on_stop_event()
return
elif self._server is None:
continue
elif event.kind is _low.Event.Kind.SERVICE_ACCEPTED:
self._on_service_acceptance_event(event, server)
elif event.kind is _low.Event.Kind.READ_ACCEPTED:
self._on_read_event(event)
elif event.kind is _low.Event.Kind.WRITE_ACCEPTED:
self._on_write_event(event)
elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED:
self._on_complete_event(event)
elif event.kind is _low.Event.Kind.FINISH:
self._on_finish_event(event)
else:
logging.error('Illegal event! %s', (event,))
def _continue(self, call, payload):
rpc_state = self._rpc_states.get(call, None)
if rpc_state is None:
return
_write(call, rpc_state, payload)
def _complete(self, call, payload):
"""Handle completion of the writes of an RPC."""
rpc_state = self._rpc_states.get(call, None)
if rpc_state is None:
return
if rpc_state.write.low is _LowWrite.OPEN:
if payload is None:
_status(call, rpc_state)
else:
_write(call, rpc_state, payload)
elif rpc_state.write.low is _LowWrite.ACTIVE:
if payload is not None:
rpc_state.write.pending.append(rpc_state.serializer(payload))
else:
raise ValueError('Called to complete after having already completed!')
rpc_state.write.high = _common.HighWrite.CLOSED
def _cancel(self, call):
call.cancel()
self._rpc_states.pop(call, None)
def join_rear_link(self, rear_link):
"""See base_interfaces.ForeLink.join_rear_link for specification."""
self._rear_link = null.NULL_REAR_LINK if rear_link is None else rear_link
def _start(self):
"""Starts this ForeLink.
This method must be called before attempting to exchange tickets with this
object.
"""
with self._condition:
address = '[::]:%d' % (
0 if self._requested_port is None else self._requested_port)
self._completion_queue = _low.CompletionQueue()
if self._root_certificates is None and not self._key_chain_pairs:
self._server = _low.Server(self._completion_queue)
self._port = self._server.add_http2_addr(address)
else:
server_credentials = _low.ServerCredentials(
self._root_certificates, self._key_chain_pairs, False)
self._server = _low.Server(self._completion_queue)
self._port = self._server.add_secure_http2_addr(
address, server_credentials)
self._server.start()
self._server.service(None)
self._pool.submit(self._spin, self._completion_queue, self._server)
self._spinning = True
return self
# TODO(nathaniel): Expose graceful-shutdown semantics in which this object
# enters a state in which it finishes ongoing RPCs but refuses new ones.
def _stop(self):
"""Stops this ForeLink.
This method must be called for proper termination of this object, and no
attempts to exchange tickets with this object may be made after this method
has been called.
"""
with self._condition:
self._server.stop()
# TODO(nathaniel): Yep, this is weird. Deleting a server shouldn't have a
# behaviorally significant side-effect.
self._server = None
self._completion_queue.stop()
while self._spinning:
self._condition.wait()
self._port = None
def __enter__(self):
"""See activated.Activated.__enter__ for specification."""
return self._start()
def __exit__(self, exc_type, exc_val, exc_tb):
"""See activated.Activated.__exit__ for specification."""
self._stop()
return False
def start(self):
"""See activated.Activated.start for specification."""
return self._start()
def stop(self):
"""See activated.Activated.stop for specification."""
self._stop()
def port(self):
"""Identifies the port on which this ForeLink is servicing RPCs.
Returns:
The number of the port on which this ForeLink is servicing RPCs, or None
if this ForeLink is not currently activated and servicing RPCs.
"""
with self._condition:
return self._port
def accept_back_to_front_ticket(self, ticket):
"""See base_interfaces.ForeLink.accept_back_to_front_ticket for spec."""
with self._condition:
if self._server is None:
return
if ticket.kind is base_interfaces.BackToFrontTicket.Kind.CONTINUATION:
self._continue(ticket.operation_id, ticket.payload)
elif ticket.kind is base_interfaces.BackToFrontTicket.Kind.COMPLETION:
self._complete(ticket.operation_id, ticket.payload)
else:
self._cancel(ticket.operation_id)

@ -1,395 +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.
"""The RPC-invocation-side bridge between RPC Framework and GRPC-on-the-wire."""
import enum
import logging
import threading
import time
from grpc._adapter import _common
from grpc._adapter import _intermediary_low as _low
from grpc.framework.base import interfaces as base_interfaces
from grpc.framework.base import null
from grpc.framework.foundation import activated
from grpc.framework.foundation import logging_pool
_THREAD_POOL_SIZE = 10
_INVOCATION_EVENT_KINDS = (
_low.Event.Kind.METADATA_ACCEPTED,
_low.Event.Kind.FINISH
)
@enum.unique
class _LowWrite(enum.Enum):
"""The possible categories of low-level write state."""
OPEN = 'OPEN'
ACTIVE = 'ACTIVE'
CLOSED = 'CLOSED'
class _RPCState(object):
"""The full state of any tracked RPC.
Attributes:
call: The _low.Call object for the RPC.
outstanding: The set of Event.Kind values describing expected future events
for the RPC.
active: A boolean indicating whether or not the RPC is active.
common: An _common.RPCState describing additional state for the RPC.
"""
def __init__(self, call, outstanding, active, common):
self.call = call
self.outstanding = outstanding
self.active = active
self.common = common
def _write(operation_id, call, outstanding, write_state, serialized_payload):
if write_state.low is _LowWrite.OPEN:
call.write(serialized_payload, operation_id, 0)
outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
write_state.low = _LowWrite.ACTIVE
elif write_state.low is _LowWrite.ACTIVE:
write_state.pending.append(serialized_payload)
else:
raise ValueError('Write attempted after writes completed!')
class RearLink(base_interfaces.RearLink, activated.Activated):
"""An invocation-side bridge between RPC Framework and the C-ish _low code."""
def __init__(
self, host, port, pool, request_serializers, response_deserializers,
secure, root_certificates, private_key, certificate_chain,
metadata_transformer=None, server_host_override=None):
"""Constructor.
Args:
host: The host to which to connect for RPC service.
port: The port to which to connect for RPC service.
pool: A thread pool.
request_serializers: A dict from RPC method names to request object
serializer behaviors.
response_deserializers: A dict from RPC method names to response object
deserializer behaviors.
secure: A boolean indicating whether or not to use a secure connection.
root_certificates: The PEM-encoded root certificates or None to ask for
them to be retrieved from a default location.
private_key: The PEM-encoded private key to use or None if no private
key should be used.
certificate_chain: The PEM-encoded certificate chain to use or None if
no certificate chain should be used.
metadata_transformer: A function that given a metadata object produces
another metadata to be used in the underlying communication on the
wire.
server_host_override: (For testing only) the target name used for SSL
host name checking.
"""
self._condition = threading.Condition()
self._host = host
self._port = port
self._pool = pool
self._request_serializers = request_serializers
self._response_deserializers = response_deserializers
self._fore_link = null.NULL_FORE_LINK
self._completion_queue = None
self._channel = None
self._rpc_states = {}
self._spinning = False
if secure:
self._client_credentials = _low.ClientCredentials(
root_certificates, private_key, certificate_chain)
else:
self._client_credentials = None
self._root_certificates = root_certificates
self._private_key = private_key
self._certificate_chain = certificate_chain
self._metadata_transformer = metadata_transformer
self._server_host_override = server_host_override
def _on_write_event(self, operation_id, event, rpc_state):
if event.write_accepted:
if rpc_state.common.write.pending:
rpc_state.call.write(
rpc_state.common.write.pending.pop(0), operation_id, 0)
rpc_state.outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
elif rpc_state.common.write.high is _common.HighWrite.CLOSED:
rpc_state.call.complete(operation_id)
rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED)
rpc_state.common.write.low = _LowWrite.CLOSED
else:
rpc_state.common.write.low = _LowWrite.OPEN
else:
logging.error('RPC write not accepted! Event: %s', (event,))
rpc_state.active = False
ticket = base_interfaces.BackToFrontTicket(
operation_id, rpc_state.common.sequence_number,
base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None)
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
def _on_read_event(self, operation_id, event, rpc_state):
if event.bytes is not None:
rpc_state.call.read(operation_id)
rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED)
ticket = base_interfaces.BackToFrontTicket(
operation_id, rpc_state.common.sequence_number,
base_interfaces.BackToFrontTicket.Kind.CONTINUATION,
rpc_state.common.deserializer(event.bytes))
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
def _on_complete_event(self, operation_id, event, rpc_state):
if not event.complete_accepted:
logging.error('RPC complete not accepted! Event: %s', (event,))
rpc_state.active = False
ticket = base_interfaces.BackToFrontTicket(
operation_id, rpc_state.common.sequence_number,
base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None)
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
# TODO(nathaniel): Metadata support.
def _on_metadata_event(self, operation_id, event, rpc_state): # pylint: disable=unused-argument
rpc_state.call.read(operation_id)
rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED)
def _on_finish_event(self, operation_id, event, rpc_state):
"""Handle termination of an RPC."""
# TODO(nathaniel): Cover all statuses.
if event.status.code is _low.Code.OK:
kind = base_interfaces.BackToFrontTicket.Kind.COMPLETION
elif event.status.code is _low.Code.CANCELLED:
kind = base_interfaces.BackToFrontTicket.Kind.CANCELLATION
elif event.status.code is _low.Code.DEADLINE_EXCEEDED:
kind = base_interfaces.BackToFrontTicket.Kind.EXPIRATION
else:
kind = base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE
ticket = base_interfaces.BackToFrontTicket(
operation_id, rpc_state.common.sequence_number, kind, None)
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
def _spin(self, completion_queue):
while True:
event = completion_queue.get(None)
operation_id = event.tag
with self._condition:
rpc_state = self._rpc_states[operation_id]
rpc_state.outstanding.remove(event.kind)
if rpc_state.active and self._completion_queue is not None:
if event.kind is _low.Event.Kind.WRITE_ACCEPTED:
self._on_write_event(operation_id, event, rpc_state)
elif event.kind is _low.Event.Kind.METADATA_ACCEPTED:
self._on_metadata_event(operation_id, event, rpc_state)
elif event.kind is _low.Event.Kind.READ_ACCEPTED:
self._on_read_event(operation_id, event, rpc_state)
elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED:
self._on_complete_event(operation_id, event, rpc_state)
elif event.kind is _low.Event.Kind.FINISH:
self._on_finish_event(operation_id, event, rpc_state)
else:
logging.error('Illegal RPC event! %s', (event,))
if not rpc_state.outstanding:
self._rpc_states.pop(operation_id)
if not self._rpc_states:
self._spinning = False
self._condition.notify_all()
return
def _invoke(self, operation_id, name, high_state, payload, timeout):
"""Invoke an RPC.
Args:
operation_id: Any object to be used as an operation ID for the RPC.
name: The RPC method name.
high_state: A _common.HighWrite value representing the "high write state"
of the RPC.
payload: A payload object for the RPC or None if no payload was given at
invocation-time.
timeout: A duration of time in seconds to allow for the RPC.
"""
request_serializer = self._request_serializers[name]
call = _low.Call(self._channel, self._completion_queue, name, self._host, time.time() + timeout)
if self._metadata_transformer is not None:
metadata = self._metadata_transformer([])
for metadata_key, metadata_value in metadata:
call.add_metadata(metadata_key, metadata_value)
call.invoke(self._completion_queue, operation_id, operation_id)
outstanding = set(_INVOCATION_EVENT_KINDS)
if payload is None:
if high_state is _common.HighWrite.CLOSED:
call.complete(operation_id)
low_state = _LowWrite.CLOSED
outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED)
else:
low_state = _LowWrite.OPEN
else:
serialized_payload = request_serializer(payload)
call.write(serialized_payload, operation_id, 0)
outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
low_state = _LowWrite.ACTIVE
write_state = _common.WriteState(low_state, high_state, [])
common_state = _common.CommonRPCState(
write_state, 0, self._response_deserializers[name], request_serializer)
self._rpc_states[operation_id] = _RPCState(
call, outstanding, True, common_state)
if not self._spinning:
self._pool.submit(self._spin, self._completion_queue)
self._spinning = True
def _commence(self, operation_id, name, payload, timeout):
self._invoke(operation_id, name, _common.HighWrite.OPEN, payload, timeout)
def _continue(self, operation_id, payload):
rpc_state = self._rpc_states.get(operation_id, None)
if rpc_state is None or not rpc_state.active:
return
_write(
operation_id, rpc_state.call, rpc_state.outstanding,
rpc_state.common.write, rpc_state.common.serializer(payload))
def _complete(self, operation_id, payload):
"""Close writes associated with an ongoing RPC.
Args:
operation_id: Any object being use as an operation ID for the RPC.
payload: A payload object for the RPC (and thus the last payload object
for the RPC) or None if no payload was given along with the instruction
to indicate the end of writes for the RPC.
"""
rpc_state = self._rpc_states.get(operation_id, None)
if rpc_state is None or not rpc_state.active:
return
write_state = rpc_state.common.write
if payload is None:
if write_state.low is _LowWrite.OPEN:
rpc_state.call.complete(operation_id)
rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED)
write_state.low = _LowWrite.CLOSED
else:
_write(
operation_id, rpc_state.call, rpc_state.outstanding, write_state,
rpc_state.common.serializer(payload))
write_state.high = _common.HighWrite.CLOSED
def _entire(self, operation_id, name, payload, timeout):
self._invoke(operation_id, name, _common.HighWrite.CLOSED, payload, timeout)
def _cancel(self, operation_id):
rpc_state = self._rpc_states.get(operation_id, None)
if rpc_state is not None and rpc_state.active:
rpc_state.call.cancel()
rpc_state.active = False
def join_fore_link(self, fore_link):
"""See base_interfaces.RearLink.join_fore_link for specification."""
with self._condition:
self._fore_link = null.NULL_FORE_LINK if fore_link is None else fore_link
def _start(self):
"""Starts this RearLink.
This method must be called before attempting to exchange tickets with this
object.
"""
with self._condition:
self._completion_queue = _low.CompletionQueue()
self._channel = _low.Channel(
'%s:%d' % (self._host, self._port), self._client_credentials,
server_host_override=self._server_host_override)
return self
def _stop(self):
"""Stops this RearLink.
This method must be called for proper termination of this object, and no
attempts to exchange tickets with this object may be made after this method
has been called.
"""
with self._condition:
self._completion_queue.stop()
self._completion_queue = None
while self._spinning:
self._condition.wait()
def __enter__(self):
"""See activated.Activated.__enter__ for specification."""
return self._start()
def __exit__(self, exc_type, exc_val, exc_tb):
"""See activated.Activated.__exit__ for specification."""
self._stop()
return False
def start(self):
"""See activated.Activated.start for specification."""
return self._start()
def stop(self):
"""See activated.Activated.stop for specification."""
self._stop()
def accept_front_to_back_ticket(self, ticket):
"""See base_interfaces.RearLink.accept_front_to_back_ticket for spec."""
with self._condition:
if self._completion_queue is None:
return
if ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT:
self._commence(
ticket.operation_id, ticket.name, ticket.payload, ticket.timeout)
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CONTINUATION:
self._continue(ticket.operation_id, ticket.payload)
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMPLETION:
self._complete(ticket.operation_id, ticket.payload)
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.ENTIRE:
self._entire(
ticket.operation_id, ticket.name, ticket.payload, ticket.timeout)
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CANCELLATION:
self._cancel(ticket.operation_id)
else:
# NOTE(nathaniel): All other categories are treated as cancellation.
self._cancel(ticket.operation_id)

@ -124,6 +124,7 @@ grpc_tracer_set_enabled_type grpc_tracer_set_enabled_import;
grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
grpc_call_error_to_string_type grpc_call_error_to_string_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@ -393,6 +394,7 @@ void pygrpc_load_imports(HMODULE library) {
grpc_header_key_is_legal_import = (grpc_header_key_is_legal_type) GetProcAddress(library, "grpc_header_key_is_legal");
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");

@ -322,6 +322,9 @@ extern grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_
typedef int(*grpc_is_binary_header_type)(const char *key, size_t length);
extern grpc_is_binary_header_type grpc_is_binary_header_import;
#define grpc_is_binary_header grpc_is_binary_header_import
typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
#define grpc_call_error_to_string grpc_call_error_to_string_import
typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import

@ -1,35 +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.
import warnings
warnings.simplefilter('always', DeprecationWarning)
warnings.warn('the alpha API (includes this package) is deprecated, '
'unmaintained, and no longer tested. Please migrate to the beta '
'API.', DeprecationWarning, stacklevel=2)

@ -1,262 +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.
"""Entry points into GRPC."""
import threading
from grpc._adapter import fore as _fore
from grpc._adapter import rear as _rear
from grpc.framework.alpha import _face_utilities
from grpc.framework.alpha import _reexport
from grpc.framework.alpha import interfaces
from grpc.framework.base import implementations as _base_implementations
from grpc.framework.base import util as _base_utilities
from grpc.framework.face import implementations as _face_implementations
from grpc.framework.foundation import logging_pool
_DEFAULT_THREAD_POOL_SIZE = 8
_ONE_DAY_IN_SECONDS = 24 * 60 * 60
class _Server(interfaces.Server):
def __init__(
self, breakdown, port, private_key, certificate_chain,
thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
self._lock = threading.Lock()
self._breakdown = breakdown
self._port = port
if private_key is None or certificate_chain is None:
self._key_chain_pairs = ()
else:
self._key_chain_pairs = ((private_key, certificate_chain),)
self._pool_size = thread_pool_size
self._pool = None
self._back = None
self._fore_link = None
def _start(self):
with self._lock:
if self._pool is None:
self._pool = logging_pool.pool(self._pool_size)
servicer = _face_implementations.servicer(
self._pool, self._breakdown.implementations, None)
self._back = _base_implementations.back_link(
servicer, self._pool, self._pool, self._pool, _ONE_DAY_IN_SECONDS,
_ONE_DAY_IN_SECONDS)
self._fore_link = _fore.ForeLink(
self._pool, self._breakdown.request_deserializers,
self._breakdown.response_serializers, None, self._key_chain_pairs,
port=self._port)
self._back.join_fore_link(self._fore_link)
self._fore_link.join_rear_link(self._back)
self._fore_link.start()
else:
raise ValueError('Server currently running!')
def _stop(self):
with self._lock:
if self._pool is None:
raise ValueError('Server not running!')
else:
self._fore_link.stop()
_base_utilities.wait_for_idle(self._back)
self._pool.shutdown(wait=True)
self._fore_link = None
self._back = None
self._pool = None
def __enter__(self):
self._start()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._stop()
return False
def start(self):
self._start()
def stop(self):
self._stop()
def port(self):
with self._lock:
return self._fore_link.port()
class _Stub(interfaces.Stub):
def __init__(
self, breakdown, host, port, secure, root_certificates, private_key,
certificate_chain, metadata_transformer=None, server_host_override=None,
thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
self._lock = threading.Lock()
self._breakdown = breakdown
self._host = host
self._port = port
self._secure = secure
self._root_certificates = root_certificates
self._private_key = private_key
self._certificate_chain = certificate_chain
self._metadata_transformer = metadata_transformer
self._server_host_override = server_host_override
self._pool_size = thread_pool_size
self._pool = None
self._front = None
self._rear_link = None
self._understub = None
def __enter__(self):
with self._lock:
if self._pool is None:
self._pool = logging_pool.pool(self._pool_size)
self._front = _base_implementations.front_link(
self._pool, self._pool, self._pool)
self._rear_link = _rear.RearLink(
self._host, self._port, self._pool,
self._breakdown.request_serializers,
self._breakdown.response_deserializers, self._secure,
self._root_certificates, self._private_key, self._certificate_chain,
metadata_transformer=self._metadata_transformer,
server_host_override=self._server_host_override)
self._front.join_rear_link(self._rear_link)
self._rear_link.join_fore_link(self._front)
self._rear_link.start()
self._understub = _face_implementations.dynamic_stub(
self._breakdown.face_cardinalities, self._front, self._pool, '')
else:
raise ValueError('Tried to __enter__ already-__enter__ed Stub!')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
with self._lock:
if self._pool is None:
raise ValueError('Tried to __exit__ non-__enter__ed Stub!')
else:
self._rear_link.stop()
_base_utilities.wait_for_idle(self._front)
self._pool.shutdown(wait=True)
self._rear_link = None
self._front = None
self._pool = None
self._understub = None
return False
def __getattr__(self, attr):
with self._lock:
if self._pool is None:
raise ValueError('Tried to __getattr__ non-__enter__ed Stub!')
else:
method_cardinality = self._breakdown.cardinalities.get(attr)
underlying_attr = getattr(
self._understub, self._breakdown.qualified_names.get(attr), None)
if method_cardinality is interfaces.Cardinality.UNARY_UNARY:
return _reexport.unary_unary_sync_async(underlying_attr)
elif method_cardinality is interfaces.Cardinality.UNARY_STREAM:
return lambda request, timeout: _reexport.cancellable_iterator(
underlying_attr(request, timeout))
elif method_cardinality is interfaces.Cardinality.STREAM_UNARY:
return _reexport.stream_unary_sync_async(underlying_attr)
elif method_cardinality is interfaces.Cardinality.STREAM_STREAM:
return lambda request_iterator, timeout: (
_reexport.cancellable_iterator(underlying_attr(
request_iterator, timeout)))
else:
raise AttributeError(attr)
def stub(
service_name, methods, host, port, metadata_transformer=None, secure=False,
root_certificates=None, private_key=None, certificate_chain=None,
server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
"""Constructs an interfaces.Stub.
Args:
service_name: The package-qualified full name of the service.
methods: A dictionary from RPC method name to
interfaces.RpcMethodInvocationDescription describing the RPCs to be
supported by the created stub. The RPC method names in the dictionary are
not qualified by the service name or decorated in any other way.
host: The host to which to connect for RPC service.
port: The port to which to connect for RPC service.
metadata_transformer: A callable that given a metadata object produces
another metadata object to be used in the underlying communication on the
wire.
secure: Whether or not to construct the stub with a secure connection.
root_certificates: The PEM-encoded root certificates or None to ask for
them to be retrieved from a default location.
private_key: The PEM-encoded private key to use or None if no private key
should be used.
certificate_chain: The PEM-encoded certificate chain to use or None if no
certificate chain should be used.
server_host_override: (For testing only) the target name used for SSL
host name checking.
thread_pool_size: The maximum number of threads to allow in the backing
thread pool.
Returns:
An interfaces.Stub affording RPC invocation.
"""
breakdown = _face_utilities.break_down_invocation(service_name, methods)
return _Stub(
breakdown, host, port, secure, root_certificates, private_key,
certificate_chain, server_host_override=server_host_override,
metadata_transformer=metadata_transformer,
thread_pool_size=thread_pool_size)
def server(
service_name, methods, port, private_key=None, certificate_chain=None,
thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
"""Constructs an interfaces.Server.
Args:
service_name: The package-qualified full name of the service.
methods: A dictionary from RPC method name to
interfaces.RpcMethodServiceDescription describing the RPCs to
be serviced by the created server. The RPC method names in the dictionary
are not qualified by the service name or decorated in any other way.
port: The port on which to serve or zero to ask for a port to be
automatically selected.
private_key: A pem-encoded private key, or None for an insecure server.
certificate_chain: A pem-encoded certificate chain, or None for an insecure
server.
thread_pool_size: The maximum number of threads to allow in the backing
thread pool.
Returns:
An interfaces.Server that will serve secure traffic.
"""
breakdown = _face_utilities.break_down_service(service_name, methods)
return _Server(breakdown, port, private_key, certificate_chain,
thread_pool_size=thread_pool_size)

@ -1,35 +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.
import warnings
warnings.simplefilter('always', DeprecationWarning)
warnings.warn('the alpha API (includes this package) is deprecated, '
'unmaintained, and no longer tested. Please migrate to the beta '
'API.', DeprecationWarning, stacklevel=2)

@ -1,183 +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.
import abc
import collections
import six
# face_interfaces is referenced from specification in this module.
from grpc.framework.common import cardinality
from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import
from grpc.framework.face import utilities as face_utilities
from grpc.framework.alpha import _reexport
from grpc.framework.alpha import interfaces
def _qualified_name(service_name, method_name):
return '/%s/%s' % (service_name, method_name)
# TODO(nathaniel): This structure is getting bloated; it could be shrunk if
# implementations._Stub used a generic rather than a dynamic underlying
# face-layer stub.
class InvocationBreakdown(six.with_metaclass(abc.ABCMeta)):
"""An intermediate representation of invocation-side views of RPC methods.
Attributes:
cardinalities: A dictionary from RPC method name to interfaces.Cardinality
value.
qualified_names: A dictionary from unqualified RPC method name to
service-qualified RPC method name.
face_cardinalities: A dictionary from service-qualified RPC method name to
to cardinality.Cardinality value.
request_serializers: A dictionary from service-qualified RPC method name to
callable behavior to be used serializing request values for the RPC.
response_deserializers: A dictionary from service-qualified RPC method name
to callable behavior to be used deserializing response values for the
RPC.
"""
class _EasyInvocationBreakdown(
InvocationBreakdown,
collections.namedtuple(
'_EasyInvocationBreakdown',
('cardinalities', 'qualified_names', 'face_cardinalities',
'request_serializers', 'response_deserializers'))):
pass
class ServiceBreakdown(six.with_metaclass(abc.ABCMeta)):
"""An intermediate representation of service-side views of RPC methods.
Attributes:
implementations: A dictionary from service-qualified RPC method name to
face_interfaces.MethodImplementation implementing the RPC method.
request_deserializers: A dictionary from service-qualified RPC method name
to callable behavior to be used deserializing request values for the RPC.
response_serializers: A dictionary from service-qualified RPC method name
to callable behavior to be used serializing response values for the RPC.
"""
class _EasyServiceBreakdown(
ServiceBreakdown,
collections.namedtuple(
'_EasyServiceBreakdown',
('implementations', 'request_deserializers', 'response_serializers'))):
pass
def break_down_invocation(service_name, method_descriptions):
"""Derives an InvocationBreakdown from several RPC method descriptions.
Args:
service_name: The package-qualified full name of the service.
method_descriptions: A dictionary from RPC method name to
interfaces.RpcMethodInvocationDescription describing the RPCs.
Returns:
An InvocationBreakdown corresponding to the given method descriptions.
"""
cardinalities = {}
qualified_names = {}
face_cardinalities = {}
request_serializers = {}
response_deserializers = {}
for name, method_description in six.iteritems(method_descriptions):
qualified_name = _qualified_name(service_name, name)
method_cardinality = method_description.cardinality()
cardinalities[name] = method_description.cardinality()
qualified_names[name] = qualified_name
face_cardinalities[qualified_name] = _reexport.common_cardinality(
method_cardinality)
request_serializers[qualified_name] = method_description.serialize_request
response_deserializers[qualified_name] = (
method_description.deserialize_response)
return _EasyInvocationBreakdown(
cardinalities, qualified_names, face_cardinalities, request_serializers,
response_deserializers)
def break_down_service(service_name, method_descriptions):
"""Derives a ServiceBreakdown from several RPC method descriptions.
Args:
method_descriptions: A dictionary from RPC method name to
interfaces.RpcMethodServiceDescription describing the RPCs.
Returns:
A ServiceBreakdown corresponding to the given method descriptions.
"""
implementations = {}
request_deserializers = {}
response_serializers = {}
for name, method_description in six.iteritems(method_descriptions):
qualified_name = _qualified_name(service_name, name)
method_cardinality = method_description.cardinality()
if method_cardinality is interfaces.Cardinality.UNARY_UNARY:
def service(
request, face_rpc_context,
service_behavior=method_description.service_unary_unary):
return service_behavior(
request, _reexport.rpc_context(face_rpc_context))
implementations[qualified_name] = face_utilities.unary_unary_inline(
service)
elif method_cardinality is interfaces.Cardinality.UNARY_STREAM:
def service(
request, face_rpc_context,
service_behavior=method_description.service_unary_stream):
return service_behavior(
request, _reexport.rpc_context(face_rpc_context))
implementations[qualified_name] = face_utilities.unary_stream_inline(
service)
elif method_cardinality is interfaces.Cardinality.STREAM_UNARY:
def service(
request_iterator, face_rpc_context,
service_behavior=method_description.service_stream_unary):
return service_behavior(
request_iterator, _reexport.rpc_context(face_rpc_context))
implementations[qualified_name] = face_utilities.stream_unary_inline(
service)
elif method_cardinality is interfaces.Cardinality.STREAM_STREAM:
def service(
request_iterator, face_rpc_context,
service_behavior=method_description.service_stream_stream):
return service_behavior(
request_iterator, _reexport.rpc_context(face_rpc_context))
implementations[qualified_name] = face_utilities.stream_stream_inline(
service)
request_deserializers[qualified_name] = (
method_description.deserialize_request)
response_serializers[qualified_name] = (
method_description.serialize_response)
return _EasyServiceBreakdown(
implementations, request_deserializers, response_serializers)

@ -1,205 +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.
import six
from grpc.framework.common import cardinality
from grpc.framework.face import exceptions as face_exceptions
from grpc.framework.face import interfaces as face_interfaces
from grpc.framework.foundation import future
from grpc.framework.alpha import exceptions
from grpc.framework.alpha import interfaces
_EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY = {
interfaces.Cardinality.UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY,
interfaces.Cardinality.UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM,
interfaces.Cardinality.STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY,
interfaces.Cardinality.STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM,
}
_ABORTION_REEXPORT = {
face_interfaces.Abortion.CANCELLED: interfaces.Abortion.CANCELLED,
face_interfaces.Abortion.EXPIRED: interfaces.Abortion.EXPIRED,
face_interfaces.Abortion.NETWORK_FAILURE:
interfaces.Abortion.NETWORK_FAILURE,
face_interfaces.Abortion.SERVICED_FAILURE:
interfaces.Abortion.SERVICED_FAILURE,
face_interfaces.Abortion.SERVICER_FAILURE:
interfaces.Abortion.SERVICER_FAILURE,
}
class _RpcError(exceptions.RpcError):
pass
def _reexport_error(face_rpc_error):
if isinstance(face_rpc_error, face_exceptions.CancellationError):
return exceptions.CancellationError()
elif isinstance(face_rpc_error, face_exceptions.ExpirationError):
return exceptions.ExpirationError()
else:
return _RpcError()
def _as_face_abortion_callback(abortion_callback):
def face_abortion_callback(face_abortion):
abortion_callback(_ABORTION_REEXPORT[face_abortion])
return face_abortion_callback
class _ReexportedFuture(future.Future):
def __init__(self, face_future):
self._face_future = face_future
def cancel(self):
return self._face_future.cancel()
def cancelled(self):
return self._face_future.cancelled()
def running(self):
return self._face_future.running()
def done(self):
return self._face_future.done()
def result(self, timeout=None):
try:
return self._face_future.result(timeout=timeout)
except face_exceptions.RpcError as e:
raise _reexport_error(e)
def exception(self, timeout=None):
face_error = self._face_future.exception(timeout=timeout)
return None if face_error is None else _reexport_error(face_error)
def traceback(self, timeout=None):
return self._face_future.traceback(timeout=timeout)
def add_done_callback(self, fn):
self._face_future.add_done_callback(lambda unused_face_future: fn(self))
def _call_reexporting_errors(behavior, *args, **kwargs):
try:
return behavior(*args, **kwargs)
except face_exceptions.RpcError as e:
raise _reexport_error(e)
def _reexported_future(face_future):
return _ReexportedFuture(face_future)
class _CancellableIterator(interfaces.CancellableIterator):
def __init__(self, face_cancellable_iterator):
self._face_cancellable_iterator = face_cancellable_iterator
def __iter__(self):
return self
def next(self):
return _call_reexporting_errors(self._face_cancellable_iterator.next)
def cancel(self):
self._face_cancellable_iterator.cancel()
class _RpcContext(interfaces.RpcContext):
def __init__(self, face_rpc_context):
self._face_rpc_context = face_rpc_context
def is_active(self):
return self._face_rpc_context.is_active()
def time_remaining(self):
return self._face_rpc_context.time_remaining()
def add_abortion_callback(self, abortion_callback):
self._face_rpc_context.add_abortion_callback(
_as_face_abortion_callback(abortion_callback))
class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync):
def __init__(self, face_unary_unary_multi_callable):
self._underlying = face_unary_unary_multi_callable
def __call__(self, request, timeout):
return _call_reexporting_errors(
self._underlying, request, timeout)
def async(self, request, timeout):
return _ReexportedFuture(self._underlying.future(request, timeout))
class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync):
def __init__(self, face_stream_unary_multi_callable):
self._underlying = face_stream_unary_multi_callable
def __call__(self, request_iterator, timeout):
return _call_reexporting_errors(
self._underlying, request_iterator, timeout)
def async(self, request_iterator, timeout):
return _ReexportedFuture(self._underlying.future(request_iterator, timeout))
def common_cardinality(early_adopter_cardinality):
return _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[
early_adopter_cardinality]
def common_cardinalities(early_adopter_cardinalities):
common_cardinalities = {}
for name, early_adopter_cardinality in six.iteritems(early_adopter_cardinalities):
common_cardinalities[name] = _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[
early_adopter_cardinality]
return common_cardinalities
def rpc_context(face_rpc_context):
return _RpcContext(face_rpc_context)
def cancellable_iterator(face_cancellable_iterator):
return _CancellableIterator(face_cancellable_iterator)
def unary_unary_sync_async(face_unary_unary_multi_callable):
return _UnaryUnarySyncAsync(face_unary_unary_multi_callable)
def stream_unary_sync_async(face_stream_unary_multi_callable):
return _StreamUnarySyncAsync(face_stream_unary_multi_callable)

@ -1,384 +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.
"""Interfaces of GRPC."""
import abc
import enum
import six
# exceptions is referenced from specification in this module.
from grpc.framework.alpha import exceptions # pylint: disable=unused-import
from grpc.framework.foundation import activated
from grpc.framework.foundation import future
@enum.unique
class Cardinality(enum.Enum):
"""Constants for the four cardinalities of RPC."""
UNARY_UNARY = 'request-unary/response-unary'
UNARY_STREAM = 'request-unary/response-streaming'
STREAM_UNARY = 'request-streaming/response-unary'
STREAM_STREAM = 'request-streaming/response-streaming'
@enum.unique
class Abortion(enum.Enum):
"""Categories of RPC abortion."""
CANCELLED = 'cancelled'
EXPIRED = 'expired'
NETWORK_FAILURE = 'network failure'
SERVICED_FAILURE = 'serviced failure'
SERVICER_FAILURE = 'servicer failure'
class CancellableIterator(six.with_metaclass(abc.ABCMeta)):
"""Implements the Iterator protocol and affords a cancel method."""
@abc.abstractmethod
def __iter__(self):
"""Returns the self object in accordance with the Iterator protocol."""
raise NotImplementedError()
def __next__(self):
return self.next()
@abc.abstractmethod
def next(self):
"""Returns a value or raises StopIteration per the Iterator protocol."""
raise NotImplementedError()
@abc.abstractmethod
def cancel(self):
"""Requests cancellation of whatever computation underlies this iterator."""
raise NotImplementedError()
class RpcContext(six.with_metaclass(abc.ABCMeta)):
"""Provides RPC-related information and action."""
@abc.abstractmethod
def is_active(self):
"""Describes whether the RPC is active or has terminated."""
raise NotImplementedError()
@abc.abstractmethod
def time_remaining(self):
"""Describes the length of allowed time remaining for the RPC.
Returns:
A nonnegative float indicating the length of allowed time in seconds
remaining for the RPC to complete before it is considered to have timed
out.
"""
raise NotImplementedError()
@abc.abstractmethod
def add_abortion_callback(self, abortion_callback):
"""Registers a callback to be called if the RPC is aborted.
Args:
abortion_callback: A callable to be called and passed an Abortion value
in the event of RPC abortion.
"""
raise NotImplementedError()
class UnaryUnarySyncAsync(six.with_metaclass(abc.ABCMeta)):
"""Affords invoking a unary-unary RPC synchronously or asynchronously.
Values implementing this interface are directly callable and present an
"async" method. Both calls take a request value and a numeric timeout.
Direct invocation of a value of this type invokes its associated RPC and
blocks until the RPC's response is available. Calling the "async" method
of a value of this type invokes its associated RPC and immediately returns a
future.Future bound to the asynchronous execution of the RPC.
"""
@abc.abstractmethod
def __call__(self, request, timeout):
"""Synchronously invokes the underlying RPC.
Args:
request: The request value for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
The response value for the RPC.
Raises:
exceptions.RpcError: Indicating that the RPC was aborted.
"""
raise NotImplementedError()
@abc.abstractmethod
def async(self, request, timeout):
"""Asynchronously invokes the underlying RPC.
Args:
request: The request value for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
A future.Future representing the RPC. In the event of RPC completion, the
returned Future's result value will be the response value of the RPC.
In the event of RPC abortion, the returned Future's exception value
will be an exceptions.RpcError.
"""
raise NotImplementedError()
class StreamUnarySyncAsync(six.with_metaclass(abc.ABCMeta)):
"""Affords invoking a stream-unary RPC synchronously or asynchronously.
Values implementing this interface are directly callable and present an
"async" method. Both calls take an iterator of request values and a numeric
timeout. Direct invocation of a value of this type invokes its associated RPC
and blocks until the RPC's response is available. Calling the "async" method
of a value of this type invokes its associated RPC and immediately returns a
future.Future bound to the asynchronous execution of the RPC.
"""
@abc.abstractmethod
def __call__(self, request_iterator, timeout):
"""Synchronously invokes the underlying RPC.
Args:
request_iterator: An iterator that yields request values for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
The response value for the RPC.
Raises:
exceptions.RpcError: Indicating that the RPC was aborted.
"""
raise NotImplementedError()
@abc.abstractmethod
def async(self, request_iterator, timeout):
"""Asynchronously invokes the underlying RPC.
Args:
request_iterator: An iterator that yields request values for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
A future.Future representing the RPC. In the event of RPC completion, the
returned Future's result value will be the response value of the RPC.
In the event of RPC abortion, the returned Future's exception value
will be an exceptions.RpcError.
"""
raise NotImplementedError()
class RpcMethodDescription(six.with_metaclass(abc.ABCMeta)):
"""A type for the common aspects of RPC method descriptions."""
@abc.abstractmethod
def cardinality(self):
"""Identifies the cardinality of this RpcMethodDescription.
Returns:
A Cardinality value identifying whether or not this
RpcMethodDescription is request-unary or request-streaming and
whether or not it is response-unary or response-streaming.
"""
raise NotImplementedError()
class RpcMethodInvocationDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)):
"""Invocation-side description of an RPC method."""
@abc.abstractmethod
def serialize_request(self, request):
"""Serializes a request value.
Args:
request: A request value appropriate for the RPC method described by this
RpcMethodInvocationDescription.
Returns:
The serialization of the given request value as a
bytestring.
"""
raise NotImplementedError()
@abc.abstractmethod
def deserialize_response(self, serialized_response):
"""Deserializes a response value.
Args:
serialized_response: A bytestring that is the serialization of a response
value appropriate for the RPC method described by this
RpcMethodInvocationDescription.
Returns:
A response value corresponding to the given bytestring.
"""
raise NotImplementedError()
class RpcMethodServiceDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)):
"""Service-side description of an RPC method."""
@abc.abstractmethod
def deserialize_request(self, serialized_request):
"""Deserializes a request value.
Args:
serialized_request: A bytestring that is the serialization of a request
value appropriate for the RPC method described by this
RpcMethodServiceDescription.
Returns:
A request value corresponding to the given bytestring.
"""
raise NotImplementedError()
@abc.abstractmethod
def serialize_response(self, response):
"""Serializes a response value.
Args:
response: A response value appropriate for the RPC method described by
this RpcMethodServiceDescription.
Returns:
The serialization of the given response value as a
bytestring.
"""
raise NotImplementedError()
@abc.abstractmethod
def service_unary_unary(self, request, context):
"""Carries out this RPC.
This method may only be called if the cardinality of this
RpcMethodServiceDescription is Cardinality.UNARY_UNARY.
Args:
request: A request value appropriate for the RPC method described by this
RpcMethodServiceDescription.
context: An RpcContext object for the RPC.
Returns:
A response value appropriate for the RPC method described by this
RpcMethodServiceDescription.
"""
raise NotImplementedError()
@abc.abstractmethod
def service_unary_stream(self, request, context):
"""Carries out this RPC.
This method may only be called if the cardinality of this
RpcMethodServiceDescription is Cardinality.UNARY_STREAM.
Args:
request: A request value appropriate for the RPC method described by this
RpcMethodServiceDescription.
context: An RpcContext object for the RPC.
Yields:
Zero or more response values appropriate for the RPC method described by
this RpcMethodServiceDescription.
"""
raise NotImplementedError()
@abc.abstractmethod
def service_stream_unary(self, request_iterator, context):
"""Carries out this RPC.
This method may only be called if the cardinality of this
RpcMethodServiceDescription is Cardinality.STREAM_UNARY.
Args:
request_iterator: An iterator of request values appropriate for the RPC
method described by this RpcMethodServiceDescription.
context: An RpcContext object for the RPC.
Returns:
A response value appropriate for the RPC method described by this
RpcMethodServiceDescription.
"""
raise NotImplementedError()
@abc.abstractmethod
def service_stream_stream(self, request_iterator, context):
"""Carries out this RPC.
This method may only be called if the cardinality of this
RpcMethodServiceDescription is Cardinality.STREAM_STREAM.
Args:
request_iterator: An iterator of request values appropriate for the RPC
method described by this RpcMethodServiceDescription.
context: An RpcContext object for the RPC.
Yields:
Zero or more response values appropriate for the RPC method described by
this RpcMethodServiceDescription.
"""
raise NotImplementedError()
class Stub(six.with_metaclass(abc.ABCMeta)):
"""A stub with callable RPC method names for attributes.
Instances of this type are context managers and only afford RPC invocation
when used in context.
Instances of this type, when used in context, respond to attribute access
as follows: if the requested attribute is the name of a unary-unary RPC
method, the value of the attribute will be a UnaryUnarySyncAsync with which
to invoke the RPC method. If the requested attribute is the name of a
unary-stream RPC method, the value of the attribute will be a callable taking
a request object and a timeout parameter and returning a CancellableIterator
that yields the response values of the RPC. If the requested attribute is the
name of a stream-unary RPC method, the value of the attribute will be a
StreamUnarySyncAsync with which to invoke the RPC method. If the requested
attribute is the name of a stream-stream RPC method, the value of the
attribute will be a callable taking an iterator of request objects and a
timeout and returning a CancellableIterator that yields the response values
of the RPC.
In all cases indication of abortion is indicated by raising of
exceptions.RpcError, exceptions.CancellationError,
and exceptions.ExpirationError.
"""
class Server(six.with_metaclass(abc.ABCMeta, activated.Activated)):
"""A GRPC Server."""
@abc.abstractmethod
def port(self):
"""Reports the port on which the server is serving.
This method may only be called while the server is activated.
Returns:
The port on which the server is serving.
"""
raise NotImplementedError()

@ -1,269 +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.
"""Utilities for use with GRPC."""
from grpc.framework.alpha import interfaces
class _RpcMethodDescription(
interfaces.RpcMethodInvocationDescription,
interfaces.RpcMethodServiceDescription):
def __init__(
self, cardinality, unary_unary, unary_stream, stream_unary,
stream_stream, request_serializer, request_deserializer,
response_serializer, response_deserializer):
self._cardinality = cardinality
self._unary_unary = unary_unary
self._unary_stream = unary_stream
self._stream_unary = stream_unary
self._stream_stream = stream_stream
self._request_serializer = request_serializer
self._request_deserializer = request_deserializer
self._response_serializer = response_serializer
self._response_deserializer = response_deserializer
def cardinality(self):
"""See interfaces.RpcMethodDescription.cardinality for specification."""
return self._cardinality
def serialize_request(self, request):
"""See interfaces.RpcMethodInvocationDescription.serialize_request."""
return self._request_serializer(request)
def deserialize_request(self, serialized_request):
"""See interfaces.RpcMethodServiceDescription.deserialize_request."""
return self._request_deserializer(serialized_request)
def serialize_response(self, response):
"""See interfaces.RpcMethodServiceDescription.serialize_response."""
return self._response_serializer(response)
def deserialize_response(self, serialized_response):
"""See interfaces.RpcMethodInvocationDescription.deserialize_response."""
return self._response_deserializer(serialized_response)
def service_unary_unary(self, request, context):
"""See interfaces.RpcMethodServiceDescription.service_unary_unary."""
return self._unary_unary(request, context)
def service_unary_stream(self, request, context):
"""See interfaces.RpcMethodServiceDescription.service_unary_stream."""
return self._unary_stream(request, context)
def service_stream_unary(self, request_iterator, context):
"""See interfaces.RpcMethodServiceDescription.service_stream_unary."""
return self._stream_unary(request_iterator, context)
def service_stream_stream(self, request_iterator, context):
"""See interfaces.RpcMethodServiceDescription.service_stream_stream."""
return self._stream_stream(request_iterator, context)
def unary_unary_invocation_description(
request_serializer, response_deserializer):
"""Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
Args:
request_serializer: A callable that when called on a request
value returns a bytestring corresponding to that value.
response_deserializer: A callable that when called on a
bytestring returns the response value corresponding to
that bytestring.
Returns:
An interfaces.RpcMethodInvocationDescription constructed from the given
arguments representing a unary-request/unary-response RPC method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.UNARY_UNARY, None, None, None, None,
request_serializer, None, None, response_deserializer)
def unary_stream_invocation_description(
request_serializer, response_deserializer):
"""Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
Args:
request_serializer: A callable that when called on a request
value returns a bytestring corresponding to that value.
response_deserializer: A callable that when called on a
bytestring returns the response value corresponding to
that bytestring.
Returns:
An interfaces.RpcMethodInvocationDescription constructed from the given
arguments representing a unary-request/streaming-response RPC method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.UNARY_STREAM, None, None, None, None,
request_serializer, None, None, response_deserializer)
def stream_unary_invocation_description(
request_serializer, response_deserializer):
"""Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
Args:
request_serializer: A callable that when called on a request
value returns a bytestring corresponding to that value.
response_deserializer: A callable that when called on a
bytestring returns the response value corresponding to
that bytestring.
Returns:
An interfaces.RpcMethodInvocationDescription constructed from the given
arguments representing a streaming-request/unary-response RPC method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.STREAM_UNARY, None, None, None, None,
request_serializer, None, None, response_deserializer)
def stream_stream_invocation_description(
request_serializer, response_deserializer):
"""Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
Args:
request_serializer: A callable that when called on a request
value returns a bytestring corresponding to that value.
response_deserializer: A callable that when called on a
bytestring returns the response value corresponding to
that bytestring.
Returns:
An interfaces.RpcMethodInvocationDescription constructed from the given
arguments representing a streaming-request/streaming-response RPC
method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.STREAM_STREAM, None, None, None, None,
request_serializer, None, None, response_deserializer)
def unary_unary_service_description(
behavior, request_deserializer, response_serializer):
"""Creates an interfaces.RpcMethodServiceDescription for the given behavior.
Args:
behavior: A callable that implements a unary-unary RPC
method that accepts a single request and an interfaces.RpcContext and
returns a single response.
request_deserializer: A callable that when called on a
bytestring returns the request value corresponding to that
bytestring.
response_serializer: A callable that when called on a
response value returns the bytestring corresponding to
that value.
Returns:
An interfaces.RpcMethodServiceDescription constructed from the given
arguments representing a unary-request/unary-response RPC
method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.UNARY_UNARY, behavior, None, None, None,
None, request_deserializer, response_serializer, None)
def unary_stream_service_description(
behavior, request_deserializer, response_serializer):
"""Creates an interfaces.RpcMethodServiceDescription for the given behavior.
Args:
behavior: A callable that implements a unary-stream RPC
method that accepts a single request and an interfaces.RpcContext
and returns an iterator of zero or more responses.
request_deserializer: A callable that when called on a
bytestring returns the request value corresponding to that
bytestring.
response_serializer: A callable that when called on a
response value returns the bytestring corresponding to
that value.
Returns:
An interfaces.RpcMethodServiceDescription constructed from the given
arguments representing a unary-request/streaming-response
RPC method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.UNARY_STREAM, None, behavior, None, None,
None, request_deserializer, response_serializer, None)
def stream_unary_service_description(
behavior, request_deserializer, response_serializer):
"""Creates an interfaces.RpcMethodServiceDescription for the given behavior.
Args:
behavior: A callable that implements a stream-unary RPC
method that accepts an iterator of zero or more requests
and an interfaces.RpcContext and returns a single response.
request_deserializer: A callable that when called on a
bytestring returns the request value corresponding to that
bytestring.
response_serializer: A callable that when called on a
response value returns the bytestring corresponding to
that value.
Returns:
An interfaces.RpcMethodServiceDescription constructed from the given
arguments representing a streaming-request/unary-response
RPC method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.STREAM_UNARY, None, None, behavior, None,
None, request_deserializer, response_serializer, None)
def stream_stream_service_description(
behavior, request_deserializer, response_serializer):
"""Creates an interfaces.RpcMethodServiceDescription for the given behavior.
Args:
behavior: A callable that implements a stream-stream RPC
method that accepts an iterator of zero or more requests
and an interfaces.RpcContext and returns an iterator of
zero or more responses.
request_deserializer: A callable that when called on a
bytestring returns the request value corresponding to that
bytestring.
response_serializer: A callable that when called on a
response value returns the bytestring corresponding to
that value.
Returns:
An interfaces.RpcMethodServiceDescription constructed from the given
arguments representing a
streaming-request/streaming-response RPC method.
"""
return _RpcMethodDescription(
interfaces.Cardinality.STREAM_STREAM, None, None, None, behavior,
None, request_deserializer, response_serializer, None)

@ -1,35 +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.
import warnings
warnings.simplefilter('always', DeprecationWarning)
warnings.warn('the alpha API (includes this package) is deprecated, '
'unmaintained, and no longer tested. Please migrate to the beta '
'API.', DeprecationWarning, stacklevel=2)

@ -1,99 +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.
"""State and behavior for operation context."""
import time
# _interfaces is referenced from specification in this module.
from grpc.framework.base import interfaces
from grpc.framework.base import _interfaces # pylint: disable=unused-import
class OperationContext(interfaces.OperationContext):
"""An implementation of interfaces.OperationContext."""
def __init__(
self, lock, operation_id, local_failure, termination_manager,
transmission_manager):
"""Constructor.
Args:
lock: The operation-wide lock.
operation_id: An object identifying the operation.
local_failure: Whichever one of interfaces.Outcome.SERVICED_FAILURE or
interfaces.Outcome.SERVICER_FAILURE describes local failure of
customer code.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
"""
self._lock = lock
self._local_failure = local_failure
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._ingestion_manager = None
self._expiration_manager = None
self.operation_id = operation_id
def set_ingestion_and_expiration_managers(
self, ingestion_manager, expiration_manager):
"""Sets managers with which this OperationContext cooperates.
Args:
ingestion_manager: The _interfaces.IngestionManager for the operation.
expiration_manager: The _interfaces.ExpirationManager for the operation.
"""
self._ingestion_manager = ingestion_manager
self._expiration_manager = expiration_manager
def is_active(self):
"""See interfaces.OperationContext.is_active for specification."""
with self._lock:
return self._termination_manager.is_active()
def add_termination_callback(self, callback):
"""See interfaces.OperationContext.add_termination_callback."""
with self._lock:
self._termination_manager.add_callback(callback)
def time_remaining(self):
"""See interfaces.OperationContext.time_remaining for specification."""
with self._lock:
deadline = self._expiration_manager.deadline()
return max(0.0, deadline - time.time())
def fail(self, exception):
"""See interfaces.OperationContext.fail for specification."""
with self._lock:
self._termination_manager.abort(self._local_failure)
self._transmission_manager.abort(self._local_failure)
self._ingestion_manager.abort()
self._expiration_manager.abort()

@ -1,125 +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.
"""State and behavior for handling emitted values."""
from grpc.framework.base import interfaces
from grpc.framework.base import _interfaces
class _EmissionManager(_interfaces.EmissionManager):
"""An implementation of _interfaces.EmissionManager."""
def __init__(
self, lock, failure_outcome, termination_manager, transmission_manager):
"""Constructor.
Args:
lock: The operation-wide lock.
failure_outcome: Whichever one of interfaces.Outcome.SERVICED_FAILURE or
interfaces.Outcome.SERVICER_FAILURE describes this object's methods
being called inappropriately by customer code.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
"""
self._lock = lock
self._failure_outcome = failure_outcome
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._ingestion_manager = None
self._expiration_manager = None
self._emission_complete = False
def set_ingestion_manager_and_expiration_manager(
self, ingestion_manager, expiration_manager):
self._ingestion_manager = ingestion_manager
self._expiration_manager = expiration_manager
def _abort(self):
self._termination_manager.abort(self._failure_outcome)
self._transmission_manager.abort(self._failure_outcome)
self._ingestion_manager.abort()
self._expiration_manager.abort()
def consume(self, value):
with self._lock:
if self._emission_complete:
self._abort()
else:
self._transmission_manager.inmit(value, False)
def terminate(self):
with self._lock:
if not self._emission_complete:
self._termination_manager.emission_complete()
self._transmission_manager.inmit(None, True)
self._emission_complete = True
def consume_and_terminate(self, value):
with self._lock:
if self._emission_complete:
self._abort()
else:
self._termination_manager.emission_complete()
self._transmission_manager.inmit(value, True)
self._emission_complete = True
def front_emission_manager(lock, termination_manager, transmission_manager):
"""Creates an _interfaces.EmissionManager appropriate for front-side use.
Args:
lock: The operation-wide lock.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the operation.
Returns:
An _interfaces.EmissionManager appropriate for front-side use.
"""
return _EmissionManager(
lock, interfaces.Outcome.SERVICED_FAILURE, termination_manager,
transmission_manager)
def back_emission_manager(lock, termination_manager, transmission_manager):
"""Creates an _interfaces.EmissionManager appropriate for back-side use.
Args:
lock: The operation-wide lock.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the operation.
Returns:
An _interfaces.EmissionManager appropriate for back-side use.
"""
return _EmissionManager(
lock, interfaces.Outcome.SERVICER_FAILURE, termination_manager,
transmission_manager)

@ -1,399 +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.
"""Implementations of FrontLinks and BackLinks."""
import collections
import threading
import uuid
# _interfaces is referenced from specification in this module.
from grpc.framework.base import _cancellation
from grpc.framework.base import _context
from grpc.framework.base import _emission
from grpc.framework.base import _expiration
from grpc.framework.base import _ingestion
from grpc.framework.base import _interfaces # pylint: disable=unused-import
from grpc.framework.base import _reception
from grpc.framework.base import _termination
from grpc.framework.base import _transmission
from grpc.framework.base import interfaces
from grpc.framework.foundation import callable_util
_IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!'
class _EasyOperation(interfaces.Operation):
"""A trivial implementation of interfaces.Operation."""
def __init__(self, emission_manager, context, cancellation_manager):
"""Constructor.
Args:
emission_manager: The _interfaces.EmissionManager for the operation that
will accept values emitted by customer code.
context: The interfaces.OperationContext for use by the customer
during the operation.
cancellation_manager: The _interfaces.CancellationManager for the
operation.
"""
self.consumer = emission_manager
self.context = context
self._cancellation_manager = cancellation_manager
def cancel(self):
self._cancellation_manager.cancel()
class _Endlette(object):
"""Utility for stateful behavior common to Fronts and Backs."""
def __init__(self, pool):
"""Constructor.
Args:
pool: A thread pool to use when calling registered idle actions.
"""
self._lock = threading.Lock()
self._pool = pool
# Dictionary from operation IDs to ReceptionManager-or-None. A None value
# indicates an in-progress fire-and-forget operation for which the customer
# has chosen to ignore results.
self._operations = {}
self._stats = {outcome: 0 for outcome in interfaces.Outcome}
self._idle_actions = []
def terminal_action(self, operation_id):
"""Constructs the termination action for a single operation.
Args:
operation_id: An operation ID.
Returns:
A callable that takes an operation outcome for an argument to be used as
the termination action for the operation associated with the given
operation ID.
"""
def termination_action(outcome):
with self._lock:
self._stats[outcome] += 1
self._operations.pop(operation_id, None)
if not self._operations:
for action in self._idle_actions:
self._pool.submit(callable_util.with_exceptions_logged(
action, _IDLE_ACTION_EXCEPTION_LOG_MESSAGE))
self._idle_actions = []
return termination_action
def __enter__(self):
self._lock.acquire()
def __exit__(self, exc_type, exc_val, exc_tb):
self._lock.release()
def get_operation(self, operation_id):
return self._operations.get(operation_id, None)
def add_operation(self, operation_id, operation_reception_manager):
self._operations[operation_id] = operation_reception_manager
def operation_stats(self):
with self._lock:
return dict(self._stats)
def add_idle_action(self, action):
with self._lock:
if self._operations:
self._idle_actions.append(action)
else:
self._pool.submit(callable_util.with_exceptions_logged(
action, _IDLE_ACTION_EXCEPTION_LOG_MESSAGE))
class _FrontManagement(
collections.namedtuple(
'_FrontManagement',
('reception', 'emission', 'operation', 'cancellation'))):
"""Just a trivial helper class to bundle four fellow-traveling objects."""
def _front_operate(
callback, work_pool, transmission_pool, utility_pool,
termination_action, operation_id, name, payload, complete, timeout,
subscription, trace_id):
"""Constructs objects necessary for front-side operation management.
Args:
callback: A callable that accepts interfaces.FrontToBackTickets and
delivers them to the other side of the operation. Execution of this
callable may take any arbitrary length of time.
work_pool: A thread pool in which to execute customer code.
transmission_pool: A thread pool to use for transmitting to the other side
of the operation.
utility_pool: A thread pool for utility tasks.
termination_action: A no-arg behavior to be called upon operation
completion.
operation_id: An object identifying the operation.
name: The name of the method being called during the operation.
payload: The first customer-significant value to be transmitted to the other
side. May be None if there is no such value or if the customer chose not
to pass it at operation invocation.
complete: A boolean indicating whether or not additional payloads will be
supplied by the customer.
timeout: A length of time in seconds to allow for the operation.
subscription: A interfaces.ServicedSubscription describing the
customer's interest in the results of the operation.
trace_id: A uuid.UUID identifying a set of related operations to which this
operation belongs. May be None.
Returns:
A _FrontManagement object bundling together the
_interfaces.ReceptionManager, _interfaces.EmissionManager,
_context.OperationContext, and _interfaces.CancellationManager for the
operation.
"""
lock = threading.Lock()
with lock:
termination_manager = _termination.front_termination_manager(
work_pool, utility_pool, termination_action, subscription.kind)
transmission_manager = _transmission.front_transmission_manager(
lock, transmission_pool, callback, operation_id, name,
subscription.kind, trace_id, timeout, termination_manager)
operation_context = _context.OperationContext(
lock, operation_id, interfaces.Outcome.SERVICED_FAILURE,
termination_manager, transmission_manager)
emission_manager = _emission.front_emission_manager(
lock, termination_manager, transmission_manager)
ingestion_manager = _ingestion.front_ingestion_manager(
lock, work_pool, subscription, termination_manager,
transmission_manager, operation_context)
expiration_manager = _expiration.front_expiration_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
timeout)
reception_manager = _reception.front_reception_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
expiration_manager)
cancellation_manager = _cancellation.CancellationManager(
lock, termination_manager, transmission_manager, ingestion_manager,
expiration_manager)
termination_manager.set_expiration_manager(expiration_manager)
transmission_manager.set_ingestion_and_expiration_managers(
ingestion_manager, expiration_manager)
operation_context.set_ingestion_and_expiration_managers(
ingestion_manager, expiration_manager)
emission_manager.set_ingestion_manager_and_expiration_manager(
ingestion_manager, expiration_manager)
ingestion_manager.set_expiration_manager(expiration_manager)
transmission_manager.inmit(payload, complete)
if subscription.kind is interfaces.ServicedSubscription.Kind.NONE:
returned_reception_manager = None
else:
returned_reception_manager = reception_manager
return _FrontManagement(
returned_reception_manager, emission_manager, operation_context,
cancellation_manager)
class FrontLink(interfaces.FrontLink):
"""An implementation of interfaces.FrontLink."""
def __init__(self, work_pool, transmission_pool, utility_pool):
"""Constructor.
Args:
work_pool: A thread pool to be used for executing customer code.
transmission_pool: A thread pool to be used for transmitting values to
the other side of the operation.
utility_pool: A thread pool to be used for utility tasks.
"""
self._endlette = _Endlette(utility_pool)
self._work_pool = work_pool
self._transmission_pool = transmission_pool
self._utility_pool = utility_pool
self._callback = None
self._operations = {}
def join_rear_link(self, rear_link):
"""See interfaces.ForeLink.join_rear_link for specification."""
with self._endlette:
self._callback = rear_link.accept_front_to_back_ticket
def operation_stats(self):
"""See interfaces.End.operation_stats for specification."""
return self._endlette.operation_stats()
def add_idle_action(self, action):
"""See interfaces.End.add_idle_action for specification."""
self._endlette.add_idle_action(action)
def operate(
self, name, payload, complete, timeout, subscription, trace_id):
"""See interfaces.Front.operate for specification."""
operation_id = uuid.uuid4()
with self._endlette:
management = _front_operate(
self._callback, self._work_pool, self._transmission_pool,
self._utility_pool, self._endlette.terminal_action(operation_id),
operation_id, name, payload, complete, timeout, subscription,
trace_id)
self._endlette.add_operation(operation_id, management.reception)
return _EasyOperation(
management.emission, management.operation, management.cancellation)
def accept_back_to_front_ticket(self, ticket):
"""See interfaces.End.act for specification."""
with self._endlette:
reception_manager = self._endlette.get_operation(ticket.operation_id)
if reception_manager:
reception_manager.receive_ticket(ticket)
def _back_operate(
servicer, callback, work_pool, transmission_pool, utility_pool,
termination_action, ticket, default_timeout, maximum_timeout):
"""Constructs objects necessary for back-side operation management.
Also begins back-side operation by feeding the first received ticket into the
constructed _interfaces.ReceptionManager.
Args:
servicer: An interfaces.Servicer for servicing operations.
callback: A callable that accepts interfaces.BackToFrontTickets and
delivers them to the other side of the operation. Execution of this
callable may take any arbitrary length of time.
work_pool: A thread pool in which to execute customer code.
transmission_pool: A thread pool to use for transmitting to the other side
of the operation.
utility_pool: A thread pool for utility tasks.
termination_action: A no-arg behavior to be called upon operation
completion.
ticket: The first interfaces.FrontToBackTicket received for the operation.
default_timeout: A length of time in seconds to be used as the default
time alloted for a single operation.
maximum_timeout: A length of time in seconds to be used as the maximum
time alloted for a single operation.
Returns:
The _interfaces.ReceptionManager to be used for the operation.
"""
lock = threading.Lock()
with lock:
termination_manager = _termination.back_termination_manager(
work_pool, utility_pool, termination_action, ticket.subscription)
transmission_manager = _transmission.back_transmission_manager(
lock, transmission_pool, callback, ticket.operation_id,
termination_manager, ticket.subscription)
operation_context = _context.OperationContext(
lock, ticket.operation_id, interfaces.Outcome.SERVICER_FAILURE,
termination_manager, transmission_manager)
emission_manager = _emission.back_emission_manager(
lock, termination_manager, transmission_manager)
ingestion_manager = _ingestion.back_ingestion_manager(
lock, work_pool, servicer, termination_manager,
transmission_manager, operation_context, emission_manager)
expiration_manager = _expiration.back_expiration_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
ticket.timeout, default_timeout, maximum_timeout)
reception_manager = _reception.back_reception_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
expiration_manager)
termination_manager.set_expiration_manager(expiration_manager)
transmission_manager.set_ingestion_and_expiration_managers(
ingestion_manager, expiration_manager)
operation_context.set_ingestion_and_expiration_managers(
ingestion_manager, expiration_manager)
emission_manager.set_ingestion_manager_and_expiration_manager(
ingestion_manager, expiration_manager)
ingestion_manager.set_expiration_manager(expiration_manager)
reception_manager.receive_ticket(ticket)
return reception_manager
class BackLink(interfaces.BackLink):
"""An implementation of interfaces.BackLink."""
def __init__(
self, servicer, work_pool, transmission_pool, utility_pool,
default_timeout, maximum_timeout):
"""Constructor.
Args:
servicer: An interfaces.Servicer for servicing operations.
work_pool: A thread pool in which to execute customer code.
transmission_pool: A thread pool to use for transmitting to the other side
of the operation.
utility_pool: A thread pool for utility tasks.
default_timeout: A length of time in seconds to be used as the default
time alloted for a single operation.
maximum_timeout: A length of time in seconds to be used as the maximum
time alloted for a single operation.
"""
self._endlette = _Endlette(utility_pool)
self._servicer = servicer
self._work_pool = work_pool
self._transmission_pool = transmission_pool
self._utility_pool = utility_pool
self._default_timeout = default_timeout
self._maximum_timeout = maximum_timeout
self._callback = None
def join_fore_link(self, fore_link):
"""See interfaces.RearLink.join_fore_link for specification."""
with self._endlette:
self._callback = fore_link.accept_back_to_front_ticket
def accept_front_to_back_ticket(self, ticket):
"""See interfaces.RearLink.accept_front_to_back_ticket for specification."""
with self._endlette:
reception_manager = self._endlette.get_operation(ticket.operation_id)
if reception_manager is None:
reception_manager = _back_operate(
self._servicer, self._callback, self._work_pool,
self._transmission_pool, self._utility_pool,
self._endlette.terminal_action(ticket.operation_id), ticket,
self._default_timeout, self._maximum_timeout)
self._endlette.add_operation(ticket.operation_id, reception_manager)
else:
reception_manager.receive_ticket(ticket)
def operation_stats(self):
"""See interfaces.End.operation_stats for specification."""
return self._endlette.operation_stats()
def add_idle_action(self, action):
"""See interfaces.End.add_idle_action for specification."""
self._endlette.add_idle_action(action)

@ -1,158 +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.
"""State and behavior for operation expiration."""
import time
from grpc.framework.base import _interfaces
from grpc.framework.base import interfaces
from grpc.framework.foundation import later
class _ExpirationManager(_interfaces.ExpirationManager):
"""An implementation of _interfaces.ExpirationManager."""
def __init__(
self, lock, termination_manager, transmission_manager, ingestion_manager,
commencement, timeout, maximum_timeout):
"""Constructor.
Args:
lock: The operation-wide lock.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
ingestion_manager: The _interfaces.IngestionManager for the operation.
commencement: The time in seconds since the epoch at which the operation
began.
timeout: A length of time in seconds to allow for the operation to run.
maximum_timeout: The maximum length of time in seconds to allow for the
operation to run despite what is requested via this object's
change_timout method.
"""
self._lock = lock
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._ingestion_manager = ingestion_manager
self._commencement = commencement
self._maximum_timeout = maximum_timeout
self._timeout = timeout
self._deadline = commencement + timeout
self._index = None
self._future = None
def _expire(self, index):
with self._lock:
if self._future is not None and index == self._index:
self._future = None
self._termination_manager.abort(interfaces.Outcome.EXPIRED)
self._transmission_manager.abort(interfaces.Outcome.EXPIRED)
self._ingestion_manager.abort()
def start(self):
self._index = 0
self._future = later.later(self._timeout, lambda: self._expire(0))
def change_timeout(self, timeout):
if self._future is not None and timeout != self._timeout:
self._future.cancel()
new_timeout = min(timeout, self._maximum_timeout)
new_index = self._index + 1
self._timeout = new_timeout
self._deadline = self._commencement + new_timeout
self._index = new_index
delay = self._deadline - time.time()
self._future = later.later(
delay, lambda: self._expire(new_index))
def deadline(self):
return self._deadline
def abort(self):
if self._future:
self._future.cancel()
self._future = None
self._deadline_index = None
def front_expiration_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
timeout):
"""Creates an _interfaces.ExpirationManager appropriate for front-side use.
Args:
lock: The operation-wide lock.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
ingestion_manager: The _interfaces.IngestionManager for the operation.
timeout: A length of time in seconds to allow for the operation to run.
Returns:
An _interfaces.ExpirationManager appropriate for front-side use.
"""
commencement = time.time()
expiration_manager = _ExpirationManager(
lock, termination_manager, transmission_manager, ingestion_manager,
commencement, timeout, timeout)
expiration_manager.start()
return expiration_manager
def back_expiration_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
timeout, default_timeout, maximum_timeout):
"""Creates an _interfaces.ExpirationManager appropriate for back-side use.
Args:
lock: The operation-wide lock.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
ingestion_manager: The _interfaces.IngestionManager for the operation.
timeout: A length of time in seconds to allow for the operation to run. May
be None in which case default_timeout will be used.
default_timeout: The default length of time in seconds to allow for the
operation to run if the front-side customer has not specified such a value
(or if the value they specified is not yet known).
maximum_timeout: The maximum length of time in seconds to allow for the
operation to run.
Returns:
An _interfaces.ExpirationManager appropriate for back-side use.
"""
commencement = time.time()
expiration_manager = _ExpirationManager(
lock, termination_manager, transmission_manager, ingestion_manager,
commencement, default_timeout if timeout is None else timeout,
maximum_timeout)
expiration_manager.start()
return expiration_manager

@ -1,443 +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.
"""State and behavior for ingestion during an operation."""
import abc
import collections
import six
from grpc.framework.base import _constants
from grpc.framework.base import _interfaces
from grpc.framework.base import exceptions
from grpc.framework.base import interfaces
from grpc.framework.foundation import abandonment
from grpc.framework.foundation import callable_util
from grpc.framework.foundation import stream
_CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE = 'Exception initializing ingestion!'
_CONSUME_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!'
class _ConsumerCreation(collections.namedtuple(
'_ConsumerCreation', ('consumer', 'remote_error', 'abandoned'))):
"""A sum type for the outcome of ingestion initialization.
Either consumer will be non-None, remote_error will be True, or abandoned will
be True.
Attributes:
consumer: A stream.Consumer for ingesting payloads.
remote_error: A boolean indicating that the consumer could not be created
due to an error on the remote side of the operation.
abandoned: A boolean indicating that the consumer creation was abandoned.
"""
class _EmptyConsumer(stream.Consumer):
"""A no-operative stream.Consumer that ignores all inputs and calls."""
def consume(self, value):
"""See stream.Consumer.consume for specification."""
def terminate(self):
"""See stream.Consumer.terminate for specification."""
def consume_and_terminate(self, value):
"""See stream.Consumer.consume_and_terminate for specification."""
class _ConsumerCreator(six.with_metaclass(abc.ABCMeta)):
"""Common specification of different consumer-creating behavior."""
@abc.abstractmethod
def create_consumer(self, requirement):
"""Creates the stream.Consumer to which customer payloads will be delivered.
Any exceptions raised by this method should be attributed to and treated as
defects in the serviced or servicer code called by this method.
Args:
requirement: A value required by this _ConsumerCreator for consumer
creation.
Returns:
A _ConsumerCreation describing the result of consumer creation.
"""
raise NotImplementedError()
class _FrontConsumerCreator(_ConsumerCreator):
"""A _ConsumerCreator appropriate for front-side use."""
def __init__(self, subscription, operation_context):
"""Constructor.
Args:
subscription: The serviced's interfaces.ServicedSubscription for the
operation.
operation_context: The interfaces.OperationContext object for the
operation.
"""
self._subscription = subscription
self._operation_context = operation_context
def create_consumer(self, requirement):
"""See _ConsumerCreator.create_consumer for specification."""
if self._subscription.kind is interfaces.ServicedSubscription.Kind.FULL:
try:
return _ConsumerCreation(
self._subscription.ingestor.consumer(self._operation_context),
False, False)
except abandonment.Abandoned:
return _ConsumerCreation(None, False, True)
else:
return _ConsumerCreation(_EmptyConsumer(), False, False)
class _BackConsumerCreator(_ConsumerCreator):
"""A _ConsumerCreator appropriate for back-side use."""
def __init__(self, servicer, operation_context, emission_consumer):
"""Constructor.
Args:
servicer: The interfaces.Servicer that will service the operation.
operation_context: The interfaces.OperationContext object for the
operation.
emission_consumer: The stream.Consumer object to which payloads emitted
from the operation will be passed.
"""
self._servicer = servicer
self._operation_context = operation_context
self._emission_consumer = emission_consumer
def create_consumer(self, requirement):
"""See _ConsumerCreator.create_consumer for full specification.
Args:
requirement: The name of the Servicer method to be called during this
operation.
Returns:
A _ConsumerCreation describing the result of consumer creation.
"""
try:
return _ConsumerCreation(
self._servicer.service(
requirement, self._operation_context, self._emission_consumer),
False, False)
except exceptions.NoSuchMethodError:
return _ConsumerCreation(None, True, False)
except abandonment.Abandoned:
return _ConsumerCreation(None, False, True)
class _WrappedConsumer(object):
"""Wraps a consumer to catch the exceptions that it is allowed to throw."""
def __init__(self, consumer):
"""Constructor.
Args:
consumer: A stream.Consumer that may raise abandonment.Abandoned from any
of its methods.
"""
self._consumer = consumer
def moar(self, payload, complete):
"""Makes progress with the wrapped consumer.
This method catches all exceptions allowed to be thrown by the wrapped
consumer. Any exceptions raised by this method should be blamed on the
customer-supplied consumer.
Args:
payload: A customer-significant payload object. May be None only if
complete is True.
complete: Whether or not the end of the payload sequence has been reached.
Must be True if payload is None.
Returns:
True if the wrapped consumer made progress or False if the wrapped
consumer raised abandonment.Abandoned to indicate its abandonment of
progress.
"""
try:
if payload is None:
self._consumer.terminate()
elif complete:
self._consumer.consume_and_terminate(payload)
else:
self._consumer.consume(payload)
return True
except abandonment.Abandoned:
return False
class _IngestionManager(_interfaces.IngestionManager):
"""An implementation of _interfaces.IngestionManager."""
def __init__(
self, lock, pool, consumer_creator, failure_outcome, termination_manager,
transmission_manager):
"""Constructor.
Args:
lock: The operation-wide lock.
pool: A thread pool in which to execute customer code.
consumer_creator: A _ConsumerCreator wrapping the portion of customer code
that when called returns the stream.Consumer with which the customer
code will ingest payload values.
failure_outcome: Whichever one of
interfaces.Outcome.SERVICED_FAILURE or
interfaces.Outcome.SERVICER_FAILURE describes local failure of
customer code.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
"""
self._lock = lock
self._pool = pool
self._consumer_creator = consumer_creator
self._failure_outcome = failure_outcome
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._expiration_manager = None
self._wrapped_ingestion_consumer = None
self._pending_ingestion = []
self._ingestion_complete = False
self._processing = False
def set_expiration_manager(self, expiration_manager):
self._expiration_manager = expiration_manager
def _abort_internal_only(self):
self._wrapped_ingestion_consumer = None
self._pending_ingestion = None
def _abort_and_notify(self, outcome):
self._abort_internal_only()
self._termination_manager.abort(outcome)
self._transmission_manager.abort(outcome)
self._expiration_manager.abort()
def _next(self):
"""Computes the next step for ingestion.
Returns:
A payload, complete, continue triplet indicating what payload (if any) is
available to feed into customer code, whether or not the sequence of
payloads has terminated, and whether or not there is anything
immediately actionable to call customer code to do.
"""
if self._pending_ingestion is None:
return None, False, False
elif self._pending_ingestion:
payload = self._pending_ingestion.pop(0)
complete = self._ingestion_complete and not self._pending_ingestion
return payload, complete, True
elif self._ingestion_complete:
return None, True, True
else:
return None, False, False
def _process(self, wrapped_ingestion_consumer, payload, complete):
"""A method to call to execute customer code.
This object's lock must *not* be held when calling this method.
Args:
wrapped_ingestion_consumer: The _WrappedConsumer with which to pass
payloads to customer code.
payload: A customer payload. May be None only if complete is True.
complete: Whether or not the sequence of payloads to pass to the customer
has concluded.
"""
while True:
consumption_outcome = callable_util.call_logging_exceptions(
wrapped_ingestion_consumer.moar, _CONSUME_EXCEPTION_LOG_MESSAGE,
payload, complete)
if consumption_outcome.exception is None:
if consumption_outcome.return_value:
with self._lock:
if complete:
self._pending_ingestion = None
self._termination_manager.ingestion_complete()
return
else:
payload, complete, moar = self._next()
if not moar:
self._processing = False
return
else:
with self._lock:
if self._pending_ingestion is not None:
self._abort_and_notify(self._failure_outcome)
self._processing = False
return
else:
with self._lock:
self._abort_and_notify(self._failure_outcome)
self._processing = False
return
def start(self, requirement):
if self._pending_ingestion is not None:
def initialize():
consumer_creation_outcome = callable_util.call_logging_exceptions(
self._consumer_creator.create_consumer,
_CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE, requirement)
if consumer_creation_outcome.return_value is None:
with self._lock:
self._abort_and_notify(self._failure_outcome)
self._processing = False
elif consumer_creation_outcome.return_value.remote_error:
with self._lock:
self._abort_and_notify(interfaces.Outcome.RECEPTION_FAILURE)
self._processing = False
elif consumer_creation_outcome.return_value.abandoned:
with self._lock:
if self._pending_ingestion is not None:
self._abort_and_notify(self._failure_outcome)
self._processing = False
else:
wrapped_ingestion_consumer = _WrappedConsumer(
consumer_creation_outcome.return_value.consumer)
with self._lock:
self._wrapped_ingestion_consumer = wrapped_ingestion_consumer
payload, complete, moar = self._next()
if not moar:
self._processing = False
return
self._process(wrapped_ingestion_consumer, payload, complete)
self._pool.submit(
callable_util.with_exceptions_logged(
initialize, _constants.INTERNAL_ERROR_LOG_MESSAGE))
self._processing = True
def consume(self, payload):
if self._ingestion_complete:
self._abort_and_notify(self._failure_outcome)
elif self._pending_ingestion is not None:
if self._processing:
self._pending_ingestion.append(payload)
else:
self._pool.submit(
callable_util.with_exceptions_logged(
self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE),
self._wrapped_ingestion_consumer, payload, False)
self._processing = True
def terminate(self):
if self._ingestion_complete:
self._abort_and_notify(self._failure_outcome)
else:
self._ingestion_complete = True
if self._pending_ingestion is not None and not self._processing:
self._pool.submit(
callable_util.with_exceptions_logged(
self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE),
self._wrapped_ingestion_consumer, None, True)
self._processing = True
def consume_and_terminate(self, payload):
if self._ingestion_complete:
self._abort_and_notify(self._failure_outcome)
else:
self._ingestion_complete = True
if self._pending_ingestion is not None:
if self._processing:
self._pending_ingestion.append(payload)
else:
self._pool.submit(
callable_util.with_exceptions_logged(
self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE),
self._wrapped_ingestion_consumer, payload, True)
self._processing = True
def abort(self):
"""See _interfaces.IngestionManager.abort for specification."""
self._abort_internal_only()
def front_ingestion_manager(
lock, pool, subscription, termination_manager, transmission_manager,
operation_context):
"""Creates an IngestionManager appropriate for front-side use.
Args:
lock: The operation-wide lock.
pool: A thread pool in which to execute customer code.
subscription: A interfaces.ServicedSubscription indicating the
customer's interest in the results of the operation.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
operation_context: A interfaces.OperationContext for the operation.
Returns:
An IngestionManager appropriate for front-side use.
"""
ingestion_manager = _IngestionManager(
lock, pool, _FrontConsumerCreator(subscription, operation_context),
interfaces.Outcome.SERVICED_FAILURE, termination_manager,
transmission_manager)
ingestion_manager.start(None)
return ingestion_manager
def back_ingestion_manager(
lock, pool, servicer, termination_manager, transmission_manager,
operation_context, emission_consumer):
"""Creates an IngestionManager appropriate for back-side use.
Args:
lock: The operation-wide lock.
pool: A thread pool in which to execute customer code.
servicer: A interfaces.Servicer for servicing the operation.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
operation_context: A interfaces.OperationContext for the operation.
emission_consumer: The _interfaces.EmissionConsumer for the operation.
Returns:
An IngestionManager appropriate for back-side use.
"""
ingestion_manager = _IngestionManager(
lock, pool, _BackConsumerCreator(
servicer, operation_context, emission_consumer),
interfaces.Outcome.SERVICER_FAILURE, termination_manager,
transmission_manager)
return ingestion_manager

@ -1,266 +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.
"""Package-internal interfaces."""
import abc
import six
# interfaces is referenced from specification in this module.
from grpc.framework.base import interfaces # pylint: disable=unused-import
from grpc.framework.foundation import stream
class TerminationManager(six.with_metaclass(abc.ABCMeta)):
"""An object responsible for handling the termination of an operation."""
@abc.abstractmethod
def set_expiration_manager(self, expiration_manager):
"""Sets the ExpirationManager with which this object will cooperate."""
raise NotImplementedError()
@abc.abstractmethod
def is_active(self):
"""Reports whether or not the operation is active.
Returns:
True if the operation is active or False if the operation has terminated.
"""
raise NotImplementedError()
@abc.abstractmethod
def add_callback(self, callback):
"""Registers a callback to be called on operation termination.
If the operation has already terminated, the callback will be called
immediately.
Args:
callback: A callable that will be passed an interfaces.Outcome value.
"""
raise NotImplementedError()
@abc.abstractmethod
def emission_complete(self):
"""Indicates that emissions from customer code have completed."""
raise NotImplementedError()
@abc.abstractmethod
def transmission_complete(self):
"""Indicates that transmissions to the remote end are complete."""
raise NotImplementedError()
@abc.abstractmethod
def ingestion_complete(self):
"""Indicates that customer code ingestion of received values is complete."""
raise NotImplementedError()
@abc.abstractmethod
def abort(self, outcome):
"""Indicates that the operation must abort for the indicated reason.
Args:
outcome: An interfaces.Outcome indicating operation abortion.
"""
raise NotImplementedError()
class TransmissionManager(six.with_metaclass(abc.ABCMeta)):
"""A manager responsible for transmitting to the other end of an operation."""
@abc.abstractmethod
def inmit(self, emission, complete):
"""Accepts a value for transmission to the other end of the operation.
Args:
emission: A value of some significance to the customer to be transmitted
to the other end of the operation. May be None only if complete is True.
complete: A boolean that if True indicates that customer code has emitted
all values it intends to emit.
"""
raise NotImplementedError()
@abc.abstractmethod
def abort(self, outcome):
"""Indicates that the operation has aborted for the indicated reason.
Args:
outcome: An interfaces.Outcome indicating operation abortion.
"""
raise NotImplementedError()
class EmissionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)):
"""A manager of values emitted by customer code."""
@abc.abstractmethod
def set_ingestion_manager_and_expiration_manager(
self, ingestion_manager, expiration_manager):
"""Sets two other objects with which this EmissionManager will cooperate.
Args:
ingestion_manager: The IngestionManager for the operation.
expiration_manager: The ExpirationManager for the operation.
"""
raise NotImplementedError()
@abc.abstractmethod
def consume(self, value):
"""Accepts a value emitted by customer code.
This method should only be called by customer code.
Args:
value: Any value of significance to the customer.
"""
raise NotImplementedError()
@abc.abstractmethod
def terminate(self):
"""Indicates that no more values will be emitted by customer code.
This method should only be called by customer code.
Implementations of this method may be idempotent and forgive customer code
calling this method more than once.
"""
raise NotImplementedError()
@abc.abstractmethod
def consume_and_terminate(self, value):
"""Accepts the last value emitted by customer code.
This method should only be called by customer code.
Args:
value: Any value of significance to the customer.
"""
raise NotImplementedError()
class IngestionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)):
"""A manager responsible for executing customer code."""
@abc.abstractmethod
def set_expiration_manager(self, expiration_manager):
"""Sets the ExpirationManager with which this object will cooperate."""
raise NotImplementedError()
@abc.abstractmethod
def start(self, requirement):
"""Commences execution of customer code.
Args:
requirement: Some value unavailable at the time of this object's
construction that is required to begin executing customer code.
"""
raise NotImplementedError()
@abc.abstractmethod
def consume(self, payload):
"""Accepts a customer-significant value to be supplied to customer code.
Args:
payload: Some customer-significant value.
"""
raise NotImplementedError()
@abc.abstractmethod
def terminate(self):
"""Indicates the end of values to be supplied to customer code."""
raise NotImplementedError()
@abc.abstractmethod
def consume_and_terminate(self, payload):
"""Accepts the last value to be supplied to customer code.
Args:
payload: Some customer-significant value (and the last such value).
"""
raise NotImplementedError()
@abc.abstractmethod
def abort(self):
"""Indicates to this manager that the operation has aborted."""
raise NotImplementedError()
class ExpirationManager(six.with_metaclass(abc.ABCMeta)):
"""A manager responsible for aborting the operation if it runs out of time."""
@abc.abstractmethod
def change_timeout(self, timeout):
"""Changes the timeout allotted for the operation.
Operation duration is always measure from the beginning of the operation;
calling this method changes the operation's allotted time to timeout total
seconds, not timeout seconds from the time of this method call.
Args:
timeout: A length of time in seconds to allow for the operation.
"""
raise NotImplementedError()
@abc.abstractmethod
def deadline(self):
"""Returns the time until which the operation is allowed to run.
Returns:
The time (seconds since the epoch) at which the operation will expire.
"""
raise NotImplementedError()
@abc.abstractmethod
def abort(self):
"""Indicates to this manager that the operation has aborted."""
raise NotImplementedError()
class ReceptionManager(six.with_metaclass(abc.ABCMeta)):
"""A manager responsible for receiving tickets from the other end."""
@abc.abstractmethod
def receive_ticket(self, ticket):
"""Handle a ticket from the other side of the operation.
Args:
ticket: An interfaces.BackToFrontTicket or interfaces.FrontToBackTicket
appropriate to this end of the operation and this object.
"""
raise NotImplementedError()
class CancellationManager(six.with_metaclass(abc.ABCMeta)):
"""A manager of operation cancellation."""
@abc.abstractmethod
def cancel(self):
"""Cancels the operation."""
raise NotImplementedError()

@ -1,400 +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.
"""State and behavior for ticket reception."""
import abc
import six
from grpc.framework.base import interfaces
from grpc.framework.base import _interfaces
_INITIAL_FRONT_TO_BACK_TICKET_KINDS = (
interfaces.FrontToBackTicket.Kind.COMMENCEMENT,
interfaces.FrontToBackTicket.Kind.ENTIRE,
)
class _Receiver(six.with_metaclass(abc.ABCMeta)):
"""Common specification of different ticket-handling behavior."""
@abc.abstractmethod
def abort_if_abortive(self, ticket):
"""Aborts the operation if the ticket is abortive.
Args:
ticket: A just-arrived ticket.
Returns:
A boolean indicating whether or not this Receiver aborted the operation
based on the ticket.
"""
raise NotImplementedError()
@abc.abstractmethod
def receive(self, ticket):
"""Handles a just-arrived ticket.
Args:
ticket: A just-arrived ticket.
Returns:
A boolean indicating whether or not the ticket was terminal (i.e. whether
or not non-abortive tickets are legal after this one).
"""
raise NotImplementedError()
@abc.abstractmethod
def reception_failure(self):
"""Aborts the operation with an indication of reception failure."""
raise NotImplementedError()
def _abort(
outcome, termination_manager, transmission_manager, ingestion_manager,
expiration_manager):
"""Indicates abortion with the given outcome to the given managers."""
termination_manager.abort(outcome)
transmission_manager.abort(outcome)
ingestion_manager.abort()
expiration_manager.abort()
def _abort_if_abortive(
ticket, abortive, termination_manager, transmission_manager,
ingestion_manager, expiration_manager):
"""Determines a ticket's being abortive and if so aborts the operation.
Args:
ticket: A just-arrived ticket.
abortive: A callable that takes a ticket and returns an interfaces.Outcome
indicating that the operation should be aborted or None indicating that
the operation should not be aborted.
termination_manager: The operation's _interfaces.TerminationManager.
transmission_manager: The operation's _interfaces.TransmissionManager.
ingestion_manager: The operation's _interfaces.IngestionManager.
expiration_manager: The operation's _interfaces.ExpirationManager.
Returns:
True if the operation was aborted; False otherwise.
"""
abortion_outcome = abortive(ticket)
if abortion_outcome is None:
return False
else:
_abort(
abortion_outcome, termination_manager, transmission_manager,
ingestion_manager, expiration_manager)
return True
def _reception_failure(
termination_manager, transmission_manager, ingestion_manager,
expiration_manager):
"""Aborts the operation with an indication of reception failure."""
_abort(
interfaces.Outcome.RECEPTION_FAILURE, termination_manager,
transmission_manager, ingestion_manager, expiration_manager)
class _BackReceiver(_Receiver):
"""Ticket-handling specific to the back side of an operation."""
def __init__(
self, termination_manager, transmission_manager, ingestion_manager,
expiration_manager):
"""Constructor.
Args:
termination_manager: The operation's _interfaces.TerminationManager.
transmission_manager: The operation's _interfaces.TransmissionManager.
ingestion_manager: The operation's _interfaces.IngestionManager.
expiration_manager: The operation's _interfaces.ExpirationManager.
"""
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._ingestion_manager = ingestion_manager
self._expiration_manager = expiration_manager
self._first_ticket_seen = False
self._last_ticket_seen = False
def _abortive(self, ticket):
"""Determines whether or not (and if so, how) a ticket is abortive.
Args:
ticket: A just-arrived ticket.
Returns:
An interfaces.Outcome value describing operation abortion if the
ticket is abortive or None if the ticket is not abortive.
"""
if ticket.kind is interfaces.FrontToBackTicket.Kind.CANCELLATION:
return interfaces.Outcome.CANCELLED
elif ticket.kind is interfaces.FrontToBackTicket.Kind.EXPIRATION:
return interfaces.Outcome.EXPIRED
elif ticket.kind is interfaces.FrontToBackTicket.Kind.SERVICED_FAILURE:
return interfaces.Outcome.SERVICED_FAILURE
elif ticket.kind is interfaces.FrontToBackTicket.Kind.RECEPTION_FAILURE:
return interfaces.Outcome.SERVICED_FAILURE
elif (ticket.kind in _INITIAL_FRONT_TO_BACK_TICKET_KINDS and
self._first_ticket_seen):
return interfaces.Outcome.RECEPTION_FAILURE
elif self._last_ticket_seen:
return interfaces.Outcome.RECEPTION_FAILURE
else:
return None
def abort_if_abortive(self, ticket):
"""See _Receiver.abort_if_abortive for specification."""
return _abort_if_abortive(
ticket, self._abortive, self._termination_manager,
self._transmission_manager, self._ingestion_manager,
self._expiration_manager)
def receive(self, ticket):
"""See _Receiver.receive for specification."""
if ticket.timeout is not None:
self._expiration_manager.change_timeout(ticket.timeout)
if ticket.kind is interfaces.FrontToBackTicket.Kind.COMMENCEMENT:
self._first_ticket_seen = True
self._ingestion_manager.start(ticket.name)
if ticket.payload is not None:
self._ingestion_manager.consume(ticket.payload)
elif ticket.kind is interfaces.FrontToBackTicket.Kind.CONTINUATION:
self._ingestion_manager.consume(ticket.payload)
elif ticket.kind is interfaces.FrontToBackTicket.Kind.COMPLETION:
self._last_ticket_seen = True
if ticket.payload is None:
self._ingestion_manager.terminate()
else:
self._ingestion_manager.consume_and_terminate(ticket.payload)
else:
self._first_ticket_seen = True
self._last_ticket_seen = True
self._ingestion_manager.start(ticket.name)
if ticket.payload is None:
self._ingestion_manager.terminate()
else:
self._ingestion_manager.consume_and_terminate(ticket.payload)
def reception_failure(self):
"""See _Receiver.reception_failure for specification."""
_reception_failure(
self._termination_manager, self._transmission_manager,
self._ingestion_manager, self._expiration_manager)
class _FrontReceiver(_Receiver):
"""Ticket-handling specific to the front side of an operation."""
def __init__(
self, termination_manager, transmission_manager, ingestion_manager,
expiration_manager):
"""Constructor.
Args:
termination_manager: The operation's _interfaces.TerminationManager.
transmission_manager: The operation's _interfaces.TransmissionManager.
ingestion_manager: The operation's _interfaces.IngestionManager.
expiration_manager: The operation's _interfaces.ExpirationManager.
"""
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._ingestion_manager = ingestion_manager
self._expiration_manager = expiration_manager
self._last_ticket_seen = False
def _abortive(self, ticket):
"""Determines whether or not (and if so, how) a ticket is abortive.
Args:
ticket: A just-arrived ticket.
Returns:
An interfaces.Outcome value describing operation abortion if the ticket
is abortive or None if the ticket is not abortive.
"""
if ticket.kind is interfaces.BackToFrontTicket.Kind.CANCELLATION:
return interfaces.Outcome.CANCELLED
elif ticket.kind is interfaces.BackToFrontTicket.Kind.EXPIRATION:
return interfaces.Outcome.EXPIRED
elif ticket.kind is interfaces.BackToFrontTicket.Kind.SERVICER_FAILURE:
return interfaces.Outcome.SERVICER_FAILURE
elif ticket.kind is interfaces.BackToFrontTicket.Kind.RECEPTION_FAILURE:
return interfaces.Outcome.SERVICER_FAILURE
elif self._last_ticket_seen:
return interfaces.Outcome.RECEPTION_FAILURE
else:
return None
def abort_if_abortive(self, ticket):
"""See _Receiver.abort_if_abortive for specification."""
return _abort_if_abortive(
ticket, self._abortive, self._termination_manager,
self._transmission_manager, self._ingestion_manager,
self._expiration_manager)
def receive(self, ticket):
"""See _Receiver.receive for specification."""
if ticket.kind is interfaces.BackToFrontTicket.Kind.CONTINUATION:
self._ingestion_manager.consume(ticket.payload)
elif ticket.kind is interfaces.BackToFrontTicket.Kind.COMPLETION:
self._last_ticket_seen = True
if ticket.payload is None:
self._ingestion_manager.terminate()
else:
self._ingestion_manager.consume_and_terminate(ticket.payload)
def reception_failure(self):
"""See _Receiver.reception_failure for specification."""
_reception_failure(
self._termination_manager, self._transmission_manager,
self._ingestion_manager, self._expiration_manager)
class _ReceptionManager(_interfaces.ReceptionManager):
"""A ReceptionManager based around a _Receiver passed to it."""
def __init__(self, lock, receiver):
"""Constructor.
Args:
lock: The operation-servicing-wide lock object.
receiver: A _Receiver responsible for handling received tickets.
"""
self._lock = lock
self._receiver = receiver
self._lowest_unseen_sequence_number = 0
self._out_of_sequence_tickets = {}
self._completed_sequence_number = None
self._aborted = False
def _sequence_failure(self, ticket):
"""Determines a just-arrived ticket's sequential legitimacy.
Args:
ticket: A just-arrived ticket.
Returns:
True if the ticket is sequentially legitimate; False otherwise.
"""
if ticket.sequence_number < self._lowest_unseen_sequence_number:
return True
elif ticket.sequence_number in self._out_of_sequence_tickets:
return True
elif (self._completed_sequence_number is not None and
self._completed_sequence_number <= ticket.sequence_number):
return True
else:
return False
def _process(self, ticket):
"""Process those tickets ready to be processed.
Args:
ticket: A just-arrived ticket the sequence number of which matches this
_ReceptionManager's _lowest_unseen_sequence_number field.
"""
while True:
completed = self._receiver.receive(ticket)
if completed:
self._out_of_sequence_tickets.clear()
self._completed_sequence_number = ticket.sequence_number
self._lowest_unseen_sequence_number = ticket.sequence_number + 1
return
else:
next_ticket = self._out_of_sequence_tickets.pop(
ticket.sequence_number + 1, None)
if next_ticket is None:
self._lowest_unseen_sequence_number = ticket.sequence_number + 1
return
else:
ticket = next_ticket
def receive_ticket(self, ticket):
"""See _interfaces.ReceptionManager.receive_ticket for specification."""
with self._lock:
if self._aborted:
return
elif self._sequence_failure(ticket):
self._receiver.reception_failure()
self._aborted = True
elif self._receiver.abort_if_abortive(ticket):
self._aborted = True
elif ticket.sequence_number == self._lowest_unseen_sequence_number:
self._process(ticket)
else:
self._out_of_sequence_tickets[ticket.sequence_number] = ticket
def front_reception_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
expiration_manager):
"""Creates a _interfaces.ReceptionManager for front-side use.
Args:
lock: The operation-servicing-wide lock object.
termination_manager: The operation's _interfaces.TerminationManager.
transmission_manager: The operation's _interfaces.TransmissionManager.
ingestion_manager: The operation's _interfaces.IngestionManager.
expiration_manager: The operation's _interfaces.ExpirationManager.
Returns:
A _interfaces.ReceptionManager appropriate for front-side use.
"""
return _ReceptionManager(
lock, _FrontReceiver(
termination_manager, transmission_manager, ingestion_manager,
expiration_manager))
def back_reception_manager(
lock, termination_manager, transmission_manager, ingestion_manager,
expiration_manager):
"""Creates a _interfaces.ReceptionManager for back-side use.
Args:
lock: The operation-servicing-wide lock object.
termination_manager: The operation's _interfaces.TerminationManager.
transmission_manager: The operation's _interfaces.TransmissionManager.
ingestion_manager: The operation's _interfaces.IngestionManager.
expiration_manager: The operation's _interfaces.ExpirationManager.
Returns:
A _interfaces.ReceptionManager appropriate for back-side use.
"""
return _ReceptionManager(
lock, _BackReceiver(
termination_manager, transmission_manager, ingestion_manager,
expiration_manager))

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save