aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Jorge Canizales <jcanizales@google.com>2015-02-17 19:28:18 -0800
committerGravatar Jorge Canizales <jcanizales@google.com>2015-02-17 19:28:18 -0800
commitdb128617534ace98f7e7e2c4e77d44bd366aae52 (patch)
tree80baba6ac2f9b49a0c1fe32dd04277ed8fcf095a /src
parentd1a8cc082acac3a01defa365b1ae98bc40c5ea3a (diff)
parent0a9ae3d23d48667d3fe915b233e4d5cab55be92f (diff)
Merge branch 'master' of https://github.com/grpc/grpc into import-ios-library
Diffstat (limited to 'src')
-rw-r--r--src/core/channel/connected_channel.c6
-rw-r--r--src/core/iomgr/fd_posix.c7
-rw-r--r--src/core/iomgr/pollset_posix.c1
-rw-r--r--src/core/iomgr/resolve_address.c14
-rw-r--r--src/core/iomgr/sockaddr_utils.c2
-rw-r--r--src/core/iomgr/socket_utils_linux.c5
-rw-r--r--src/core/iomgr/tcp_client_posix.c6
-rw-r--r--src/core/iomgr/tcp_server_posix.c38
-rw-r--r--src/core/security/security_context.c10
-rw-r--r--src/core/support/file_posix.c13
-rw-r--r--src/core/support/log_posix.c10
-rw-r--r--src/core/support/string_posix.c7
-rw-r--r--src/core/support/sync_posix.c7
-rw-r--r--src/core/support/time_posix.c12
-rw-r--r--src/core/surface/call.c17
-rw-r--r--src/core/surface/init.c28
-rw-r--r--src/core/transport/chttp2_transport.c29
-rw-r--r--src/core/transport/stream_op.c46
-rw-r--r--src/core/transport/stream_op.h6
-rw-r--r--src/csharp/GrpcApi/MathExamples.cs33
-rw-r--r--src/csharp/GrpcApi/MathGrpc.cs33
-rw-r--r--src/csharp/GrpcApi/MathServiceImpl.cs33
-rw-r--r--src/csharp/GrpcApi/proto/test.proto2
-rw-r--r--src/csharp/GrpcApiTests/MathClientServerTests.cs41
-rw-r--r--src/csharp/GrpcCore/Call.cs33
-rw-r--r--src/csharp/GrpcCore/Calls.cs33
-rw-r--r--src/csharp/GrpcCore/Channel.cs40
-rw-r--r--src/csharp/GrpcCore/ClientStreamingAsyncResult.cs33
-rw-r--r--src/csharp/GrpcCore/GrpcCore.csproj1
-rw-r--r--src/csharp/GrpcCore/GrpcEnvironment.cs112
-rw-r--r--src/csharp/GrpcCore/Internal/AsyncCall.cs33
-rw-r--r--src/csharp/GrpcCore/Internal/CallSafeHandle.cs137
-rw-r--r--src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs45
-rw-r--r--src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs67
-rw-r--r--src/csharp/GrpcCore/Internal/Enums.cs33
-rw-r--r--src/csharp/GrpcCore/Internal/Event.cs117
-rw-r--r--src/csharp/GrpcCore/Internal/GrpcThreadPool.cs33
-rw-r--r--src/csharp/GrpcCore/Internal/SafeHandleZeroIsInvalid.cs33
-rw-r--r--src/csharp/GrpcCore/Internal/ServerSafeHandle.cs79
-rw-r--r--src/csharp/GrpcCore/Internal/ServerWritingObserver.cs33
-rw-r--r--src/csharp/GrpcCore/Internal/StreamingInputObserver.cs33
-rw-r--r--src/csharp/GrpcCore/Internal/Timespec.cs71
-rw-r--r--src/csharp/GrpcCore/Marshaller.cs33
-rw-r--r--src/csharp/GrpcCore/Method.cs33
-rw-r--r--src/csharp/GrpcCore/RpcException.cs33
-rw-r--r--src/csharp/GrpcCore/Server.cs37
-rw-r--r--src/csharp/GrpcCore/ServerCallHandler.cs33
-rw-r--r--src/csharp/GrpcCore/ServerCalls.cs33
-rw-r--r--src/csharp/GrpcCore/ServerServiceDefinition.cs33
-rw-r--r--src/csharp/GrpcCore/Status.cs33
-rw-r--r--src/csharp/GrpcCore/StatusCode.cs33
-rw-r--r--src/csharp/GrpcCore/Utils/PortPicker.cs50
-rw-r--r--src/csharp/GrpcCore/Utils/RecordingObserver.cs33
-rw-r--r--src/csharp/GrpcCore/Utils/RecordingQueue.cs34
-rw-r--r--src/csharp/GrpcCoreTests/ClientServerTest.cs41
-rw-r--r--src/csharp/GrpcCoreTests/GrpcEnvironmentTest.cs57
-rw-r--r--src/csharp/GrpcCoreTests/ServerTest.cs39
-rw-r--r--src/csharp/GrpcCoreTests/TimespecTest.cs64
-rw-r--r--src/csharp/InteropClient/Client.cs35
-rw-r--r--src/csharp/MathClient/MathClient.cs35
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c304
-rw-r--r--src/node/binding.gyp9
-rw-r--r--src/node/ext/call.cc654
-rw-r--r--src/node/ext/call.h65
-rw-r--r--src/node/ext/completion_queue_async_worker.cc25
-rw-r--r--src/node/ext/completion_queue_async_worker.h2
-rw-r--r--src/node/ext/credentials.cc1
-rw-r--r--src/node/ext/event.cc173
-rw-r--r--src/node/ext/event.h48
-rw-r--r--src/node/ext/node_grpc.cc58
-rw-r--r--src/node/ext/server.cc65
-rw-r--r--src/node/ext/server_credentials.cc1
-rw-r--r--src/node/ext/tag.cc101
-rw-r--r--src/node/ext/tag.h59
-rw-r--r--src/node/index.js10
-rw-r--r--src/node/interop/interop_client.js2
-rw-r--r--src/node/interop/test.proto2
-rw-r--r--src/node/package.json2
-rw-r--r--src/node/src/client.js525
-rw-r--r--src/node/src/common.js25
-rw-r--r--src/node/src/server.js583
-rw-r--r--src/node/src/surface_client.js357
-rw-r--r--src/node/src/surface_server.js340
-rw-r--r--src/node/test/call_test.js126
-rw-r--r--src/node/test/client_server_test.js255
-rw-r--r--src/node/test/constant_test.js37
-rw-r--r--src/node/test/end_to_end_test.js250
-rw-r--r--src/node/test/interop_sanity_test.js2
-rw-r--r--src/node/test/math_client_test.js3
-rw-r--r--src/node/test/server_test.js122
-rw-r--r--src/node/test/surface_test.js4
-rw-r--r--src/python/interop/interop/__init__.py0
-rwxr-xr-xsrc/python/interop/interop/credentials/README1
-rwxr-xr-xsrc/python/interop/interop/credentials/server1.key16
-rwxr-xr-xsrc/python/interop/interop/credentials/server1.pem16
-rw-r--r--src/python/interop/interop/empty_pb2.py60
-rw-r--r--src/python/interop/interop/messages_pb2.py444
-rw-r--r--src/python/interop/interop/methods.py109
-rw-r--r--src/python/interop/interop/server.py91
-rw-r--r--src/python/interop/interop/test_pb2.py32
-rw-r--r--src/python/interop/setup.py51
-rw-r--r--src/python/src/_adapter/_face_test_case.py2
-rw-r--r--src/python/src/_adapter/_links_test.py6
-rw-r--r--src/python/src/_adapter/_low.py1
-rw-r--r--src/python/src/_adapter/_server.c15
-rw-r--r--src/python/src/_adapter/fore.py21
-rw-r--r--src/python/src/_framework/base/packets/_ingestion.py13
-rw-r--r--src/python/src/_framework/face/_calls.py195
-rw-r--r--src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py84
-rw-r--r--src/python/src/_framework/foundation/_later_test.py62
-rw-r--r--src/python/src/_framework/foundation/_timer_future.py116
-rw-r--r--src/python/src/_framework/foundation/callable_util.py39
-rw-r--r--src/python/src/_framework/foundation/future.py232
-rw-r--r--src/python/src/grpc_early_adopter/__init__.py0
-rw-r--r--src/python/src/grpc_early_adopter/_face_utilities.py143
-rw-r--r--src/python/src/grpc_early_adopter/implementations.py129
-rw-r--r--src/python/src/grpc_early_adopter/interfaces.py194
-rw-r--r--src/python/src/grpc_early_adopter/utilities.py213
-rw-r--r--src/python/src/setup.py (renamed from src/python/setup.py)35
-rw-r--r--src/ruby/spec/client_server_spec.rb10
120 files changed, 5678 insertions, 2923 deletions
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index 61a6caf032..2d61d389e4 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -467,17 +467,11 @@ static void transport_goaway(void *user_data, grpc_transport *transport,
/* transport got goaway ==> call up and handle it */
grpc_channel_element *elem = user_data;
channel_data *chand = elem->channel_data;
- char *msg;
grpc_channel_op op;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(chand->transport == transport);
- msg = gpr_hexdump((const char *)GPR_SLICE_START_PTR(debug),
- GPR_SLICE_LENGTH(debug), GPR_HEXDUMP_PLAINTEXT);
- gpr_log(GPR_DEBUG, "got goaway: status=%d, message=%s", status, msg);
- gpr_free(msg);
-
op.type = GRPC_TRANSPORT_GOAWAY;
op.dir = GRPC_CALL_UP;
op.data.goaway.status = status;
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index 737ee016aa..cc57830551 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -104,14 +104,17 @@ static void destroy(grpc_fd *fd) {
}
static void ref_by(grpc_fd *fd, int n) {
- gpr_atm_no_barrier_fetch_add(&fd->refst, n);
+ GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
}
static void unref_by(grpc_fd *fd, int n) {
- if (gpr_atm_full_fetch_add(&fd->refst, -n) == n) {
+ gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n);
+ if (old == n) {
grpc_iomgr_add_callback(fd->on_done, fd->on_done_user_data);
freelist_fd(fd);
grpc_iomgr_unref();
+ } else {
+ GPR_ASSERT(old > n);
}
}
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 53c9806fb9..1245d22dde 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -214,6 +214,7 @@ static void unary_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
* unary poller */
grpc_fd_unref(fds[0]);
pollset->data.ptr = fd;
+ grpc_fd_ref(fd);
}
}
diff --git a/src/core/iomgr/resolve_address.c b/src/core/iomgr/resolve_address.c
index 575f884d91..e17bcdba0f 100644
--- a/src/core/iomgr/resolve_address.c
+++ b/src/core/iomgr/resolve_address.c
@@ -39,6 +39,7 @@
#include "src/core/iomgr/resolve_address.h"
#include <sys/types.h>
+#include <sys/un.h>
#include <string.h>
#include "src/core/iomgr/iomgr_internal.h"
@@ -123,6 +124,19 @@ grpc_resolved_addresses *grpc_blocking_resolve_address(
size_t i;
grpc_resolved_addresses *addrs = NULL;
const gpr_timespec start_time = gpr_now();
+ struct sockaddr_un *un;
+
+ if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' &&
+ name[4] == ':' && name[5] != 0) {
+ addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+ addrs->naddrs = 1;
+ addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address));
+ un = (struct sockaddr_un *)addrs->addrs->addr;
+ un->sun_family = AF_UNIX;
+ strcpy(un->sun_path, name + 5);
+ addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family);
+ return addrs;
+ }
/* parse name, splitting it into host and port parts */
split_host_port(name, &host, &port);
diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c
index 8dcfca74c6..f794241776 100644
--- a/src/core/iomgr/sockaddr_utils.c
+++ b/src/core/iomgr/sockaddr_utils.c
@@ -166,6 +166,8 @@ int grpc_sockaddr_get_port(const struct sockaddr *addr) {
return ntohs(((struct sockaddr_in *)addr)->sin_port);
case AF_INET6:
return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
+ case AF_UNIX:
+ return 1;
default:
gpr_log(GPR_ERROR, "Unknown socket family %d in %s", addr->sa_family,
__FUNCTION__);
diff --git a/src/core/iomgr/socket_utils_linux.c b/src/core/iomgr/socket_utils_linux.c
index 7ef58940c2..f3c22187d7 100644
--- a/src/core/iomgr/socket_utils_linux.c
+++ b/src/core/iomgr/socket_utils_linux.c
@@ -31,12 +31,9 @@
*
*/
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
#include <grpc/support/port_platform.h>
-#ifdef GPR_LINUX
+#ifdef GPR_LINUX_SOCKETUTILS
#include "src/core/iomgr/socket_utils_posix.h"
diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c
index 851530ce68..6dc7997833 100644
--- a/src/core/iomgr/tcp_client_posix.c
+++ b/src/core/iomgr/tcp_client_posix.c
@@ -62,13 +62,13 @@ typedef struct {
int refs;
} async_connect;
-static int prepare_socket(int fd) {
+static int prepare_socket(const struct sockaddr *addr, int fd) {
if (fd < 0) {
goto error;
}
if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
- !grpc_set_socket_low_latency(fd, 1)) {
+ (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1))) {
gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
strerror(errno));
goto error;
@@ -200,7 +200,7 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
addr = (struct sockaddr *)&addr4_copy;
addr_len = sizeof(addr4_copy);
}
- if (!prepare_socket(fd)) {
+ if (!prepare_socket(addr, fd)) {
cb(arg, NULL);
return;
}
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 091f0aab1a..9e5076efc7 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -42,18 +42,21 @@
#include "src/core/iomgr/tcp_server.h"
-#include <limits.h>
+#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
-#include <sys/types.h>
+#include <string.h>
#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
#include <unistd.h>
-#include <string.h>
-#include <errno.h>
#include "src/core/iomgr/pollset_posix.h"
+#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/iomgr/socket_utils_posix.h"
#include "src/core/iomgr/tcp_posix.h"
@@ -73,8 +76,22 @@ typedef struct {
int fd;
grpc_fd *emfd;
grpc_tcp_server *server;
+ union {
+ gpr_uint8 untyped[GRPC_MAX_SOCKADDR_SIZE];
+ struct sockaddr sockaddr;
+ struct sockaddr_un un;
+ } addr;
+ int addr_len;
} server_port;
+static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
+ struct stat st;
+
+ if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
+ unlink(un->sun_path);
+ }
+}
+
/* the overall server */
struct grpc_tcp_server {
grpc_tcp_server_cb cb;
@@ -121,6 +138,9 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s) {
/* delete ALL the things */
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
+ if (sp->addr.sockaddr.sa_family == AF_UNIX) {
+ unlink_if_unix_domain_socket(&sp->addr.un);
+ }
grpc_fd_orphan(sp->emfd, NULL, NULL);
}
gpr_free(s->ports);
@@ -170,8 +190,8 @@ static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) {
}
if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
- !grpc_set_socket_low_latency(fd, 1) ||
- !grpc_set_socket_reuse_addr(fd, 1)) {
+ (addr->sa_family != AF_UNIX && (!grpc_set_socket_low_latency(fd, 1) ||
+ !grpc_set_socket_reuse_addr(fd, 1)))) {
gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
strerror(errno));
goto error;
@@ -265,6 +285,8 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
sp->server = s;
sp->fd = fd;
sp->emfd = grpc_fd_create(fd);
+ memcpy(sp->addr.untyped, addr, addr_len);
+ sp->addr_len = addr_len;
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
}
@@ -288,6 +310,10 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
socklen_t sockname_len;
int port;
+ if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
+ unlink_if_unix_domain_socket(addr);
+ }
+
/* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) {
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index adb0269792..1909617614 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -349,11 +349,13 @@ static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx,
void *user_data) {
grpc_ssl_channel_security_context *c =
(grpc_ssl_channel_security_context *)ctx;
- grpc_security_status status = ssl_check_peer(c->overridden_target_name != NULL
- ? c->overridden_target_name
- : c->target_name,
- &peer);
+ grpc_security_status status;
+ tsi_peer_destruct(&c->peer);
c->peer = peer;
+ status = ssl_check_peer(c->overridden_target_name != NULL
+ ? c->overridden_target_name
+ : c->target_name,
+ &peer);
return status;
}
diff --git a/src/core/support/file_posix.c b/src/core/support/file_posix.c
index cb48b3d52f..e1765666db 100644
--- a/src/core/support/file_posix.c
+++ b/src/core/support/file_posix.c
@@ -31,19 +31,6 @@
*
*/
-/* Posix code for gpr fdopen and mkstemp support. */
-
-#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 200112L
-#undef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-/* Don't know why I have to do this for mkstemp, looks like _POSIX_C_SOURCE
- should be enough... */
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE
-#endif
-
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_FILE
diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c
index 05f45de130..36479baeed 100644
--- a/src/core/support/log_posix.c
+++ b/src/core/support/log_posix.c
@@ -31,16 +31,6 @@
*
*/
-#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 200112L
-#undef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-/* FIXME: "posix" files probably shouldn't depend on _GNU_SOURCE */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
#include <grpc/support/port_platform.h>
#if defined(GPR_POSIX_LOG)
diff --git a/src/core/support/string_posix.c b/src/core/support/string_posix.c
index a6bb8058e6..b6f0cd4af0 100644
--- a/src/core/support/string_posix.c
+++ b/src/core/support/string_posix.c
@@ -31,13 +31,6 @@
*
*/
-/* Posix code for gpr snprintf support. */
-
-#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 200112L
-#undef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200112L
-#endif
-
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_STRING
diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c
index a28a4c6bf4..94fc1b0bec 100644
--- a/src/core/support/sync_posix.c
+++ b/src/core/support/sync_posix.c
@@ -31,13 +31,6 @@
*
*/
-/* Posix gpr synchroization support code. */
-
-#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 199309L
-#undef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 199309L
-#endif
-
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SYNC
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
index 7f0f028183..4af537d974 100644
--- a/src/core/support/time_posix.c
+++ b/src/core/support/time_posix.c
@@ -31,14 +31,6 @@
*
*/
-/* Posix code for gpr time support. */
-
-/* So we get nanosleep and clock_* */
-#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 199309L
-#undef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 199309L
-#endif
-
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_TIME
@@ -70,7 +62,9 @@ gpr_timespec gpr_now(void) {
}
#else
/* For some reason Apple's OSes haven't implemented clock_gettime. */
-/* TODO(klempner): Add special handling for Apple. */
+
+#include <sys/time.h>
+
gpr_timespec gpr_now(void) {
gpr_timespec now;
struct timeval now_tv;
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 0af2154842..58a2436937 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -514,32 +514,32 @@ static void finish_ioreq_op(grpc_call *call, grpc_ioreq_op op,
}
}
-static void finish_send_op(grpc_call *call, grpc_ioreq_op op,
+static void finish_send_op(grpc_call *call, grpc_ioreq_op op, write_state ws,
grpc_op_error error) {
lock(call);
finish_ioreq_op(call, op, error);
call->sending = 0;
+ call->write_state = ws;
unlock(call);
grpc_call_internal_unref(call, 0);
}
static void finish_write_step(void *pc, grpc_op_error error) {
- finish_send_op(pc, GRPC_IOREQ_SEND_MESSAGE, error);
+ finish_send_op(pc, GRPC_IOREQ_SEND_MESSAGE, WRITE_STATE_STARTED, error);
}
static void finish_finish_step(void *pc, grpc_op_error error) {
- finish_send_op(pc, GRPC_IOREQ_SEND_CLOSE, error);
+ finish_send_op(pc, GRPC_IOREQ_SEND_CLOSE, WRITE_STATE_WRITE_CLOSED, error);
}
static void finish_start_step(void *pc, grpc_op_error error) {
- finish_send_op(pc, GRPC_IOREQ_SEND_INITIAL_METADATA, error);
+ finish_send_op(pc, GRPC_IOREQ_SEND_INITIAL_METADATA, WRITE_STATE_STARTED, error);
}
static send_action choose_send_action(grpc_call *call) {
switch (call->write_state) {
case WRITE_STATE_INITIAL:
if (is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) {
- call->write_state = WRITE_STATE_STARTED;
if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE) || is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
return SEND_BUFFERED_INITIAL_METADATA;
} else {
@@ -555,7 +555,6 @@ static send_action choose_send_action(grpc_call *call) {
return SEND_MESSAGE;
}
} else if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
- call->write_state = WRITE_STATE_WRITE_CLOSED;
finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, GRPC_OP_OK);
finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, GRPC_OP_OK);
if (call->is_client) {
@@ -992,6 +991,12 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
const grpc_op *op;
grpc_ioreq *req;
+ if (nops == 0) {
+ grpc_cq_begin_op(call->cq, call, GRPC_OP_COMPLETE);
+ grpc_cq_end_op_complete(call->cq, tag, call, do_nothing, NULL, GRPC_OP_OK);
+ return GRPC_CALL_OK;
+ }
+
/* rewrite batch ops into ioreq ops */
for (in = 0, out = 0; in < nops; in++) {
op = &ops[in];
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index b5019eb03f..4d639fcbce 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -35,12 +35,32 @@
#include "src/core/statistics/census_interface.h"
#include "src/core/iomgr/iomgr.h"
+static gpr_once g_init = GPR_ONCE_INIT;
+static gpr_mu g_init_mu;
+static int g_initializations;
+
+static void do_init() {
+ gpr_mu_init(&g_init_mu);
+ g_initializations = 0;
+}
+
void grpc_init(void) {
- grpc_iomgr_init();
- census_init();
+ gpr_once_init(&g_init, do_init);
+
+ gpr_mu_lock(&g_init_mu);
+ if (++g_initializations == 1) {
+ grpc_iomgr_init();
+ census_init();
+ }
+ gpr_mu_unlock(&g_init_mu);
}
void grpc_shutdown(void) {
- grpc_iomgr_shutdown();
- census_shutdown();
+ gpr_mu_lock(&g_init_mu);
+ if (--g_initializations == 0) {
+ grpc_iomgr_shutdown();
+ census_shutdown();
+ }
+ gpr_mu_unlock(&g_init_mu);
}
+
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index ea579cf4a5..5921c3806e 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -184,11 +184,13 @@ struct transport {
gpr_uint8 is_client;
gpr_mu mu;
+ gpr_cv cv;
/* basic state management - what are we doing at the moment? */
gpr_uint8 reading;
gpr_uint8 writing;
gpr_uint8 calling_back;
+ gpr_uint8 destroying;
error_state error_state;
/* stream indexing */
@@ -362,6 +364,7 @@ static void unref_transport(transport *t) {
gpr_mu_unlock(&t->mu);
gpr_mu_destroy(&t->mu);
+ gpr_cv_destroy(&t->cv);
/* callback remaining pings: they're not allowed to call into the transpot,
and maybe they hold resources that need to be freed */
@@ -397,6 +400,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
/* one ref is for destroy, the other for when ep becomes NULL */
gpr_ref_init(&t->refs, 2);
gpr_mu_init(&t->mu);
+ gpr_cv_init(&t->cv);
t->metadata_context = mdctx;
t->str_grpc_timeout =
grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
@@ -405,6 +409,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
t->error_state = ERROR_STATE_NONE;
t->next_stream_id = is_client ? 1 : 2;
t->last_incoming_stream_id = 0;
+ t->destroying = 0;
t->is_client = is_client;
t->outgoing_window = DEFAULT_WINDOW;
t->incoming_window = DEFAULT_WINDOW;
@@ -487,6 +492,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
t->cb = sr.callbacks;
t->cb_user_data = sr.user_data;
t->calling_back = 0;
+ if (t->destroying) gpr_cv_signal(&t->cv);
unlock(t);
unref_transport(t);
}
@@ -495,6 +501,10 @@ static void destroy_transport(grpc_transport *gt) {
transport *t = (transport *)gt;
gpr_mu_lock(&t->mu);
+ t->destroying = 1;
+ while (t->calling_back) {
+ gpr_cv_wait(&t->cv, &t->mu, gpr_inf_future);
+ }
t->cb = NULL;
gpr_mu_unlock(&t->mu);
@@ -684,10 +694,11 @@ static void unlock(transport *t) {
int i;
pending_goaway *goaways = NULL;
grpc_endpoint *ep = t->ep;
- grpc_stream_op_buffer nuke_now = t->nuke_later_sopb;
-
- if (nuke_now.nops) {
- memset(&t->nuke_later_sopb, 0, sizeof(t->nuke_later_sopb));
+ grpc_stream_op_buffer nuke_now;
+
+ grpc_sopb_init(&nuke_now);
+ if (t->nuke_later_sopb.nops) {
+ grpc_sopb_swap(&nuke_now, &t->nuke_later_sopb);
}
/* see if we need to trigger a write - and if so, get the data ready */
@@ -753,13 +764,12 @@ static void unlock(transport *t) {
if (perform_callbacks || call_closed || num_goaways) {
lock(t);
t->calling_back = 0;
+ if (t->destroying) gpr_cv_signal(&t->cv);
unlock(t);
unref_transport(t);
}
- if (nuke_now.nops) {
- grpc_sopb_destroy(&nuke_now);
- }
+ grpc_sopb_destroy(&nuke_now);
gpr_free(goaways);
}
@@ -1698,13 +1708,10 @@ static grpc_stream_state compute_state(gpr_uint8 write_closed,
static int prepare_callbacks(transport *t) {
stream *s;
- grpc_stream_op_buffer temp_sopb;
int n = 0;
while ((s = stream_list_remove_head(t, PENDING_CALLBACKS))) {
int execute = 1;
- temp_sopb = s->parser.incoming_sopb;
- s->parser.incoming_sopb = s->callback_sopb;
- s->callback_sopb = temp_sopb;
+ grpc_sopb_swap(&s->parser.incoming_sopb, &s->callback_sopb);
s->callback_state = compute_state(s->sent_write_closed, s->read_closed);
if (s->callback_state == GRPC_STREAM_CLOSED) {
diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c
index 555543fc4b..03a338bd9b 100644
--- a/src/core/transport/stream_op.c
+++ b/src/core/transport/stream_op.c
@@ -38,23 +38,19 @@
#include <string.h>
-/* Initial number of operations to allocate */
-#define INITIAL_SLOTS 8
/* Exponential growth function: Given x, return a larger x.
- Currently we grow by 1.5 times upon reallocation.
- Assumes INITIAL_SLOTS > 1 */
+ Currently we grow by 1.5 times upon reallocation. */
#define GROW(x) (3 * (x) / 2)
void grpc_sopb_init(grpc_stream_op_buffer *sopb) {
- sopb->ops = gpr_malloc(sizeof(grpc_stream_op) * INITIAL_SLOTS);
- GPR_ASSERT(sopb->ops);
+ sopb->ops = sopb->inlined_ops;
sopb->nops = 0;
- sopb->capacity = INITIAL_SLOTS;
+ sopb->capacity = GRPC_SOPB_INLINE_ELEMENTS;
}
void grpc_sopb_destroy(grpc_stream_op_buffer *sopb) {
grpc_stream_ops_unref_owned_objects(sopb->ops, sopb->nops);
- gpr_free(sopb->ops);
+ if (sopb->ops != sopb->inlined_ops) gpr_free(sopb->ops);
}
void grpc_sopb_reset(grpc_stream_op_buffer *sopb) {
@@ -62,6 +58,19 @@ void grpc_sopb_reset(grpc_stream_op_buffer *sopb) {
sopb->nops = 0;
}
+void grpc_sopb_swap(grpc_stream_op_buffer *a, grpc_stream_op_buffer *b) {
+ grpc_stream_op_buffer temp = *a;
+ *a = *b;
+ *b = temp;
+
+ if (a->ops == b->inlined_ops) {
+ a->ops = a->inlined_ops;
+ }
+ if (b->ops == a->inlined_ops) {
+ b->ops = b->inlined_ops;
+ }
+}
+
void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) {
size_t i;
for (i = 0; i < nops; i++) {
@@ -84,17 +93,21 @@ void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) {
}
}
-static void expand(grpc_stream_op_buffer *sopb) {
- sopb->capacity = GROW(sopb->capacity);
- sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * sopb->capacity);
- GPR_ASSERT(sopb->ops);
+static void expandto(grpc_stream_op_buffer *sopb, size_t new_capacity) {
+ sopb->capacity = new_capacity;
+ if (sopb->ops == sopb->inlined_ops) {
+ sopb->ops = gpr_malloc(sizeof(grpc_stream_op) * new_capacity);
+ memcpy(sopb->ops, sopb->inlined_ops, sopb->nops * sizeof(grpc_stream_op));
+ } else {
+ sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * new_capacity);
+ }
}
static grpc_stream_op *add(grpc_stream_op_buffer *sopb) {
grpc_stream_op *out;
if (sopb->nops == sopb->capacity) {
- expand(sopb);
+ expandto(sopb, GROW(sopb->capacity));
}
out = sopb->ops + sopb->nops;
sopb->nops++;
@@ -152,12 +165,7 @@ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
size_t new_nops = orig_nops + nops;
if (new_nops > sopb->capacity) {
- size_t new_capacity = GROW(sopb->capacity);
- if (new_capacity < new_nops) {
- new_capacity = new_nops;
- }
- sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * new_capacity);
- sopb->capacity = new_capacity;
+ expandto(sopb, GPR_MAX(GROW(sopb->capacity), new_nops));
}
memcpy(sopb->ops + orig_nops, ops, sizeof(grpc_stream_op) * nops);
diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h
index 20d609133f..d4d7515c4f 100644
--- a/src/core/transport/stream_op.h
+++ b/src/core/transport/stream_op.h
@@ -40,6 +40,9 @@
#include <grpc/support/time.h>
#include "src/core/transport/metadata.h"
+/* this many stream ops are inlined into a sopb before allocating */
+#define GRPC_SOPB_INLINE_ELEMENTS 16
+
/* Operations that can be performed on a stream.
Used by grpc_stream_op. */
typedef enum grpc_stream_op_code {
@@ -96,6 +99,7 @@ typedef struct grpc_stream_op_buffer {
grpc_stream_op *ops;
size_t nops;
size_t capacity;
+ grpc_stream_op inlined_ops[GRPC_SOPB_INLINE_ELEMENTS];
} grpc_stream_op_buffer;
/* Initialize a stream op buffer */
@@ -104,6 +108,8 @@ void grpc_sopb_init(grpc_stream_op_buffer *sopb);
void grpc_sopb_destroy(grpc_stream_op_buffer *sopb);
/* Reset a sopb to no elements */
void grpc_sopb_reset(grpc_stream_op_buffer *sopb);
+/* Swap two sopbs */
+void grpc_sopb_swap(grpc_stream_op_buffer *a, grpc_stream_op_buffer *b);
void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops);
diff --git a/src/csharp/GrpcApi/MathExamples.cs b/src/csharp/GrpcApi/MathExamples.cs
index 43f0cedef6..07bcc9c9cd 100644
--- a/src/csharp/GrpcApi/MathExamples.cs
+++ b/src/csharp/GrpcApi/MathExamples.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
diff --git a/src/csharp/GrpcApi/MathGrpc.cs b/src/csharp/GrpcApi/MathGrpc.cs
index 520fec437a..606e7f0239 100644
--- a/src/csharp/GrpcApi/MathGrpc.cs
+++ b/src/csharp/GrpcApi/MathGrpc.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/csharp/GrpcApi/MathServiceImpl.cs b/src/csharp/GrpcApi/MathServiceImpl.cs
index 27abc4ce17..ffd794d6c6 100644
--- a/src/csharp/GrpcApi/MathServiceImpl.cs
+++ b/src/csharp/GrpcApi/MathServiceImpl.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/csharp/GrpcApi/proto/test.proto b/src/csharp/GrpcApi/proto/test.proto
index 8380ebb31d..996f11aa6d 100644
--- a/src/csharp/GrpcApi/proto/test.proto
+++ b/src/csharp/GrpcApi/proto/test.proto
@@ -14,7 +14,7 @@ service TestService {
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
- // The server returns the client payload as-is.
+ // TODO(Issue 527): Describe required server behavior.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by a sequence of responses (streamed download).
diff --git a/src/csharp/GrpcApiTests/MathClientServerTests.cs b/src/csharp/GrpcApiTests/MathClientServerTests.cs
index aa78b698e8..bb3f75d4ac 100644
--- a/src/csharp/GrpcApiTests/MathClientServerTests.cs
+++ b/src/csharp/GrpcApiTests/MathClientServerTests.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using NUnit.Framework;
using Google.GRPC.Core;
@@ -13,7 +46,7 @@ namespace math.Tests
/// </summary>
public class MathClientServerTest
{
- string serverAddr = "localhost:" + PortPicker.PickUnusedPort();
+ string host = "localhost";
Server server;
Channel channel;
MathGrpc.IMathServiceClient client;
@@ -21,11 +54,13 @@ namespace math.Tests
[TestFixtureSetUp]
public void Init()
{
+ GrpcEnvironment.Initialize();
+
server = new Server();
server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl()));
- server.AddPort(serverAddr);
+ int port = server.AddPort(host + ":0");
server.Start();
- channel = new Channel(serverAddr);
+ channel = new Channel(host + ":" + port);
client = MathGrpc.NewStub(channel);
}
diff --git a/src/csharp/GrpcCore/Call.cs b/src/csharp/GrpcCore/Call.cs
index 66e7004180..181210902f 100644
--- a/src/csharp/GrpcCore/Call.cs
+++ b/src/csharp/GrpcCore/Call.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using Google.GRPC.Core.Internal;
diff --git a/src/csharp/GrpcCore/Calls.cs b/src/csharp/GrpcCore/Calls.cs
index c3e51cb478..101965600e 100644
--- a/src/csharp/GrpcCore/Calls.cs
+++ b/src/csharp/GrpcCore/Calls.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/csharp/GrpcCore/Channel.cs b/src/csharp/GrpcCore/Channel.cs
index b0d8beeb7b..cd4f151f49 100644
--- a/src/csharp/GrpcCore/Channel.cs
+++ b/src/csharp/GrpcCore/Channel.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Threading;
@@ -8,13 +41,6 @@ namespace Google.GRPC.Core
{
public class Channel : IDisposable
{
- /// <summary>
- /// Make sure GPRC environment is initialized before any channels get used.
- /// </summary>
- static Channel() {
- GrpcEnvironment.EnsureInitialized();
- }
-
readonly ChannelSafeHandle handle;
readonly String target;
diff --git a/src/csharp/GrpcCore/ClientStreamingAsyncResult.cs b/src/csharp/GrpcCore/ClientStreamingAsyncResult.cs
index 9e7312c1fa..507d0dd8ad 100644
--- a/src/csharp/GrpcCore/ClientStreamingAsyncResult.cs
+++ b/src/csharp/GrpcCore/ClientStreamingAsyncResult.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Threading.Tasks;
diff --git a/src/csharp/GrpcCore/GrpcCore.csproj b/src/csharp/GrpcCore/GrpcCore.csproj
index 95df890917..34b9f6dfb8 100644
--- a/src/csharp/GrpcCore/GrpcCore.csproj
+++ b/src/csharp/GrpcCore/GrpcCore.csproj
@@ -61,7 +61,6 @@
<Compile Include="Marshaller.cs" />
<Compile Include="ServerServiceDefinition.cs" />
<Compile Include="Utils\RecordingObserver.cs" />
- <Compile Include="Utils\PortPicker.cs" />
<Compile Include="Utils\RecordingQueue.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
diff --git a/src/csharp/GrpcCore/GrpcEnvironment.cs b/src/csharp/GrpcCore/GrpcEnvironment.cs
index 201320828b..ee1168621d 100644
--- a/src/csharp/GrpcCore/GrpcEnvironment.cs
+++ b/src/csharp/GrpcCore/GrpcEnvironment.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using Google.GRPC.Core.Internal;
using System.Runtime.InteropServices;
@@ -5,36 +38,37 @@ using System.Runtime.InteropServices;
namespace Google.GRPC.Core
{
/// <summary>
- /// Encapsulates initialization and shutdown of GRPC C core library.
- /// You should not need to initialize it manually, as static constructors
- /// should load the library when needed.
+ /// Encapsulates initialization and shutdown of gRPC library.
/// </summary>
- public static class GrpcEnvironment
+ public class GrpcEnvironment
{
const int THREAD_POOL_SIZE = 1;
- [DllImport("grpc.dll")]
- static extern void grpc_init();
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_init();
- [DllImport("grpc.dll")]
- static extern void grpc_shutdown();
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_shutdown();
static object staticLock = new object();
- static bool initCalled = false;
- static bool shutdownCalled = false;
-
- static GrpcThreadPool threadPool = new GrpcThreadPool(THREAD_POOL_SIZE);
+ static volatile GrpcEnvironment instance;
+
+ readonly GrpcThreadPool threadPool;
+ bool isClosed;
/// <summary>
- /// Makes sure GRPC environment is initialized.
+ /// Makes sure GRPC environment is initialized. Subsequent invocations don't have any
+ /// effect unless you call Shutdown first.
+ /// Although normal use cases assume you will call this just once in your application's
+ /// lifetime (and call Shutdown once you're done), for the sake of easier testing it's
+ /// allowed to initialize the environment again after it has been successfully shutdown.
/// </summary>
- public static void EnsureInitialized() {
+ public static void Initialize() {
lock(staticLock)
{
- if (!initCalled)
+ if (instance == null)
{
- initCalled = true;
- GrpcInit();
+ instance = new GrpcEnvironment();
}
}
}
@@ -47,45 +81,55 @@ namespace Google.GRPC.Core
{
lock(staticLock)
{
- if (initCalled && !shutdownCalled)
+ if (instance != null)
{
- shutdownCalled = true;
- GrpcShutdown();
+ instance.Close();
+ instance = null;
}
}
+ }
+ internal static GrpcThreadPool ThreadPool
+ {
+ get
+ {
+ var inst = instance;
+ if (inst == null)
+ {
+ throw new InvalidOperationException("GRPC environment not initialized");
+ }
+ return inst.threadPool;
+ }
}
/// <summary>
- /// Initializes GRPC C Core library.
+ /// Creates gRPC environment.
/// </summary>
- private static void GrpcInit()
+ private GrpcEnvironment()
{
- grpc_init();
+ grpcsharp_init();
+ threadPool = new GrpcThreadPool(THREAD_POOL_SIZE);
threadPool.Start();
// TODO: use proper logging here
Console.WriteLine("GRPC initialized.");
}
/// <summary>
- /// Shutdown GRPC C Core library.
+ /// Shuts down this environment.
/// </summary>
- private static void GrpcShutdown()
+ private void Close()
{
+ if (isClosed)
+ {
+ throw new InvalidOperationException("Close has already been called");
+ }
threadPool.Stop();
- grpc_shutdown();
+ grpcsharp_shutdown();
+ isClosed = true;
// TODO: use proper logging here
Console.WriteLine("GRPC shutdown.");
}
-
- internal static GrpcThreadPool ThreadPool
- {
- get
- {
- return threadPool;
- }
- }
}
}
diff --git a/src/csharp/GrpcCore/Internal/AsyncCall.cs b/src/csharp/GrpcCore/Internal/AsyncCall.cs
index c38363bb2b..a3b40e512c 100644
--- a/src/csharp/GrpcCore/Internal/AsyncCall.cs
+++ b/src/csharp/GrpcCore/Internal/AsyncCall.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
diff --git a/src/csharp/GrpcCore/Internal/CallSafeHandle.cs b/src/csharp/GrpcCore/Internal/CallSafeHandle.cs
index bbb830b355..d91d2ac6cb 100644
--- a/src/csharp/GrpcCore/Internal/CallSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/CallSafeHandle.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
@@ -15,67 +48,67 @@ namespace Google.GRPC.Core.Internal
{
const UInt32 GRPC_WRITE_BUFFER_HINT = 1;
- [DllImport("grpc.dll")]
- static extern CallSafeHandle grpc_channel_create_call_old(ChannelSafeHandle channel, string method, string host, Timespec deadline);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern CallSafeHandle grpcsharp_channel_create_call_old(ChannelSafeHandle channel, string method, string host, Timespec deadline);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_add_metadata(CallSafeHandle call, IntPtr metadata, UInt32 flags);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_add_metadata(CallSafeHandle call, IntPtr metadata, UInt32 flags);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_invoke_old(CallSafeHandle call, CompletionQueueSafeHandle cq, IntPtr metadataReadTag, IntPtr finishedTag, UInt32 flags);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_invoke_old(CallSafeHandle call, CompletionQueueSafeHandle cq, IntPtr metadataReadTag, IntPtr finishedTag, UInt32 flags);
- [DllImport("grpc.dll", EntryPoint = "grpc_call_invoke_old")]
- static extern GRPCCallError grpc_call_invoke_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle cq,
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_call_invoke_old")]
+ static extern GRPCCallError grpcsharp_call_invoke_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle cq,
[MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate metadataReadCallback,
[MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate finishedCallback,
UInt32 flags);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_server_accept_old(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, IntPtr finishedTag);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_server_accept_old(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, IntPtr finishedTag);
- [DllImport("grpc.dll", EntryPoint = "grpc_call_server_accept_old")]
- static extern GRPCCallError grpc_call_server_accept_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate finishedCallback);
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_call_server_accept_old")]
+ static extern GRPCCallError grpcsharp_call_server_accept_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate finishedCallback);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_server_end_initial_metadata_old(CallSafeHandle call, UInt32 flags);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_server_end_initial_metadata_old(CallSafeHandle call, UInt32 flags);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_cancel(CallSafeHandle call);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_start_write_status_old(CallSafeHandle call, StatusCode statusCode, string statusMessage, IntPtr tag);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_start_write_status_old(CallSafeHandle call, StatusCode statusCode, string statusMessage, IntPtr tag);
- [DllImport("grpc.dll", EntryPoint = "grpc_call_start_write_status_old")]
- static extern GRPCCallError grpc_call_start_write_status_old_CALLBACK(CallSafeHandle call, StatusCode statusCode, string statusMessage, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_call_start_write_status_old")]
+ static extern GRPCCallError grpcsharp_call_start_write_status_old_CALLBACK(CallSafeHandle call, StatusCode statusCode, string statusMessage, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_writes_done_old(CallSafeHandle call, IntPtr tag);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_writes_done_old(CallSafeHandle call, IntPtr tag);
- [DllImport("grpc.dll", EntryPoint = "grpc_call_writes_done_old")]
- static extern GRPCCallError grpc_call_writes_done_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_call_writes_done_old")]
+ static extern GRPCCallError grpcsharp_call_writes_done_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("grpc.dll")]
- static extern GRPCCallError grpc_call_start_read_old(CallSafeHandle call, IntPtr tag);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_start_read_old(CallSafeHandle call, IntPtr tag);
- [DllImport("grpc.dll", EntryPoint = "grpc_call_start_read_old")]
- static extern GRPCCallError grpc_call_start_read_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_call_start_read_old")]
+ static extern GRPCCallError grpcsharp_call_start_read_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
[DllImport("grpc_csharp_ext.dll")]
- static extern void grpc_call_start_write_from_copied_buffer(CallSafeHandle call,
+ static extern void grpcsharp_call_start_write_from_copied_buffer(CallSafeHandle call,
byte[] buffer, UIntPtr length,
IntPtr tag, UInt32 flags);
- [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpc_call_start_write_from_copied_buffer")]
- static extern void grpc_call_start_write_from_copied_buffer_CALLBACK(CallSafeHandle call,
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_call_start_write_from_copied_buffer")]
+ static extern void grpcsharp_call_start_write_from_copied_buffer_CALLBACK(CallSafeHandle call,
byte[] buffer, UIntPtr length,
[MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback,
UInt32 flags);
- [DllImport("grpc.dll")]
- static extern void grpc_call_destroy(IntPtr call);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_call_destroy(IntPtr call);
private CallSafeHandle()
{
@@ -86,87 +119,87 @@ namespace Google.GRPC.Core.Internal
/// </summary>
public static CallSafeHandle Create(ChannelSafeHandle channel, string method, string host, Timespec deadline)
{
- return grpc_channel_create_call_old(channel, method, host, deadline);
+ return grpcsharp_channel_create_call_old(channel, method, host, deadline);
}
public void Invoke(CompletionQueueSafeHandle cq, IntPtr metadataReadTag, IntPtr finishedTag, bool buffered)
{
- AssertCallOk(grpc_call_invoke_old(this, cq, metadataReadTag, finishedTag, GetFlags(buffered)));
+ AssertCallOk(grpcsharp_call_invoke_old(this, cq, metadataReadTag, finishedTag, GetFlags(buffered)));
}
public void Invoke(CompletionQueueSafeHandle cq, bool buffered, EventCallbackDelegate metadataReadCallback, EventCallbackDelegate finishedCallback)
{
- AssertCallOk(grpc_call_invoke_old_CALLBACK(this, cq, metadataReadCallback, finishedCallback, GetFlags(buffered)));
+ AssertCallOk(grpcsharp_call_invoke_old_CALLBACK(this, cq, metadataReadCallback, finishedCallback, GetFlags(buffered)));
}
public void ServerAccept(CompletionQueueSafeHandle cq, IntPtr finishedTag)
{
- AssertCallOk(grpc_call_server_accept_old(this, cq, finishedTag));
+ AssertCallOk(grpcsharp_call_server_accept_old(this, cq, finishedTag));
}
public void ServerAccept(CompletionQueueSafeHandle cq, EventCallbackDelegate callback)
{
- AssertCallOk(grpc_call_server_accept_old_CALLBACK(this, cq, callback));
+ AssertCallOk(grpcsharp_call_server_accept_old_CALLBACK(this, cq, callback));
}
public void ServerEndInitialMetadata(UInt32 flags)
{
- AssertCallOk(grpc_call_server_end_initial_metadata_old(this, flags));
+ AssertCallOk(grpcsharp_call_server_end_initial_metadata_old(this, flags));
}
public void StartWrite(byte[] payload, IntPtr tag, bool buffered)
{
- grpc_call_start_write_from_copied_buffer(this, payload, new UIntPtr((ulong) payload.Length), tag, GetFlags(buffered));
+ grpcsharp_call_start_write_from_copied_buffer(this, payload, new UIntPtr((ulong) payload.Length), tag, GetFlags(buffered));
}
public void StartWrite(byte[] payload, bool buffered, EventCallbackDelegate callback)
{
- grpc_call_start_write_from_copied_buffer_CALLBACK(this, payload, new UIntPtr((ulong) payload.Length), callback, GetFlags(buffered));
+ grpcsharp_call_start_write_from_copied_buffer_CALLBACK(this, payload, new UIntPtr((ulong) payload.Length), callback, GetFlags(buffered));
}
public void StartWriteStatus(Status status, IntPtr tag)
{
- AssertCallOk(grpc_call_start_write_status_old(this, status.StatusCode, status.Detail, tag));
+ AssertCallOk(grpcsharp_call_start_write_status_old(this, status.StatusCode, status.Detail, tag));
}
public void StartWriteStatus(Status status, EventCallbackDelegate callback)
{
- AssertCallOk(grpc_call_start_write_status_old_CALLBACK(this, status.StatusCode, status.Detail, callback));
+ AssertCallOk(grpcsharp_call_start_write_status_old_CALLBACK(this, status.StatusCode, status.Detail, callback));
}
public void WritesDone(IntPtr tag)
{
- AssertCallOk(grpc_call_writes_done_old(this, tag));
+ AssertCallOk(grpcsharp_call_writes_done_old(this, tag));
}
public void WritesDone(EventCallbackDelegate callback)
{
- AssertCallOk(grpc_call_writes_done_old_CALLBACK(this, callback));
+ AssertCallOk(grpcsharp_call_writes_done_old_CALLBACK(this, callback));
}
public void StartRead(IntPtr tag)
{
- AssertCallOk(grpc_call_start_read_old(this, tag));
+ AssertCallOk(grpcsharp_call_start_read_old(this, tag));
}
public void StartRead(EventCallbackDelegate callback)
{
- AssertCallOk(grpc_call_start_read_old_CALLBACK(this, callback));
+ AssertCallOk(grpcsharp_call_start_read_old_CALLBACK(this, callback));
}
public void Cancel()
{
- AssertCallOk(grpc_call_cancel(this));
+ AssertCallOk(grpcsharp_call_cancel(this));
}
public void CancelWithStatus(Status status)
{
- AssertCallOk(grpc_call_cancel_with_status(this, status.StatusCode, status.Detail));
+ AssertCallOk(grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail));
}
protected override bool ReleaseHandle()
{
- grpc_call_destroy(handle);
+ grpcsharp_call_destroy(handle);
return true;
}
diff --git a/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs b/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs
index 0f38d63f98..f6af64c967 100644
--- a/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Threading;
@@ -10,11 +43,11 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class ChannelSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("grpc.dll")]
- static extern ChannelSafeHandle grpc_channel_create(string target, IntPtr channelArgs);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern ChannelSafeHandle grpcsharp_channel_create(string target, IntPtr channelArgs);
- [DllImport("grpc.dll")]
- static extern void grpc_channel_destroy(IntPtr channel);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_channel_destroy(IntPtr channel);
private ChannelSafeHandle()
{
@@ -22,12 +55,12 @@ namespace Google.GRPC.Core.Internal
public static ChannelSafeHandle Create(string target, IntPtr channelArgs)
{
- return grpc_channel_create(target, channelArgs);
+ return grpcsharp_channel_create(target, channelArgs);
}
protected override bool ReleaseHandle()
{
- grpc_channel_destroy(handle);
+ grpcsharp_channel_destroy(handle);
return true;
}
}
diff --git a/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs b/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs
index f098de6820..fc2b1d5421 100644
--- a/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -9,23 +42,23 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class CompletionQueueSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("grpc.dll")]
- static extern CompletionQueueSafeHandle grpc_completion_queue_create();
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create();
- [DllImport("grpc.dll")]
- static extern EventSafeHandle grpc_completion_queue_pluck(CompletionQueueSafeHandle cq, IntPtr tag, Timespec deadline);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern EventSafeHandle grpcsharp_completion_queue_pluck(CompletionQueueSafeHandle cq, IntPtr tag, Timespec deadline);
- [DllImport("grpc.dll")]
- static extern EventSafeHandle grpc_completion_queue_next(CompletionQueueSafeHandle cq, Timespec deadline);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern EventSafeHandle grpcsharp_completion_queue_next(CompletionQueueSafeHandle cq, Timespec deadline);
- [DllImport("grpc.dll")]
- static extern void grpc_completion_queue_shutdown(CompletionQueueSafeHandle cq);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_completion_queue_shutdown(CompletionQueueSafeHandle cq);
[DllImport("grpc_csharp_ext.dll")]
- static extern GRPCCompletionType grpc_completion_queue_next_with_callback(CompletionQueueSafeHandle cq);
+ static extern GRPCCompletionType grpcsharp_completion_queue_next_with_callback(CompletionQueueSafeHandle cq);
- [DllImport("grpc.dll")]
- static extern void grpc_completion_queue_destroy(IntPtr cq);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_completion_queue_destroy(IntPtr cq);
private CompletionQueueSafeHandle()
{
@@ -33,32 +66,32 @@ namespace Google.GRPC.Core.Internal
public static CompletionQueueSafeHandle Create()
{
- return grpc_completion_queue_create();
+ return grpcsharp_completion_queue_create();
}
public EventSafeHandle Next(Timespec deadline)
{
- return grpc_completion_queue_next(this, deadline);
+ return grpcsharp_completion_queue_next(this, deadline);
}
public GRPCCompletionType NextWithCallback()
{
- return grpc_completion_queue_next_with_callback(this);
+ return grpcsharp_completion_queue_next_with_callback(this);
}
public EventSafeHandle Pluck(IntPtr tag, Timespec deadline)
{
- return grpc_completion_queue_pluck(this, tag, deadline);
+ return grpcsharp_completion_queue_pluck(this, tag, deadline);
}
public void Shutdown()
{
- grpc_completion_queue_shutdown(this);
+ grpcsharp_completion_queue_shutdown(this);
}
protected override bool ReleaseHandle()
{
- grpc_completion_queue_destroy(handle);
+ grpcsharp_completion_queue_destroy(handle);
return true;
}
}
diff --git a/src/csharp/GrpcCore/Internal/Enums.cs b/src/csharp/GrpcCore/Internal/Enums.cs
index 1151e94899..c2eb1327b3 100644
--- a/src/csharp/GrpcCore/Internal/Enums.cs
+++ b/src/csharp/GrpcCore/Internal/Enums.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
diff --git a/src/csharp/GrpcCore/Internal/Event.cs b/src/csharp/GrpcCore/Internal/Event.cs
index 5853ddd570..9229472ccd 100644
--- a/src/csharp/GrpcCore/Internal/Event.cs
+++ b/src/csharp/GrpcCore/Internal/Event.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using Google.GRPC.Core;
@@ -9,84 +42,84 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class EventSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("grpc.dll")]
- static extern void grpc_event_finish(IntPtr ev);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_event_finish(IntPtr ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern GRPCCompletionType grpc_event_type(EventSafeHandle ev);
+ static extern GRPCCompletionType grpcsharp_event_type(EventSafeHandle ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern CallSafeHandle grpc_event_call(EventSafeHandle ev);
+ static extern CallSafeHandle grpcsharp_event_call(EventSafeHandle ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern GRPCOpError grpc_event_write_accepted(EventSafeHandle ev);
+ static extern GRPCOpError grpcsharp_event_write_accepted(EventSafeHandle ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern GRPCOpError grpc_event_finish_accepted(EventSafeHandle ev);
+ static extern GRPCOpError grpcsharp_event_finish_accepted(EventSafeHandle ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern StatusCode grpc_event_finished_status(EventSafeHandle ev);
+ static extern StatusCode grpcsharp_event_finished_status(EventSafeHandle ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern IntPtr grpc_event_finished_details(EventSafeHandle ev); // returns const char*
+ static extern IntPtr grpcsharp_event_finished_details(EventSafeHandle ev); // returns const char*
[DllImport("grpc_csharp_ext.dll")]
- static extern IntPtr grpc_event_read_length(EventSafeHandle ev);
+ static extern IntPtr grpcsharp_event_read_length(EventSafeHandle ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern void grpc_event_read_copy_to_buffer(EventSafeHandle ev, byte[] buffer, UIntPtr bufferLen);
+ static extern void grpcsharp_event_read_copy_to_buffer(EventSafeHandle ev, byte[] buffer, UIntPtr bufferLen);
[DllImport("grpc_csharp_ext.dll")]
- static extern IntPtr grpc_event_server_rpc_new_method(EventSafeHandle ev); // returns const char*
+ static extern IntPtr grpcsharp_event_server_rpc_new_method(EventSafeHandle ev); // returns const char*
public GRPCCompletionType GetCompletionType()
{
- return grpc_event_type(this);
+ return grpcsharp_event_type(this);
}
public GRPCOpError GetWriteAccepted()
{
- return grpc_event_write_accepted(this);
+ return grpcsharp_event_write_accepted(this);
}
public GRPCOpError GetFinishAccepted()
{
- return grpc_event_finish_accepted(this);
+ return grpcsharp_event_finish_accepted(this);
}
public Status GetFinished()
{
// TODO: can the native method return string directly?
- string details = Marshal.PtrToStringAnsi(grpc_event_finished_details(this));
- return new Status(grpc_event_finished_status(this), details);
+ string details = Marshal.PtrToStringAnsi(grpcsharp_event_finished_details(this));
+ return new Status(grpcsharp_event_finished_status(this), details);
}
public byte[] GetReadData()
{
- IntPtr len = grpc_event_read_length(this);
+ IntPtr len = grpcsharp_event_read_length(this);
if (len == new IntPtr(-1))
{
return null;
}
byte[] data = new byte[(int) len];
- grpc_event_read_copy_to_buffer(this, data, new UIntPtr((ulong)data.Length));
+ grpcsharp_event_read_copy_to_buffer(this, data, new UIntPtr((ulong)data.Length));
return data;
}
public CallSafeHandle GetCall() {
- return grpc_event_call(this);
+ return grpcsharp_event_call(this);
}
public string GetServerRpcNewMethod() {
// TODO: can the native method return string directly?
- return Marshal.PtrToStringAnsi(grpc_event_server_rpc_new_method(this));
+ return Marshal.PtrToStringAnsi(grpcsharp_event_server_rpc_new_method(this));
}
//TODO: client_metadata_read event type
protected override bool ReleaseHandle()
{
- grpc_event_finish(handle);
+ grpcsharp_event_finish(handle);
return true;
}
}
@@ -98,35 +131,35 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class EventSafeHandleNotOwned : SafeHandleZeroIsInvalid
{
- [DllImport("grpc.dll")]
- static extern void grpc_event_finish(IntPtr ev);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_event_finish(IntPtr ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern GRPCCompletionType grpc_event_type(EventSafeHandleNotOwned ev);
+ static extern GRPCCompletionType grpcsharp_event_type(EventSafeHandleNotOwned ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern CallSafeHandle grpc_event_call(EventSafeHandleNotOwned ev);
+ static extern CallSafeHandle grpcsharp_event_call(EventSafeHandleNotOwned ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern GRPCOpError grpc_event_write_accepted(EventSafeHandleNotOwned ev);
+ static extern GRPCOpError grpcsharp_event_write_accepted(EventSafeHandleNotOwned ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern GRPCOpError grpc_event_finish_accepted(EventSafeHandleNotOwned ev);
+ static extern GRPCOpError grpcsharp_event_finish_accepted(EventSafeHandleNotOwned ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern StatusCode grpc_event_finished_status(EventSafeHandleNotOwned ev);
+ static extern StatusCode grpcsharp_event_finished_status(EventSafeHandleNotOwned ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern IntPtr grpc_event_finished_details(EventSafeHandleNotOwned ev); // returns const char*
+ static extern IntPtr grpcsharp_event_finished_details(EventSafeHandleNotOwned ev); // returns const char*
[DllImport("grpc_csharp_ext.dll")]
- static extern IntPtr grpc_event_read_length(EventSafeHandleNotOwned ev);
+ static extern IntPtr grpcsharp_event_read_length(EventSafeHandleNotOwned ev);
[DllImport("grpc_csharp_ext.dll")]
- static extern void grpc_event_read_copy_to_buffer(EventSafeHandleNotOwned ev, byte[] buffer, UIntPtr bufferLen);
+ static extern void grpcsharp_event_read_copy_to_buffer(EventSafeHandleNotOwned ev, byte[] buffer, UIntPtr bufferLen);
[DllImport("grpc_csharp_ext.dll")]
- static extern IntPtr grpc_event_server_rpc_new_method(EventSafeHandleNotOwned ev); // returns const char*
+ static extern IntPtr grpcsharp_event_server_rpc_new_method(EventSafeHandleNotOwned ev); // returns const char*
public EventSafeHandleNotOwned() : base(false)
{
@@ -139,52 +172,52 @@ namespace Google.GRPC.Core.Internal
public GRPCCompletionType GetCompletionType()
{
- return grpc_event_type(this);
+ return grpcsharp_event_type(this);
}
public GRPCOpError GetWriteAccepted()
{
- return grpc_event_write_accepted(this);
+ return grpcsharp_event_write_accepted(this);
}
public GRPCOpError GetFinishAccepted()
{
- return grpc_event_finish_accepted(this);
+ return grpcsharp_event_finish_accepted(this);
}
public Status GetFinished()
{
// TODO: can the native method return string directly?
- string details = Marshal.PtrToStringAnsi(grpc_event_finished_details(this));
- return new Status(grpc_event_finished_status(this), details);
+ string details = Marshal.PtrToStringAnsi(grpcsharp_event_finished_details(this));
+ return new Status(grpcsharp_event_finished_status(this), details);
}
public byte[] GetReadData()
{
- IntPtr len = grpc_event_read_length(this);
+ IntPtr len = grpcsharp_event_read_length(this);
if (len == new IntPtr(-1))
{
return null;
}
byte[] data = new byte[(int) len];
- grpc_event_read_copy_to_buffer(this, data, new UIntPtr((ulong)data.Length));
+ grpcsharp_event_read_copy_to_buffer(this, data, new UIntPtr((ulong)data.Length));
return data;
}
public CallSafeHandle GetCall() {
- return grpc_event_call(this);
+ return grpcsharp_event_call(this);
}
public string GetServerRpcNewMethod() {
// TODO: can the native method return string directly?
- return Marshal.PtrToStringAnsi(grpc_event_server_rpc_new_method(this));
+ return Marshal.PtrToStringAnsi(grpcsharp_event_server_rpc_new_method(this));
}
//TODO: client_metadata_read event type
protected override bool ReleaseHandle()
{
- grpc_event_finish(handle);
+ grpcsharp_event_finish(handle);
return true;
}
}
diff --git a/src/csharp/GrpcCore/Internal/GrpcThreadPool.cs b/src/csharp/GrpcCore/Internal/GrpcThreadPool.cs
index 1139e54a1d..b768decc8c 100644
--- a/src/csharp/GrpcCore/Internal/GrpcThreadPool.cs
+++ b/src/csharp/GrpcCore/Internal/GrpcThreadPool.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using Google.GRPC.Core.Internal;
using System.Runtime.InteropServices;
diff --git a/src/csharp/GrpcCore/Internal/SafeHandleZeroIsInvalid.cs b/src/csharp/GrpcCore/Internal/SafeHandleZeroIsInvalid.cs
index 5a1252b881..c7d8a0a3c3 100644
--- a/src/csharp/GrpcCore/Internal/SafeHandleZeroIsInvalid.cs
+++ b/src/csharp/GrpcCore/Internal/SafeHandleZeroIsInvalid.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
diff --git a/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs b/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
index d363b34f0b..2ae0ad237d 100644
--- a/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
@@ -10,31 +43,31 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("grpc.dll", EntryPoint = "grpc_server_request_call_old")]
- static extern GRPCCallError grpc_server_request_call_old_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_server_request_call_old")]
+ static extern GRPCCallError grpcsharp_server_request_call_old_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("grpc.dll")]
- static extern ServerSafeHandle grpc_server_create(CompletionQueueSafeHandle cq, IntPtr args);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, IntPtr args);
// TODO: check int representation size
- [DllImport("grpc.dll")]
- static extern int grpc_server_add_http2_port(ServerSafeHandle server, string addr);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
// TODO: check int representation size
- [DllImport("grpc.dll")]
- static extern int grpc_server_add_secure_http2_port(ServerSafeHandle server, string addr);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr);
- [DllImport("grpc.dll")]
- static extern void grpc_server_start(ServerSafeHandle server);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_server_start(ServerSafeHandle server);
- [DllImport("grpc.dll")]
- static extern void grpc_server_shutdown(ServerSafeHandle server);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_server_shutdown(ServerSafeHandle server);
- [DllImport("grpc.dll", EntryPoint = "grpc_server_shutdown_and_notify")]
- static extern void grpc_server_shutdown_and_notify_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_server_shutdown_and_notify")]
+ static extern void grpcsharp_server_shutdown_and_notify_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("grpc.dll")]
- static extern void grpc_server_destroy(IntPtr server);
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_server_destroy(IntPtr server);
private ServerSafeHandle()
{
@@ -43,38 +76,38 @@ namespace Google.GRPC.Core.Internal
public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, IntPtr args)
{
// TODO: also grpc_secure_server_create...
- return grpc_server_create(cq, args);
+ return grpcsharp_server_create(cq, args);
}
public int AddPort(string addr)
{
// TODO: also grpc_server_add_secure_http2_port...
- return grpc_server_add_http2_port(this, addr);
+ return grpcsharp_server_add_http2_port(this, addr);
}
public void Start()
{
- grpc_server_start(this);
+ grpcsharp_server_start(this);
}
public void Shutdown()
{
- grpc_server_shutdown(this);
+ grpcsharp_server_shutdown(this);
}
public void ShutdownAndNotify(EventCallbackDelegate callback)
{
- grpc_server_shutdown_and_notify_CALLBACK(this, callback);
+ grpcsharp_server_shutdown_and_notify_CALLBACK(this, callback);
}
public GRPCCallError RequestCall(EventCallbackDelegate callback)
{
- return grpc_server_request_call_old_CALLBACK(this, callback);
+ return grpcsharp_server_request_call_old_CALLBACK(this, callback);
}
protected override bool ReleaseHandle()
{
- grpc_server_destroy(handle);
+ grpcsharp_server_destroy(handle);
return true;
}
}
diff --git a/src/csharp/GrpcCore/Internal/ServerWritingObserver.cs b/src/csharp/GrpcCore/Internal/ServerWritingObserver.cs
index 2b46e9c53d..1120791842 100644
--- a/src/csharp/GrpcCore/Internal/ServerWritingObserver.cs
+++ b/src/csharp/GrpcCore/Internal/ServerWritingObserver.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using Google.GRPC.Core.Internal;
diff --git a/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs b/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs
index c5de979351..49410961cb 100644
--- a/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs
+++ b/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using Google.GRPC.Core.Internal;
diff --git a/src/csharp/GrpcCore/Internal/Timespec.cs b/src/csharp/GrpcCore/Internal/Timespec.cs
index 5a197e121c..651003dae8 100644
--- a/src/csharp/GrpcCore/Internal/Timespec.cs
+++ b/src/csharp/GrpcCore/Internal/Timespec.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Threading;
@@ -13,13 +46,20 @@ namespace Google.GRPC.Core.Internal
const int nanosPerSecond = 1000 * 1000 * 1000;
const int nanosPerTick = 100;
- [DllImport("gpr.dll")]
- static extern Timespec gpr_now();
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern Timespec gprsharp_now();
- // TODO: this only works on 64bit linux, can we autoselect the right size of ints?
- // perhaps using IntPtr would work.
- public System.Int64 tv_sec;
- public System.Int64 tv_nsec;
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern Timespec gprsharp_inf_future();
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern int gprsharp_sizeof_timespec();
+
+ // TODO: revisit this.
+ // NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
+ // so IntPtr seems to have the right size to work on both.
+ public System.IntPtr tv_sec;
+ public System.IntPtr tv_nsec;
/// <summary>
/// Timespec a long time in the future.
@@ -28,8 +68,7 @@ namespace Google.GRPC.Core.Internal
{
get
{
- // TODO: set correct value based on the length of the struct
- return new Timespec { tv_sec = Int32.MaxValue, tv_nsec = 0 };
+ return gprsharp_inf_future();
}
}
@@ -37,7 +76,15 @@ namespace Google.GRPC.Core.Internal
{
get
{
- return gpr_now();
+ return gprsharp_now();
+ }
+ }
+
+ internal static int NativeSize
+ {
+ get
+ {
+ return gprsharp_sizeof_timespec();
}
}
@@ -54,12 +101,12 @@ namespace Google.GRPC.Core.Internal
}
public Timespec Add(TimeSpan timeSpan) {
- long nanos = tv_nsec + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * nanosPerTick;
+ long nanos = tv_nsec.ToInt64() + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * nanosPerTick;
long overflow_sec = (nanos > nanosPerSecond) ? 1 : 0;
Timespec result;
- result.tv_nsec = nanos % nanosPerSecond;
- result.tv_sec = tv_sec + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec;
+ result.tv_nsec = new IntPtr(nanos % nanosPerSecond);
+ result.tv_sec = new IntPtr(tv_sec.ToInt64() + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec);
return result;
}
}
diff --git a/src/csharp/GrpcCore/Marshaller.cs b/src/csharp/GrpcCore/Marshaller.cs
index 242524063c..21bd26650b 100644
--- a/src/csharp/GrpcCore/Marshaller.cs
+++ b/src/csharp/GrpcCore/Marshaller.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
namespace Google.GRPC.Core
diff --git a/src/csharp/GrpcCore/Method.cs b/src/csharp/GrpcCore/Method.cs
index 9067ae8c94..a8c647035d 100644
--- a/src/csharp/GrpcCore/Method.cs
+++ b/src/csharp/GrpcCore/Method.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
namespace Google.GRPC.Core
diff --git a/src/csharp/GrpcCore/RpcException.cs b/src/csharp/GrpcCore/RpcException.cs
index 8811c3a7c7..5d1ca3bcdf 100644
--- a/src/csharp/GrpcCore/RpcException.cs
+++ b/src/csharp/GrpcCore/RpcException.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
namespace Google.GRPC.Core
diff --git a/src/csharp/GrpcCore/Server.cs b/src/csharp/GrpcCore/Server.cs
index d3bc81e574..62ffa70b71 100644
--- a/src/csharp/GrpcCore/Server.cs
+++ b/src/csharp/GrpcCore/Server.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
@@ -26,10 +59,6 @@ namespace Google.GRPC.Core
readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
- static Server() {
- GrpcEnvironment.EnsureInitialized();
- }
-
public Server()
{
// TODO: what is the tag for server shutdown?
diff --git a/src/csharp/GrpcCore/ServerCallHandler.cs b/src/csharp/GrpcCore/ServerCallHandler.cs
index 67103791b4..12d0c93634 100644
--- a/src/csharp/GrpcCore/ServerCallHandler.cs
+++ b/src/csharp/GrpcCore/ServerCallHandler.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using Google.GRPC.Core.Internal;
diff --git a/src/csharp/GrpcCore/ServerCalls.cs b/src/csharp/GrpcCore/ServerCalls.cs
index 86c4718932..b95a0d97b4 100644
--- a/src/csharp/GrpcCore/ServerCalls.cs
+++ b/src/csharp/GrpcCore/ServerCalls.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
namespace Google.GRPC.Core
diff --git a/src/csharp/GrpcCore/ServerServiceDefinition.cs b/src/csharp/GrpcCore/ServerServiceDefinition.cs
index 7f1cc6284e..f0b4daf071 100644
--- a/src/csharp/GrpcCore/ServerServiceDefinition.cs
+++ b/src/csharp/GrpcCore/ServerServiceDefinition.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Collections.Generic;
diff --git a/src/csharp/GrpcCore/Status.cs b/src/csharp/GrpcCore/Status.cs
index f1212f8d67..dce1e24d7e 100644
--- a/src/csharp/GrpcCore/Status.cs
+++ b/src/csharp/GrpcCore/Status.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
diff --git a/src/csharp/GrpcCore/StatusCode.cs b/src/csharp/GrpcCore/StatusCode.cs
index 80fc8bd581..eccaae72f6 100644
--- a/src/csharp/GrpcCore/StatusCode.cs
+++ b/src/csharp/GrpcCore/StatusCode.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
namespace Google.GRPC.Core
diff --git a/src/csharp/GrpcCore/Utils/PortPicker.cs b/src/csharp/GrpcCore/Utils/PortPicker.cs
deleted file mode 100644
index 7c83bf3886..0000000000
--- a/src/csharp/GrpcCore/Utils/PortPicker.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-using System.Net;
-using System.Net.Sockets;
-
-namespace Google.GRPC.Core.Utils
-{
- public class PortPicker
- {
- static Random random = new Random();
-
- // TODO: cleanup this code a bit
- public static int PickUnusedPort()
- {
- int port;
- do
- {
- port = random.Next(2000, 50000);
-
- } while(!IsPortAvailable(port));
- return port;
- }
-
- // TODO: cleanup this code a bit
- public static bool IsPortAvailable(int port)
- {
- bool available = true;
-
- TcpListener server = null;
- try
- {
- IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
- server = new TcpListener(ipAddress, port);
- server.Start();
- }
- catch (Exception ex)
- {
- available = false;
- }
- finally
- {
- if (server != null)
- {
- server.Stop();
- }
- }
- return available;
- }
- }
-}
-
diff --git a/src/csharp/GrpcCore/Utils/RecordingObserver.cs b/src/csharp/GrpcCore/Utils/RecordingObserver.cs
index ca11cc4aa2..0cadfc0e4a 100644
--- a/src/csharp/GrpcCore/Utils/RecordingObserver.cs
+++ b/src/csharp/GrpcCore/Utils/RecordingObserver.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
diff --git a/src/csharp/GrpcCore/Utils/RecordingQueue.cs b/src/csharp/GrpcCore/Utils/RecordingQueue.cs
index 0726f00af7..d73fc0fc78 100644
--- a/src/csharp/GrpcCore/Utils/RecordingQueue.cs
+++ b/src/csharp/GrpcCore/Utils/RecordingQueue.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
@@ -5,6 +38,7 @@ using System.Collections.Concurrent;
namespace Google.GRPC.Core.Utils
{
+ // TODO: replace this by something that implements IAsyncEnumerator.
/// <summary>
/// Observer that allows us to await incoming messages one-by-one.
/// The implementation is not ideal and class will be probably replaced
diff --git a/src/csharp/GrpcCoreTests/ClientServerTest.cs b/src/csharp/GrpcCoreTests/ClientServerTest.cs
index c700ffbe7b..1472db6e07 100644
--- a/src/csharp/GrpcCoreTests/ClientServerTest.cs
+++ b/src/csharp/GrpcCoreTests/ClientServerTest.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using NUnit.Framework;
using Google.GRPC.Core;
@@ -10,7 +43,7 @@ namespace Google.GRPC.Core.Tests
{
public class ClientServerTest
{
- string serverAddr = "localhost:" + PortPicker.PickUnusedPort();
+ string host = "localhost";
Method<string, string> unaryEchoStringMethod = new Method<string, string>(
MethodType.Unary,
@@ -21,15 +54,17 @@ namespace Google.GRPC.Core.Tests
[Test]
public void EmptyCall()
{
+ GrpcEnvironment.Initialize();
+
Server server = new Server();
server.AddServiceDefinition(
ServerServiceDefinition.CreateBuilder("someService")
.AddMethod(unaryEchoStringMethod, HandleUnaryEchoString).Build());
- server.AddPort(serverAddr);
+ int port = server.AddPort(host + ":0");
server.Start();
- using (Channel channel = new Channel(serverAddr))
+ using (Channel channel = new Channel(host + ":" + port))
{
var call = new Call<string, string>(unaryEchoStringMethod, channel);
diff --git a/src/csharp/GrpcCoreTests/GrpcEnvironmentTest.cs b/src/csharp/GrpcCoreTests/GrpcEnvironmentTest.cs
index 136878d76e..1bc6cce401 100644
--- a/src/csharp/GrpcCoreTests/GrpcEnvironmentTest.cs
+++ b/src/csharp/GrpcCoreTests/GrpcEnvironmentTest.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using NUnit.Framework;
using Google.GRPC.Core;
@@ -9,10 +42,30 @@ namespace Google.GRPC.Core.Tests
{
[Test]
public void InitializeAndShutdownGrpcEnvironment() {
- GrpcEnvironment.EnsureInitialized();
- Thread.Sleep(500);
+ GrpcEnvironment.Initialize();
Assert.IsNotNull(GrpcEnvironment.ThreadPool.CompletionQueue);
GrpcEnvironment.Shutdown();
}
+
+ [Test]
+ public void SubsequentInvocations() {
+ GrpcEnvironment.Initialize();
+ GrpcEnvironment.Initialize();
+ GrpcEnvironment.Shutdown();
+ GrpcEnvironment.Shutdown();
+ }
+
+ [Test]
+ public void InitializeAfterShutdown() {
+ GrpcEnvironment.Initialize();
+ var tp1 = GrpcEnvironment.ThreadPool;
+ GrpcEnvironment.Shutdown();
+
+ GrpcEnvironment.Initialize();
+ var tp2 = GrpcEnvironment.ThreadPool;
+ GrpcEnvironment.Shutdown();
+
+ Assert.IsFalse(Object.ReferenceEquals(tp1, tp2));
+ }
}
}
diff --git a/src/csharp/GrpcCoreTests/ServerTest.cs b/src/csharp/GrpcCoreTests/ServerTest.cs
index 6e13bc735f..1c70a3d6c4 100644
--- a/src/csharp/GrpcCoreTests/ServerTest.cs
+++ b/src/csharp/GrpcCoreTests/ServerTest.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using NUnit.Framework;
using Google.GRPC.Core.Internal;
@@ -9,10 +42,12 @@ namespace Google.GRPC.Core.Tests
public class ServerTest
{
[Test]
- public void StartAndShutdownServer() {
+ public void StartAndShutdownServer()
+ {
+ GrpcEnvironment.Initialize();
Server server = new Server();
- server.AddPort("localhost:" + PortPicker.PickUnusedPort());
+ int port = server.AddPort("localhost:0");
server.Start();
server.ShutdownAsync().Wait();
diff --git a/src/csharp/GrpcCoreTests/TimespecTest.cs b/src/csharp/GrpcCoreTests/TimespecTest.cs
index 484bad7ca1..2b03513cb7 100644
--- a/src/csharp/GrpcCoreTests/TimespecTest.cs
+++ b/src/csharp/GrpcCoreTests/TimespecTest.cs
@@ -1,5 +1,39 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using NUnit.Framework;
+using System.Runtime.InteropServices;
using Google.GRPC.Core.Internal;
namespace Google.GRPC.Core.Internal.Tests
@@ -13,30 +47,42 @@ namespace Google.GRPC.Core.Internal.Tests
}
[Test]
+ public void InfFuture()
+ {
+ var timespec = Timespec.InfFuture;
+ }
+
+ [Test]
+ public void TimespecSizeIsNativeSize()
+ {
+ Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec)));
+ }
+
+ [Test]
public void Add()
{
- var t = new Timespec { tv_sec = 12345, tv_nsec = 123456789 };
+ var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = new IntPtr(123456789) };
var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10));
- Assert.AreEqual(result.tv_sec, 12355);
- Assert.AreEqual(result.tv_nsec, 123456789);
+ Assert.AreEqual(result.tv_sec, new IntPtr(12355));
+ Assert.AreEqual(result.tv_nsec, new IntPtr(123456789));
}
[Test]
public void Add_Nanos()
{
- var t = new Timespec { tv_sec = 12345, tv_nsec = 123456789 };
+ var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = new IntPtr(123456789) };
var result = t.Add(TimeSpan.FromTicks(10));
- Assert.AreEqual(result.tv_sec, 12345);
- Assert.AreEqual(result.tv_nsec, 123456789 + 1000);
+ Assert.AreEqual(result.tv_sec, new IntPtr(12345));
+ Assert.AreEqual(result.tv_nsec, new IntPtr(123456789 + 1000));
}
[Test]
public void Add_NanosOverflow()
{
- var t = new Timespec { tv_sec = 12345, tv_nsec = 999999999 };
+ var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = new IntPtr(999999999) };
var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10 + 10));
- Assert.AreEqual(result.tv_sec, 12356);
- Assert.AreEqual(result.tv_nsec, 999);
+ Assert.AreEqual(result.tv_sec, new IntPtr(12356));
+ Assert.AreEqual(result.tv_nsec, new IntPtr(999));
}
}
}
diff --git a/src/csharp/InteropClient/Client.cs b/src/csharp/InteropClient/Client.cs
index 9f5815050e..fcc6a572e4 100644
--- a/src/csharp/InteropClient/Client.cs
+++ b/src/csharp/InteropClient/Client.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Collections.Generic;
using NUnit.Framework;
@@ -60,6 +93,8 @@ namespace Google.GRPC.Interop
private void Run()
{
+ GrpcEnvironment.Initialize();
+
string addr = string.Format("{0}:{1}", options.serverHost, options.serverPort);
using (Channel channel = new Channel(addr))
{
diff --git a/src/csharp/MathClient/MathClient.cs b/src/csharp/MathClient/MathClient.cs
index 45222abb79..a54c8e3809 100644
--- a/src/csharp/MathClient/MathClient.cs
+++ b/src/csharp/MathClient/MathClient.cs
@@ -1,3 +1,36 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
using System;
using System.Runtime.InteropServices;
using Google.GRPC.Core;
@@ -9,6 +42,8 @@ namespace math
{
public static void Main (string[] args)
{
+ GrpcEnvironment.Initialize();
+
using (Channel channel = new Channel("127.0.0.1:23456"))
{
MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 74d11c655b..c7949af44e 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -1,9 +1,56 @@
+/*
+ *
+ * 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>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <string.h>
+#ifdef GPR_WIN32
+#define GPR_EXPORT __declspec(dllexport)
+#define GPR_CALLTYPE __stdcall
+#endif
+
+#ifndef GPR_EXPORT
+#define GPR_EXPORT
+#endif
+
+#ifndef GPR_CALLTYPE
+#define GPR_CALLTYPE
+#endif
+
grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
gpr_slice slice = gpr_slice_from_copied_buffer(buffer, len);
grpc_byte_buffer *bb = grpc_byte_buffer_create(&slice, 1);
@@ -11,40 +58,119 @@ grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
return bb;
}
-void grpc_call_start_write_from_copied_buffer(grpc_call *call,
- const char *buffer, size_t len,
- void *tag, gpr_uint32 flags) {
- grpc_byte_buffer *byte_buffer = string_to_byte_buffer(buffer, len);
- GPR_ASSERT(grpc_call_start_write_old(call, byte_buffer, tag, flags) ==
- GRPC_CALL_OK);
- grpc_byte_buffer_destroy(byte_buffer);
+/* Init & shutdown */
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_init(void) { grpc_init(); }
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_shutdown(void) { grpc_shutdown(); }
+
+/* Completion queue */
+
+GPR_EXPORT grpc_completion_queue *GPR_CALLTYPE
+grpcsharp_completion_queue_create(void) {
+ return grpc_completion_queue_create();
+}
+
+GPR_EXPORT grpc_event *GPR_CALLTYPE
+grpcsharp_completion_queue_next(grpc_completion_queue *cq,
+ gpr_timespec deadline) {
+ return grpc_completion_queue_next(cq, deadline);
+}
+
+GPR_EXPORT grpc_event *GPR_CALLTYPE
+grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
+ gpr_timespec deadline) {
+ return grpc_completion_queue_pluck(cq, tag, deadline);
+}
+
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_completion_queue_shutdown(grpc_completion_queue *cq) {
+ grpc_completion_queue_shutdown(cq);
+}
+
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_completion_queue_destroy(grpc_completion_queue *cq) {
+ grpc_completion_queue_destroy(cq);
+}
+
+GPR_EXPORT grpc_completion_type GPR_CALLTYPE
+grpcsharp_completion_queue_next_with_callback(grpc_completion_queue *cq) {
+ grpc_event *ev;
+ grpc_completion_type t;
+ void(GPR_CALLTYPE * callback)(grpc_event *);
+
+ ev = grpc_completion_queue_next(cq, gpr_inf_future);
+ t = ev->type;
+ if (ev->tag) {
+ /* call the callback in ev->tag */
+ /* C forbids to cast object pointers to function pointers, so
+ * we cast to intptr first.
+ */
+ callback = (void(GPR_CALLTYPE *)(grpc_event *))(gpr_intptr)ev->tag;
+ (*callback)(ev);
+ }
+ grpc_event_finish(ev);
+
+ /* return completion type to allow some handling for events that have no
+ * tag - such as GRPC_QUEUE_SHUTDOWN
+ */
+ return t;
+}
+
+/* Channel */
+
+GPR_EXPORT grpc_channel *GPR_CALLTYPE
+grpcsharp_channel_create(const char *target, const grpc_channel_args *args) {
+ return grpc_channel_create(target, args);
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) {
+ grpc_channel_destroy(channel);
}
-grpc_completion_type grpc_event_type(const grpc_event *event) {
+GPR_EXPORT grpc_call *GPR_CALLTYPE
+grpcsharp_channel_create_call_old(grpc_channel *channel, const char *method,
+ const char *host, gpr_timespec deadline) {
+ return grpc_channel_create_call_old(channel, method, host, deadline);
+}
+
+/* Event */
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_event_finish(grpc_event *event) {
+ grpc_event_finish(event);
+}
+
+GPR_EXPORT grpc_completion_type GPR_CALLTYPE
+grpcsharp_event_type(const grpc_event *event) {
return event->type;
}
-grpc_op_error grpc_event_write_accepted(const grpc_event *event) {
+GPR_EXPORT grpc_op_error GPR_CALLTYPE
+grpcsharp_event_write_accepted(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_WRITE_ACCEPTED);
return event->data.invoke_accepted;
}
-grpc_op_error grpc_event_finish_accepted(const grpc_event *event) {
+GPR_EXPORT grpc_op_error GPR_CALLTYPE
+grpcsharp_event_finish_accepted(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_FINISH_ACCEPTED);
return event->data.finish_accepted;
}
-grpc_status_code grpc_event_finished_status(const grpc_event *event) {
+GPR_EXPORT grpc_status_code GPR_CALLTYPE
+grpcsharp_event_finished_status(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_FINISHED);
return event->data.finished.status;
}
-const char *grpc_event_finished_details(const grpc_event *event) {
+GPR_EXPORT const char *GPR_CALLTYPE
+grpcsharp_event_finished_details(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_FINISHED);
return event->data.finished.details;
}
-gpr_intptr grpc_event_read_length(const grpc_event *event) {
+GPR_EXPORT gpr_intptr GPR_CALLTYPE
+grpcsharp_event_read_length(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_READ);
if (!event->data.read) {
return -1;
@@ -56,7 +182,8 @@ gpr_intptr grpc_event_read_length(const grpc_event *event) {
* Copies data from read event to a buffer. Fatal error occurs if
* buffer is too small.
*/
-void grpc_event_read_copy_to_buffer(const grpc_event *event, char *buffer,
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_event_read_copy_to_buffer(const grpc_event *event, char *buffer,
size_t buffer_len) {
grpc_byte_buffer_reader *reader;
gpr_slice slice;
@@ -77,37 +204,142 @@ void grpc_event_read_copy_to_buffer(const grpc_event *event, char *buffer,
grpc_byte_buffer_reader_destroy(reader);
}
-grpc_call *grpc_event_call(const grpc_event *event) {
+GPR_EXPORT grpc_call *GPR_CALLTYPE
+grpcsharp_event_call(const grpc_event *event) {
/* we only allow this for newly incoming server calls. */
GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW);
return event->call;
}
-const char *grpc_event_server_rpc_new_method(const grpc_event *event) {
+GPR_EXPORT const char *GPR_CALLTYPE
+grpcsharp_event_server_rpc_new_method(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW);
return event->data.server_rpc_new.method;
}
-grpc_completion_type grpc_completion_queue_next_with_callback(
- grpc_completion_queue *cq) {
- grpc_event *ev;
- grpc_completion_type t;
- void (*callback)(grpc_event *);
+/* Timespec */
- ev = grpc_completion_queue_next(cq, gpr_inf_future);
- t = ev->type;
- if (ev->tag) {
- /* call the callback in ev->tag */
- /* C forbids to cast object pointers to function pointers, so
- * we cast to intptr first.
- */
- callback = (void (*)(grpc_event *))(gpr_intptr)ev->tag;
- (*callback)(ev);
- }
- grpc_event_finish(ev);
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(void) { return gpr_now(); }
- /* return completion type to allow some handling for events that have no
- * tag - such as GRPC_QUEUE_SHUTDOWN
- */
- return t;
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(void) {
+ return gpr_inf_future;
+}
+
+GPR_EXPORT gpr_int32 GPR_CALLTYPE gprsharp_sizeof_timespec(void) {
+ return sizeof(gpr_timespec);
+}
+
+/* Call */
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_add_metadata_old(grpc_call *call, grpc_metadata *metadata,
+ gpr_uint32 flags) {
+ return grpc_call_add_metadata_old(call, metadata, flags);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_invoke_old(grpc_call *call, grpc_completion_queue *cq,
+ void *metadata_read_tag, void *finished_tag,
+ gpr_uint32 flags) {
+ return grpc_call_invoke_old(call, cq, metadata_read_tag, finished_tag, flags);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_server_accept_old(grpc_call *call, grpc_completion_queue *cq,
+ void *finished_tag) {
+ return grpc_call_server_accept_old(call, cq, finished_tag);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_server_end_initial_metadata_old(grpc_call *call,
+ gpr_uint32 flags) {
+ return grpc_call_server_end_initial_metadata_old(call, flags);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel(grpc_call *call) {
+ return grpc_call_cancel(call);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_cancel_with_status(grpc_call *call, grpc_status_code status,
+ const char *description) {
+ return grpc_call_cancel_with_status(call, status, description);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_start_write_old(grpc_call *call, grpc_byte_buffer *byte_buffer,
+ void *tag, gpr_uint32 flags) {
+ return grpc_call_start_write_old(call, byte_buffer, tag, flags);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_start_write_status_old(grpc_call *call,
+ grpc_status_code status_code,
+ const char *status_message, void *tag) {
+ return grpc_call_start_write_status_old(call, status_code, status_message,
+ tag);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_writes_done_old(grpc_call *call, void *tag) {
+ return grpc_call_writes_done_old(call, tag);
+}
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_call_start_read_old(grpc_call *call, void *tag) {
+ return grpc_call_start_read_old(call, tag);
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) {
+ grpc_call_destroy(call);
+}
+
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_call_start_write_from_copied_buffer(grpc_call *call,
+ const char *buffer, size_t len,
+ void *tag, gpr_uint32 flags) {
+ grpc_byte_buffer *byte_buffer = string_to_byte_buffer(buffer, len);
+ GPR_ASSERT(grpc_call_start_write_old(call, byte_buffer, tag, flags) ==
+ GRPC_CALL_OK);
+ grpc_byte_buffer_destroy(byte_buffer);
+}
+
+/* Server */
+
+GPR_EXPORT grpc_call_error GPR_CALLTYPE
+grpcsharp_server_request_call_old(grpc_server *server, void *tag_new) {
+ return grpc_server_request_call_old(server, tag_new);
+}
+
+GPR_EXPORT grpc_server *GPR_CALLTYPE
+grpcsharp_server_create(grpc_completion_queue *cq,
+ const grpc_channel_args *args) {
+ return grpc_server_create(cq, args);
+}
+
+GPR_EXPORT int GPR_CALLTYPE
+grpcsharp_server_add_http2_port(grpc_server *server, const char *addr) {
+ return grpc_server_add_http2_port(server, addr);
+}
+
+GPR_EXPORT int GPR_CALLTYPE
+grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr) {
+ return grpc_server_add_secure_http2_port(server, addr);
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_start(grpc_server *server) {
+ grpc_server_start(server);
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_shutdown(grpc_server *server) {
+ grpc_server_shutdown(server);
+}
+
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_server_shutdown_and_notify(grpc_server *server, void *tag) {
+ grpc_server_shutdown_and_notify(server, tag);
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_destroy(grpc_server *server) {
+ grpc_server_destroy(server);
}
diff --git a/src/node/binding.gyp b/src/node/binding.gyp
index cf2a6acb04..fb4c779f8e 100644
--- a/src/node/binding.gyp
+++ b/src/node/binding.gyp
@@ -9,14 +9,15 @@
'include_dirs': [
"<!(nodejs -e \"require('nan')\")"
],
- 'cxxflags': [
+ 'cflags': [
+ '-std=c++11',
'-Wall',
'-pthread',
'-pedantic',
'-g',
'-zdefs'
- '-Werror',
- ],
+ '-Werror'
+ ],
'ldflags': [
'-g'
],
@@ -33,11 +34,9 @@
"ext/channel.cc",
"ext/completion_queue_async_worker.cc",
"ext/credentials.cc",
- "ext/event.cc",
"ext/node_grpc.cc",
"ext/server.cc",
"ext/server_credentials.cc",
- "ext/tag.cc",
"ext/timeval.cc"
],
'conditions' : [
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 23aead07b2..9ed389f3bc 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,25 @@
*
*/
+#include <memory>
+#include <vector>
+#include <map>
+
#include <node.h>
#include "grpc/support/log.h"
#include "grpc/grpc.h"
+#include "grpc/support/alloc.h"
#include "grpc/support/time.h"
#include "byte_buffer.h"
#include "call.h"
#include "channel.h"
#include "completion_queue_async_worker.h"
#include "timeval.h"
-#include "tag.h"
+
+using std::unique_ptr;
+using std::shared_ptr;
+using std::vector;
namespace grpc {
namespace node {
@@ -49,6 +57,7 @@ namespace node {
using ::node::Buffer;
using v8::Arguments;
using v8::Array;
+using v8::Boolean;
using v8::Exception;
using v8::External;
using v8::Function;
@@ -68,37 +77,372 @@ using v8::Value;
Persistent<Function> Call::constructor;
Persistent<FunctionTemplate> Call::fun_tpl;
-Call::Call(grpc_call *call) : wrapped_call(call) {}
-Call::~Call() { grpc_call_destroy(wrapped_call); }
+bool CreateMetadataArray(Handle<Object> metadata, grpc_metadata_array *array,
+ shared_ptr<Resources> resources) {
+ NanScope();
+ grpc_metadata_array_init(array);
+ Handle<Array> keys(metadata->GetOwnPropertyNames());
+ for (unsigned int i = 0; i < keys->Length(); i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ if (!metadata->Get(current_key)->IsArray()) {
+ return false;
+ }
+ array->capacity += Local<Array>::Cast(metadata->Get(current_key))->Length();
+ }
+ array->metadata = reinterpret_cast<grpc_metadata*>(
+ gpr_malloc(array->capacity * sizeof(grpc_metadata)));
+ for (unsigned int i = 0; i < keys->Length(); i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ NanUtf8String *utf8_key = new NanUtf8String(current_key);
+ resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_key));
+ Handle<Array> values = Local<Array>::Cast(metadata->Get(current_key));
+ for (unsigned int j = 0; j < values->Length(); j++) {
+ Handle<Value> value = values->Get(j);
+ grpc_metadata *current = &array->metadata[array->count];
+ current->key = **utf8_key;
+ if (Buffer::HasInstance(value)) {
+ current->value = Buffer::Data(value);
+ current->value_length = Buffer::Length(value);
+ Persistent<Value> handle;
+ NanAssignPersistent(handle, value);
+ resources->handles.push_back(unique_ptr<PersistentHolder>(
+ new PersistentHolder(handle)));
+ } else if (value->IsString()) {
+ Handle<String> string_value = value->ToString();
+ NanUtf8String *utf8_value = new NanUtf8String(string_value);
+ resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_value));
+ current->value = **utf8_value;
+ current->value_length = string_value->Length();
+ } else {
+ return false;
+ }
+ array->count += 1;
+ }
+ }
+ return true;
+}
+
+Handle<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
+ NanEscapableScope();
+ grpc_metadata *metadata_elements = metadata_array->metadata;
+ size_t length = metadata_array->count;
+ std::map<const char*, size_t> size_map;
+ std::map<const char*, size_t> index_map;
+
+ for (unsigned int i = 0; i < length; i++) {
+ const char *key = metadata_elements[i].key;
+ if (size_map.count(key)) {
+ size_map[key] += 1;
+ }
+ index_map[key] = 0;
+ }
+ Handle<Object> metadata_object = NanNew<Object>();
+ for (unsigned int i = 0; i < length; i++) {
+ grpc_metadata* elem = &metadata_elements[i];
+ Handle<String> key_string = String::New(elem->key);
+ Handle<Array> array;
+ if (metadata_object->Has(key_string)) {
+ array = Handle<Array>::Cast(metadata_object->Get(key_string));
+ } else {
+ array = NanNew<Array>(size_map[elem->key]);
+ metadata_object->Set(key_string, array);
+ }
+ array->Set(index_map[elem->key],
+ MakeFastBuffer(
+ NanNewBufferHandle(elem->value, elem->value_length)));
+ index_map[elem->key] += 1;
+ }
+ return NanEscapeScope(metadata_object);
+}
+
+Handle<Value> Op::GetOpType() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanNew<String>(GetTypeString()));
+}
+
+class SendMetadataOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ if (!value->IsObject()) {
+ return false;
+ }
+ grpc_metadata_array array;
+ if (!CreateMetadataArray(value->ToObject(), &array, resources)) {
+ return false;
+ }
+ out->data.send_initial_metadata.count = array.count;
+ out->data.send_initial_metadata.metadata = array.metadata;
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "send metadata";
+ }
+};
+
+class SendMessageOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ if (!Buffer::HasInstance(value)) {
+ return false;
+ }
+ out->data.send_message = BufferToByteBuffer(value);
+ Persistent<Value> handle;
+ NanAssignPersistent(handle, value);
+ resources->handles.push_back(unique_ptr<PersistentHolder>(
+ new PersistentHolder(handle)));
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "send message";
+ }
+};
+
+class SendClientCloseOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "client close";
+ }
+};
+
+class SendServerStatusOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ if (!value->IsObject()) {
+ return false;
+ }
+ Handle<Object> server_status = value->ToObject();
+ if (!server_status->Get(NanNew("metadata"))->IsObject()) {
+ return false;
+ }
+ if (!server_status->Get(NanNew("code"))->IsUint32()) {
+ return false;
+ }
+ if (!server_status->Get(NanNew("details"))->IsString()) {
+ return false;
+ }
+ grpc_metadata_array array;
+ if (!CreateMetadataArray(server_status->Get(NanNew("metadata"))->
+ ToObject(),
+ &array, resources)) {
+ return false;
+ }
+ out->data.send_status_from_server.trailing_metadata_count = array.count;
+ out->data.send_status_from_server.trailing_metadata = array.metadata;
+ out->data.send_status_from_server.status =
+ static_cast<grpc_status_code>(
+ server_status->Get(NanNew("code"))->Uint32Value());
+ NanUtf8String *str = new NanUtf8String(
+ server_status->Get(NanNew("details")));
+ resources->strings.push_back(unique_ptr<NanUtf8String>(str));
+ out->data.send_status_from_server.status_details = **str;
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "send status";
+ }
+};
+
+class GetMetadataOp : public Op {
+ public:
+ GetMetadataOp() {
+ grpc_metadata_array_init(&recv_metadata);
+ }
+
+ ~GetMetadataOp() {
+ grpc_metadata_array_destroy(&recv_metadata);
+ }
+
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(ParseMetadata(&recv_metadata));
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_initial_metadata = &recv_metadata;
+ return true;
+ }
+
+ protected:
+ std::string GetTypeString() const {
+ return "metadata";
+ }
+
+ private:
+ grpc_metadata_array recv_metadata;
+};
+
+class ReadMessageOp : public Op {
+ public:
+ ReadMessageOp() {
+ recv_message = NULL;
+ }
+ ~ReadMessageOp() {
+ if (recv_message != NULL) {
+ gpr_free(recv_message);
+ }
+ }
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(ByteBufferToBuffer(recv_message));
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_message = &recv_message;
+ return true;
+ }
+
+ protected:
+ std::string GetTypeString() const {
+ return "read";
+ }
+
+ private:
+ grpc_byte_buffer *recv_message;
+};
+
+class ClientStatusOp : public Op {
+ public:
+ ClientStatusOp() {
+ grpc_metadata_array_init(&metadata_array);
+ status_details = NULL;
+ details_capacity = 0;
+ }
+
+ ~ClientStatusOp() {
+ grpc_metadata_array_destroy(&metadata_array);
+ gpr_free(status_details);
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_status_on_client.trailing_metadata = &metadata_array;
+ out->data.recv_status_on_client.status = &status;
+ out->data.recv_status_on_client.status_details = &status_details;
+ out->data.recv_status_on_client.status_details_capacity = &details_capacity;
+ return true;
+ }
+
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ Handle<Object> status_obj = NanNew<Object>();
+ status_obj->Set(NanNew("code"), NanNew<Number>(status));
+ if (status_details != NULL) {
+ status_obj->Set(NanNew("details"), String::New(status_details));
+ }
+ status_obj->Set(NanNew("metadata"), ParseMetadata(&metadata_array));
+ return NanEscapeScope(status_obj);
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "status";
+ }
+ private:
+ grpc_metadata_array metadata_array;
+ grpc_status_code status;
+ char *status_details;
+ size_t details_capacity;
+};
+
+class ServerCloseResponseOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanNew<Boolean>(cancelled));
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_close_on_server.cancelled = &cancelled;
+ return true;
+ }
+
+ protected:
+ std::string GetTypeString() const {
+ return "cancelled";
+ }
+
+ private:
+ int cancelled;
+};
+
+tag::tag(NanCallback *callback, OpVec *ops,
+ shared_ptr<Resources> resources) :
+ callback(callback), ops(ops), resources(resources){
+}
+
+tag::~tag() {
+ delete callback;
+ delete ops;
+}
+
+Handle<Value> GetTagNodeValue(void *tag) {
+ NanEscapableScope();
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ Handle<Object> tag_obj = NanNew<Object>();
+ for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
+ it != tag_struct->ops->end(); ++it) {
+ Op *op_ptr = it->get();
+ tag_obj->Set(op_ptr->GetOpType(), op_ptr->GetNodeValue());
+ }
+ return NanEscapeScope(tag_obj);
+}
+
+NanCallback *GetTagCallback(void *tag) {
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ return tag_struct->callback;
+}
+
+void DestroyTag(void *tag) {
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ delete tag_struct;
+}
+
+Call::Call(grpc_call *call) : wrapped_call(call) {
+}
+
+Call::~Call() {
+ grpc_call_destroy(wrapped_call);
+}
void Call::Init(Handle<Object> exports) {
NanScope();
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(NanNew("Call"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
- NanSetPrototypeTemplate(tpl, "addMetadata",
- FunctionTemplate::New(AddMetadata)->GetFunction());
- NanSetPrototypeTemplate(tpl, "invoke",
- FunctionTemplate::New(Invoke)->GetFunction());
- NanSetPrototypeTemplate(tpl, "serverAccept",
- FunctionTemplate::New(ServerAccept)->GetFunction());
- NanSetPrototypeTemplate(
- tpl, "serverEndInitialMetadata",
- FunctionTemplate::New(ServerEndInitialMetadata)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "startBatch",
+ FunctionTemplate::New(StartBatch)->GetFunction());
NanSetPrototypeTemplate(tpl, "cancel",
FunctionTemplate::New(Cancel)->GetFunction());
- NanSetPrototypeTemplate(tpl, "startWrite",
- FunctionTemplate::New(StartWrite)->GetFunction());
- NanSetPrototypeTemplate(
- tpl, "startWriteStatus",
- FunctionTemplate::New(StartWriteStatus)->GetFunction());
- NanSetPrototypeTemplate(tpl, "writesDone",
- FunctionTemplate::New(WritesDone)->GetFunction());
- NanSetPrototypeTemplate(tpl, "startReadMetadata",
- FunctionTemplate::New(WritesDone)->GetFunction());
- NanSetPrototypeTemplate(tpl, "startRead",
- FunctionTemplate::New(StartRead)->GetFunction());
NanAssignPersistent(fun_tpl, tpl);
NanAssignPersistent(constructor, tpl->GetFunction());
constructor->Set(NanNew("WRITE_BUFFER_HINT"),
@@ -152,9 +496,9 @@ NAN_METHOD(Call::New) {
NanUtf8String method(args[1]);
double deadline = args[2]->NumberValue();
grpc_channel *wrapped_channel = channel->GetWrappedChannel();
- grpc_call *wrapped_call = grpc_channel_create_call_old(
- wrapped_channel, *method, channel->GetHost(),
- MillisecondsToTimespec(deadline));
+ grpc_call *wrapped_call = grpc_channel_create_call(
+ wrapped_channel, CompletionQueueAsyncWorker::GetQueue(), *method,
+ channel->GetHost(), MillisecondsToTimespec(deadline));
call = new Call(wrapped_call);
args.This()->SetHiddenValue(String::NewSymbol("channel_"),
channel_object);
@@ -168,119 +512,74 @@ NAN_METHOD(Call::New) {
}
}
-NAN_METHOD(Call::AddMetadata) {
+NAN_METHOD(Call::StartBatch) {
NanScope();
if (!HasInstance(args.This())) {
- return NanThrowTypeError("addMetadata can only be called on Call objects");
+ return NanThrowTypeError("startBatch can only be called on Call objects");
}
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
if (!args[0]->IsObject()) {
- return NanThrowTypeError("addMetadata's first argument must be an object");
- }
- Handle<Object> metadata = args[0]->ToObject();
- Handle<Array> keys(metadata->GetOwnPropertyNames());
- for (unsigned int i = 0; i < keys->Length(); i++) {
- Handle<String> current_key(keys->Get(i)->ToString());
- if (!metadata->Get(current_key)->IsArray()) {
- return NanThrowTypeError(
- "addMetadata's first argument's values must be arrays");
- }
- NanUtf8String utf8_key(current_key);
- Handle<Array> values = Local<Array>::Cast(metadata->Get(current_key));
- for (unsigned int j = 0; j < values->Length(); j++) {
- Handle<Value> value = values->Get(j);
- grpc_metadata metadata;
- grpc_call_error error;
- metadata.key = *utf8_key;
- if (Buffer::HasInstance(value)) {
- metadata.value = Buffer::Data(value);
- metadata.value_length = Buffer::Length(value);
- error = grpc_call_add_metadata_old(call->wrapped_call, &metadata, 0);
- } else if (value->IsString()) {
- Handle<String> string_value = value->ToString();
- NanUtf8String utf8_value(string_value);
- metadata.value = *utf8_value;
- metadata.value_length = string_value->Length();
- gpr_log(GPR_DEBUG, "adding metadata: %s, %s, %d", metadata.key,
- metadata.value, metadata.value_length);
- error = grpc_call_add_metadata_old(call->wrapped_call, &metadata, 0);
- } else {
- return NanThrowTypeError(
- "addMetadata values must be strings or buffers");
- }
- if (error != GRPC_CALL_OK) {
- return NanThrowError("addMetadata failed", error);
- }
- }
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::Invoke) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("invoke can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("invoke's first argument must be a function");
+ return NanThrowError("startBatch's first argument must be an object");
}
if (!args[1]->IsFunction()) {
- return NanThrowTypeError("invoke's second argument must be a function");
- }
- if (!args[2]->IsUint32()) {
- return NanThrowTypeError("invoke's third argument must be integer flags");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- unsigned int flags = args[3]->Uint32Value();
- grpc_call_error error = grpc_call_invoke_old(
- call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
- CreateTag(args[0], args.This()), CreateTag(args[1], args.This()), flags);
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("invoke failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::ServerAccept) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("accept can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("accept's first argument must be a function");
+ return NanThrowError("startBatch's second argument must be a callback");
}
+ Handle<Function> callback_func = args[1].As<Function>();
Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_call_error error = grpc_call_server_accept_old(
- call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
- CreateTag(args[0], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("serverAccept failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::ServerEndInitialMetadata) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError(
- "serverEndInitialMetadata can only be called on Call objects");
- }
- if (!args[0]->IsUint32()) {
- return NanThrowTypeError(
- "serverEndInitialMetadata's second argument must be integer flags");
+ shared_ptr<Resources> resources(new Resources);
+ Handle<Object> obj = args[0]->ToObject();
+ Handle<Array> keys = obj->GetOwnPropertyNames();
+ size_t nops = keys->Length();
+ vector<grpc_op> ops(nops);
+ unique_ptr<OpVec> op_vector(new OpVec());
+ for (unsigned int i = 0; i < nops; i++) {
+ unique_ptr<Op> op;
+ if (!keys->Get(i)->IsUint32()) {
+ return NanThrowError(
+ "startBatch's first argument's keys must be integers");
+ }
+ uint32_t type = keys->Get(i)->Uint32Value();
+ ops[i].op = static_cast<grpc_op_type>(type);
+ switch (type) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ op.reset(new SendMetadataOp());
+ break;
+ case GRPC_OP_SEND_MESSAGE:
+ op.reset(new SendMessageOp());
+ break;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ op.reset(new SendClientCloseOp());
+ break;
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ op.reset(new SendServerStatusOp());
+ break;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ op.reset(new GetMetadataOp());
+ break;
+ case GRPC_OP_RECV_MESSAGE:
+ op.reset(new ReadMessageOp());
+ break;
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ op.reset(new ClientStatusOp());
+ break;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ op.reset(new ServerCloseResponseOp());
+ break;
+ default:
+ return NanThrowError("Argument object had an unrecognized key");
+ }
+ if (!op->ParseOp(obj->Get(type), &ops[i], resources)) {
+ return NanThrowTypeError("Incorrectly typed arguments to startBatch");
+ }
+ op_vector->push_back(std::move(op));
}
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- unsigned int flags = args[1]->Uint32Value();
- grpc_call_error error =
- grpc_call_server_end_initial_metadata_old(call->wrapped_call, flags);
+ NanCallback *callback = new NanCallback(callback_func);
+ grpc_call_error error = grpc_call_start_batch(
+ call->wrapped_call, &ops[0], nops, new struct tag(
+ callback, op_vector.release(), resources));
if (error != GRPC_CALL_OK) {
- return NanThrowError("serverEndInitialMetadata failed", error);
+ return NanThrowError("startBatch failed", error);
}
+ CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
}
@@ -297,102 +596,5 @@ NAN_METHOD(Call::Cancel) {
NanReturnUndefined();
}
-NAN_METHOD(Call::StartWrite) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("startWrite can only be called on Call objects");
- }
- if (!Buffer::HasInstance(args[0])) {
- return NanThrowTypeError("startWrite's first argument must be a Buffer");
- }
- if (!args[1]->IsFunction()) {
- return NanThrowTypeError("startWrite's second argument must be a function");
- }
- if (!args[2]->IsUint32()) {
- return NanThrowTypeError(
- "startWrite's third argument must be integer flags");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_byte_buffer *buffer = BufferToByteBuffer(args[0]);
- unsigned int flags = args[2]->Uint32Value();
- grpc_call_error error = grpc_call_start_write_old(
- call->wrapped_call, buffer, CreateTag(args[1], args.This()), flags);
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("startWrite failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::StartWriteStatus) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError(
- "startWriteStatus can only be called on Call objects");
- }
- if (!args[0]->IsUint32()) {
- return NanThrowTypeError(
- "startWriteStatus's first argument must be a status code");
- }
- if (!args[1]->IsString()) {
- return NanThrowTypeError(
- "startWriteStatus's second argument must be a string");
- }
- if (!args[2]->IsFunction()) {
- return NanThrowTypeError(
- "startWriteStatus's third argument must be a function");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- NanUtf8String details(args[1]);
- grpc_call_error error = grpc_call_start_write_status_old(
- call->wrapped_call, (grpc_status_code)args[0]->Uint32Value(), *details,
- CreateTag(args[2], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("startWriteStatus failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::WritesDone) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("writesDone can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("writesDone's first argument must be a function");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_call_error error = grpc_call_writes_done_old(
- call->wrapped_call, CreateTag(args[0], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("writesDone failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::StartRead) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("startRead can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("startRead's first argument must be a function");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_call_error error = grpc_call_start_read_old(
- call->wrapped_call, CreateTag(args[0], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("startRead failed", error);
- }
- NanReturnUndefined();
-}
-
} // namespace node
} // namespace grpc
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index 1924a1bf42..dbdb8e2ff6 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -34,15 +34,71 @@
#ifndef NET_GRPC_NODE_CALL_H_
#define NET_GRPC_NODE_CALL_H_
+#include <memory>
+#include <vector>
+
#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "channel.h"
+
namespace grpc {
namespace node {
+using std::unique_ptr;
+using std::shared_ptr;
+
+v8::Handle<v8::Value> ParseMetadata(const grpc_metadata_array *metadata_array);
+
+class PersistentHolder {
+ public:
+ explicit PersistentHolder(v8::Persistent<v8::Value> persist) :
+ persist(persist) {
+ }
+
+ ~PersistentHolder() {
+ NanDisposePersistent(persist);
+ }
+
+ private:
+ v8::Persistent<v8::Value> persist;
+};
+
+struct Resources {
+ std::vector<unique_ptr<NanUtf8String> > strings;
+ std::vector<unique_ptr<PersistentHolder> > handles;
+};
+
+class Op {
+ public:
+ virtual v8::Handle<v8::Value> GetNodeValue() const = 0;
+ virtual bool ParseOp(v8::Handle<v8::Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) = 0;
+ v8::Handle<v8::Value> GetOpType() const;
+
+ protected:
+ virtual std::string GetTypeString() const = 0;
+};
+
+typedef std::vector<unique_ptr<Op>> OpVec;
+
+struct tag {
+ tag(NanCallback *callback, OpVec *ops,
+ shared_ptr<Resources> resources);
+ ~tag();
+ NanCallback *callback;
+ OpVec *ops;
+ shared_ptr<Resources> resources;
+};
+
+v8::Handle<v8::Value> GetTagNodeValue(void *tag);
+
+NanCallback *GetTagCallback(void *tag);
+
+void DestroyTag(void *tag);
+
/* Wrapper class for grpc_call structs. */
class Call : public ::node::ObjectWrap {
public:
@@ -60,15 +116,8 @@ class Call : public ::node::ObjectWrap {
Call &operator=(const Call &);
static NAN_METHOD(New);
- static NAN_METHOD(AddMetadata);
- static NAN_METHOD(Invoke);
- static NAN_METHOD(ServerAccept);
- static NAN_METHOD(ServerEndInitialMetadata);
+ static NAN_METHOD(StartBatch);
static NAN_METHOD(Cancel);
- static NAN_METHOD(StartWrite);
- static NAN_METHOD(StartWriteStatus);
- static NAN_METHOD(WritesDone);
- static NAN_METHOD(StartRead);
static v8::Persistent<v8::Function> constructor;
// Used for typechecking instances of this javascript class
static v8::Persistent<v8::FunctionTemplate> fun_tpl;
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
index 8de7db66d5..a1f390f64b 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -35,10 +35,10 @@
#include <nan.h>
#include "grpc/grpc.h"
+#include "grpc/support/log.h"
#include "grpc/support/time.h"
#include "completion_queue_async_worker.h"
-#include "event.h"
-#include "tag.h"
+#include "call.h"
namespace grpc {
namespace node {
@@ -58,6 +58,9 @@ CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {}
void CompletionQueueAsyncWorker::Execute() {
result = grpc_completion_queue_next(queue, gpr_inf_future);
+ if (result->data.op_complete != GRPC_OP_OK) {
+ SetErrorMessage("The batch encountered an error");
+ }
}
grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; }
@@ -75,14 +78,26 @@ void CompletionQueueAsyncWorker::Init(Handle<Object> exports) {
void CompletionQueueAsyncWorker::HandleOKCallback() {
NanScope();
- NanCallback event_callback(GetTagHandle(result->tag).As<Function>());
- Handle<Value> argv[] = {CreateEventObject(result)};
+ NanCallback *callback = GetTagCallback(result->tag);
+ Handle<Value> argv[] = {NanNull(), GetTagNodeValue(result->tag)};
+
+ callback->Call(2, argv);
DestroyTag(result->tag);
grpc_event_finish(result);
result = NULL;
+}
+
+void CompletionQueueAsyncWorker::HandleErrorCallback() {
+ NanScope();
+ NanCallback *callback = GetTagCallback(result->tag);
+ Handle<Value> argv[] = {NanError(ErrorMessage())};
- event_callback.Call(1, argv);
+ callback->Call(1, argv);
+
+ DestroyTag(result->tag);
+ grpc_event_finish(result);
+ result = NULL;
}
} // namespace node
diff --git a/src/node/ext/completion_queue_async_worker.h b/src/node/ext/completion_queue_async_worker.h
index 2c928b7024..c04a303283 100644
--- a/src/node/ext/completion_queue_async_worker.h
+++ b/src/node/ext/completion_queue_async_worker.h
@@ -67,6 +67,8 @@ class CompletionQueueAsyncWorker : public NanAsyncWorker {
completion_queue_next */
void HandleOKCallback();
+ void HandleErrorCallback();
+
private:
grpc_event *result;
diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc
index c8859ed941..b79c3e3019 100644
--- a/src/node/ext/credentials.cc
+++ b/src/node/ext/credentials.cc
@@ -63,7 +63,6 @@ Credentials::Credentials(grpc_credentials *credentials)
: wrapped_credentials(credentials) {}
Credentials::~Credentials() {
- gpr_log(GPR_DEBUG, "Destroying credentials object");
grpc_credentials_release(wrapped_credentials);
}
diff --git a/src/node/ext/event.cc b/src/node/ext/event.cc
deleted file mode 100644
index d59b68fb40..0000000000
--- a/src/node/ext/event.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <map>
-
-#include <node.h>
-#include <nan.h>
-#include "grpc/grpc.h"
-#include "byte_buffer.h"
-#include "call.h"
-#include "event.h"
-#include "tag.h"
-#include "timeval.h"
-
-namespace grpc {
-namespace node {
-
-using ::node::Buffer;
-using v8::Array;
-using v8::Date;
-using v8::Handle;
-using v8::HandleScope;
-using v8::Number;
-using v8::Object;
-using v8::Persistent;
-using v8::String;
-using v8::Value;
-
-Handle<Value> ParseMetadata(grpc_metadata *metadata_elements, size_t length) {
- NanEscapableScope();
- std::map<const char*, size_t> size_map;
- std::map<const char*, size_t> index_map;
-
- for (unsigned int i = 0; i < length; i++) {
- const char *key = metadata_elements[i].key;
- if (size_map.count(key)) {
- size_map[key] += 1;
- }
- index_map[key] = 0;
- }
- Handle<Object> metadata_object = NanNew<Object>();
- for (unsigned int i = 0; i < length; i++) {
- grpc_metadata* elem = &metadata_elements[i];
- Handle<String> key_string = String::New(elem->key);
- Handle<Array> array;
- if (metadata_object->Has(key_string)) {
- array = Handle<Array>::Cast(metadata_object->Get(key_string));
- } else {
- array = NanNew<Array>(size_map[elem->key]);
- metadata_object->Set(key_string, array);
- }
- array->Set(index_map[elem->key],
- MakeFastBuffer(
- NanNewBufferHandle(elem->value, elem->value_length)));
- index_map[elem->key] += 1;
- }
- return NanEscapeScope(metadata_object);
-}
-
-Handle<Value> GetEventData(grpc_event *event) {
- NanEscapableScope();
- size_t count;
- grpc_metadata *items;
- Handle<Array> metadata;
- Handle<Object> status;
- Handle<Object> rpc_new;
- switch (event->type) {
- case GRPC_READ:
- return NanEscapeScope(ByteBufferToBuffer(event->data.read));
- case GRPC_WRITE_ACCEPTED:
- return NanEscapeScope(NanNew<Number>(event->data.write_accepted));
- case GRPC_FINISH_ACCEPTED:
- return NanEscapeScope(NanNew<Number>(event->data.finish_accepted));
- case GRPC_CLIENT_METADATA_READ:
- count = event->data.client_metadata_read.count;
- items = event->data.client_metadata_read.elements;
- return NanEscapeScope(ParseMetadata(items, count));
- case GRPC_FINISHED:
- status = NanNew<Object>();
- status->Set(NanNew("code"), NanNew<Number>(event->data.finished.status));
- if (event->data.finished.details != NULL) {
- status->Set(NanNew("details"),
- String::New(event->data.finished.details));
- }
- count = event->data.finished.metadata_count;
- items = event->data.finished.metadata_elements;
- status->Set(NanNew("metadata"), ParseMetadata(items, count));
- return NanEscapeScope(status);
- case GRPC_SERVER_RPC_NEW:
- rpc_new = NanNew<Object>();
- if (event->data.server_rpc_new.method == NULL) {
- return NanEscapeScope(NanNull());
- }
- rpc_new->Set(
- NanNew("method"),
- NanNew(event->data.server_rpc_new.method));
- rpc_new->Set(
- NanNew("host"),
- NanNew(event->data.server_rpc_new.host));
- rpc_new->Set(NanNew("absolute_deadline"),
- NanNew<Date>(TimespecToMilliseconds(
- event->data.server_rpc_new.deadline)));
- count = event->data.server_rpc_new.metadata_count;
- items = event->data.server_rpc_new.metadata_elements;
- metadata = NanNew<Array>(static_cast<int>(count));
- for (unsigned int i = 0; i < count; i++) {
- Handle<Object> item_obj = Object::New();
- item_obj->Set(NanNew("key"),
- NanNew(items[i].key));
- item_obj->Set(
- NanNew("value"),
- NanNew(items[i].value, static_cast<int>(items[i].value_length)));
- metadata->Set(i, item_obj);
- }
- rpc_new->Set(NanNew("metadata"), ParseMetadata(items, count));
- return NanEscapeScope(rpc_new);
- default:
- return NanEscapeScope(NanNull());
- }
-}
-
-Handle<Value> CreateEventObject(grpc_event *event) {
- NanEscapableScope();
- if (event == NULL) {
- return NanEscapeScope(NanNull());
- }
- Handle<Object> event_obj = NanNew<Object>();
- Handle<Value> call;
- if (TagHasCall(event->tag)) {
- call = TagGetCall(event->tag);
- } else {
- call = Call::WrapStruct(event->call);
- }
- event_obj->Set(NanNew<String, const char *>("call"), call);
- event_obj->Set(NanNew<String, const char *>("type"),
- NanNew<Number>(event->type));
- event_obj->Set(NanNew<String, const char *>("data"), GetEventData(event));
-
- return NanEscapeScope(event_obj);
-}
-
-} // namespace node
-} // namespace grpc
diff --git a/src/node/ext/event.h b/src/node/ext/event.h
deleted file mode 100644
index e06d8f0168..0000000000
--- a/src/node/ext/event.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef NET_GRPC_NODE_EVENT_H_
-#define NET_GRPC_NODE_EVENT_H_
-
-#include <node.h>
-#include "grpc/grpc.h"
-
-namespace grpc {
-namespace node {
-
-v8::Handle<v8::Value> CreateEventObject(grpc_event *event);
-
-} // namespace node
-} // namespace grpc
-
-#endif // NET_GRPC_NODE_EVENT_H_
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index bc1dfaf899..9b0fe82976 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -130,35 +130,34 @@ void InitCallErrorConstants(Handle<Object> exports) {
call_error->Set(NanNew("INVALID_FLAGS"), INVALID_FLAGS);
}
-void InitOpErrorConstants(Handle<Object> exports) {
+void InitOpTypeConstants(Handle<Object> exports) {
NanScope();
- Handle<Object> op_error = Object::New();
- exports->Set(NanNew("opError"), op_error);
- Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_OP_OK));
- op_error->Set(NanNew("OK"), OK);
- Handle<Value> ERROR(NanNew<Uint32, uint32_t>(GRPC_OP_ERROR));
- op_error->Set(NanNew("ERROR"), ERROR);
-}
-
-void InitCompletionTypeConstants(Handle<Object> exports) {
- NanScope();
- Handle<Object> completion_type = Object::New();
- exports->Set(NanNew("completionType"), completion_type);
- Handle<Value> QUEUE_SHUTDOWN(NanNew<Uint32, uint32_t>(GRPC_QUEUE_SHUTDOWN));
- completion_type->Set(NanNew("QUEUE_SHUTDOWN"), QUEUE_SHUTDOWN);
- Handle<Value> READ(NanNew<Uint32, uint32_t>(GRPC_READ));
- completion_type->Set(NanNew("READ"), READ);
- Handle<Value> WRITE_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_WRITE_ACCEPTED));
- completion_type->Set(NanNew("WRITE_ACCEPTED"), WRITE_ACCEPTED);
- Handle<Value> FINISH_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_FINISH_ACCEPTED));
- completion_type->Set(NanNew("FINISH_ACCEPTED"), FINISH_ACCEPTED);
- Handle<Value> CLIENT_METADATA_READ(
- NanNew<Uint32, uint32_t>(GRPC_CLIENT_METADATA_READ));
- completion_type->Set(NanNew("CLIENT_METADATA_READ"), CLIENT_METADATA_READ);
- Handle<Value> FINISHED(NanNew<Uint32, uint32_t>(GRPC_FINISHED));
- completion_type->Set(NanNew("FINISHED"), FINISHED);
- Handle<Value> SERVER_RPC_NEW(NanNew<Uint32, uint32_t>(GRPC_SERVER_RPC_NEW));
- completion_type->Set(NanNew("SERVER_RPC_NEW"), SERVER_RPC_NEW);
+ Handle<Object> op_type = Object::New();
+ exports->Set(NanNew("opType"), op_type);
+ Handle<Value> SEND_INITIAL_METADATA(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_INITIAL_METADATA));
+ op_type->Set(NanNew("SEND_INITIAL_METADATA"), SEND_INITIAL_METADATA);
+ Handle<Value> SEND_MESSAGE(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_MESSAGE));
+ op_type->Set(NanNew("SEND_MESSAGE"), SEND_MESSAGE);
+ Handle<Value> SEND_CLOSE_FROM_CLIENT(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
+ op_type->Set(NanNew("SEND_CLOSE_FROM_CLIENT"), SEND_CLOSE_FROM_CLIENT);
+ Handle<Value> SEND_STATUS_FROM_SERVER(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_STATUS_FROM_SERVER));
+ op_type->Set(NanNew("SEND_STATUS_FROM_SERVER"), SEND_STATUS_FROM_SERVER);
+ Handle<Value> RECV_INITIAL_METADATA(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_INITIAL_METADATA));
+ op_type->Set(NanNew("RECV_INITIAL_METADATA"), RECV_INITIAL_METADATA);
+ Handle<Value> RECV_MESSAGE(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_MESSAGE));
+ op_type->Set(NanNew("RECV_MESSAGE"), RECV_MESSAGE);
+ Handle<Value> RECV_STATUS_ON_CLIENT(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_STATUS_ON_CLIENT));
+ op_type->Set(NanNew("RECV_STATUS_ON_CLIENT"), RECV_STATUS_ON_CLIENT);
+ Handle<Value> RECV_CLOSE_ON_SERVER(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_CLOSE_ON_SERVER));
+ op_type->Set(NanNew("RECV_CLOSE_ON_SERVER"), RECV_CLOSE_ON_SERVER);
}
void init(Handle<Object> exports) {
@@ -166,8 +165,7 @@ void init(Handle<Object> exports) {
grpc_init();
InitStatusConstants(exports);
InitCallErrorConstants(exports);
- InitOpErrorConstants(exports);
- InitCompletionTypeConstants(exports);
+ InitOpTypeConstants(exports);
grpc::node::Call::Init(exports);
grpc::node::Channel::Init(exports);
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 6b8ccef9b1..ee3e1087ce 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -31,6 +31,8 @@
*
*/
+#include <memory>
+
#include "server.h"
#include <node.h>
@@ -41,17 +43,20 @@
#include <vector>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
+#include "grpc/support/log.h"
#include "call.h"
#include "completion_queue_async_worker.h"
-#include "tag.h"
#include "server_credentials.h"
+#include "timeval.h"
namespace grpc {
namespace node {
+using std::unique_ptr;
using v8::Arguments;
using v8::Array;
using v8::Boolean;
+using v8::Date;
using v8::Exception;
using v8::Function;
using v8::FunctionTemplate;
@@ -67,6 +72,49 @@ using v8::Value;
Persistent<Function> Server::constructor;
Persistent<FunctionTemplate> Server::fun_tpl;
+class NewCallOp : public Op {
+ public:
+ NewCallOp() {
+ call = NULL;
+ grpc_call_details_init(&details);
+ grpc_metadata_array_init(&request_metadata);
+ }
+
+ ~NewCallOp() {
+ grpc_call_details_destroy(&details);
+ grpc_metadata_array_destroy(&request_metadata);
+ }
+
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ if (call == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ Handle<Object> obj = NanNew<Object>();
+ obj->Set(NanNew("call"), Call::WrapStruct(call));
+ obj->Set(NanNew("method"), NanNew(details.method));
+ obj->Set(NanNew("host"), NanNew(details.host));
+ obj->Set(NanNew("deadline"),
+ NanNew<Date>(TimespecToMilliseconds(details.deadline)));
+ obj->Set(NanNew("metadata"), ParseMetadata(&request_metadata));
+ return NanEscapeScope(obj);
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ return true;
+ }
+
+ grpc_call *call;
+ grpc_call_details details;
+ grpc_metadata_array request_metadata;
+
+ protected:
+ std::string GetTypeString() const {
+ return "new call";
+ }
+};
+
Server::Server(grpc_server *server) : wrapped_server(server) {}
Server::~Server() { grpc_server_destroy(wrapped_server); }
@@ -175,13 +223,18 @@ NAN_METHOD(Server::RequestCall) {
return NanThrowTypeError("requestCall can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
- grpc_call_error error = grpc_server_request_call_old(
- server->wrapped_server, CreateTag(args[0], NanNull()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
+ NewCallOp *op = new NewCallOp();
+ unique_ptr<OpVec> ops(new OpVec());
+ ops->push_back(unique_ptr<Op>(op));
+ grpc_call_error error = grpc_server_request_call(
+ server->wrapped_server, &op->call, &op->details, &op->request_metadata,
+ CompletionQueueAsyncWorker::GetQueue(),
+ new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
+ shared_ptr<Resources>(nullptr)));
+ if (error != GRPC_CALL_OK) {
return NanThrowError("requestCall failed", error);
}
+ CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
}
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index 393f3a6305..3add43c48c 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -63,7 +63,6 @@ ServerCredentials::ServerCredentials(grpc_server_credentials *credentials)
: wrapped_credentials(credentials) {}
ServerCredentials::~ServerCredentials() {
- gpr_log(GPR_DEBUG, "Destroying server credentials object");
grpc_server_credentials_release(wrapped_credentials);
}
diff --git a/src/node/ext/tag.cc b/src/node/ext/tag.cc
deleted file mode 100644
index dc8e523e12..0000000000
--- a/src/node/ext/tag.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <stdlib.h>
-#include <node.h>
-#include <nan.h>
-#include "tag.h"
-
-namespace grpc {
-namespace node {
-
-using v8::Handle;
-using v8::HandleScope;
-using v8::Persistent;
-using v8::Value;
-
-struct tag {
- tag(Persistent<Value> *tag, Persistent<Value> *call)
- : persist_tag(tag), persist_call(call) {}
-
- ~tag() {
- persist_tag->Dispose();
- if (persist_call != NULL) {
- persist_call->Dispose();
- }
- }
- Persistent<Value> *persist_tag;
- Persistent<Value> *persist_call;
-};
-
-void *CreateTag(Handle<Value> tag, Handle<Value> call) {
- NanScope();
- Persistent<Value> *persist_tag = new Persistent<Value>();
- NanAssignPersistent(*persist_tag, tag);
- Persistent<Value> *persist_call;
- if (call->IsNull() || call->IsUndefined()) {
- persist_call = NULL;
- } else {
- persist_call = new Persistent<Value>();
- NanAssignPersistent(*persist_call, call);
- }
- struct tag *tag_struct = new struct tag(persist_tag, persist_call);
- return reinterpret_cast<void *>(tag_struct);
-}
-
-Handle<Value> GetTagHandle(void *tag) {
- NanEscapableScope();
- struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
- Handle<Value> tag_value = NanNew<Value>(*tag_struct->persist_tag);
- return NanEscapeScope(tag_value);
-}
-
-bool TagHasCall(void *tag) {
- struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
- return tag_struct->persist_call != NULL;
-}
-
-Handle<Value> TagGetCall(void *tag) {
- NanEscapableScope();
- struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
- if (tag_struct->persist_call == NULL) {
- return NanEscapeScope(NanNull());
- }
- Handle<Value> call_value = NanNew<Value>(*tag_struct->persist_call);
- return NanEscapeScope(call_value);
-}
-
-void DestroyTag(void *tag) { delete reinterpret_cast<struct tag *>(tag); }
-
-} // namespace node
-} // namespace grpc
diff --git a/src/node/ext/tag.h b/src/node/ext/tag.h
deleted file mode 100644
index bdb09252d9..0000000000
--- a/src/node/ext/tag.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef NET_GRPC_NODE_TAG_H_
-#define NET_GRPC_NODE_TAG_H_
-
-#include <node.h>
-
-namespace grpc {
-namespace node {
-
-/* Create a void* tag that can be passed to various grpc_call functions from
- a javascript value and the javascript wrapper for the call. The call can be
- null. */
-void *CreateTag(v8::Handle<v8::Value> tag, v8::Handle<v8::Value> call);
-/* Return the javascript value stored in the tag */
-v8::Handle<v8::Value> GetTagHandle(void *tag);
-/* Returns true if the call was set (non-null) when the tag was created */
-bool TagHasCall(void *tag);
-/* Returns the javascript wrapper for the call associated with this tag */
-v8::Handle<v8::Value> TagGetCall(void *call);
-/* Destroy the tag and all resources it is holding. It is illegal to call any
- of these other functions on a tag after it has been destroyed. */
-void DestroyTag(void *tag);
-
-} // namespace node
-} // namespace grpc
-
-#endif // NET_GRPC_NODE_TAG_H_
diff --git a/src/node/index.js b/src/node/index.js
index 0627e7f557..baef4d03c6 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -35,9 +35,9 @@ var _ = require('underscore');
var ProtoBuf = require('protobufjs');
-var surface_client = require('./src/surface_client.js');
+var client = require('./src/client.js');
-var surface_server = require('./src/surface_server.js');
+var server = require('./src/server.js');
var grpc = require('bindings')('grpc');
@@ -54,7 +54,7 @@ function loadObject(value) {
});
return result;
} else if (value.className === 'Service') {
- return surface_client.makeClientConstructor(value);
+ return client.makeClientConstructor(value);
} else if (value.className === 'Message' || value.className === 'Enum') {
return value.build();
} else {
@@ -84,9 +84,9 @@ exports.loadObject = loadObject;
exports.load = load;
/**
- * See docs for surface_server.makeServerConstructor
+ * See docs for server.makeServerConstructor
*/
-exports.buildServer = surface_server.makeServerConstructor;
+exports.buildServer = server.makeServerConstructor;
/**
* Status name to code number mapping
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index ce18f77fe7..8737af6cde 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -145,8 +145,8 @@ function serverStreaming(client, done) {
resp_index += 1;
});
call.on('status', function(status) {
- assert.strictEqual(resp_index, 4);
assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(resp_index, 4);
if (done) {
done();
}
diff --git a/src/node/interop/test.proto b/src/node/interop/test.proto
index 8380ebb31d..996f11aa6d 100644
--- a/src/node/interop/test.proto
+++ b/src/node/interop/test.proto
@@ -14,7 +14,7 @@ service TestService {
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
- // The server returns the client payload as-is.
+ // TODO(Issue 527): Describe required server behavior.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by a sequence of responses (streamed download).
diff --git a/src/node/package.json b/src/node/package.json
index 028dc20555..8f81014c1e 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "gRPC Library for Node",
"scripts": {
"test": "./node_modules/mocha/bin/mocha"
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 3a1c9eef84..81fa65eb26 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,185 +31,452 @@
*
*/
+var _ = require('underscore');
+
+var capitalize = require('underscore.string/capitalize');
+var decapitalize = require('underscore.string/decapitalize');
+
var grpc = require('bindings')('grpc.node');
-var common = require('./common');
+var common = require('./common.js');
+
+var EventEmitter = require('events').EventEmitter;
-var Duplex = require('stream').Duplex;
+var stream = require('stream');
+
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+var Duplex = stream.Duplex;
var util = require('util');
-util.inherits(GrpcClientStream, Duplex);
+util.inherits(ClientWritableStream, Writable);
/**
- * Class for representing a gRPC client side stream as a Node stream. Extends
- * from stream.Duplex.
+ * A stream that the client can write to. Used for calls that are streaming from
+ * the client side.
* @constructor
- * @param {grpc.Call} call Call object to proxy
- * @param {function(*):Buffer=} serialize Serialization function for requests
- * @param {function(Buffer):*=} deserialize Deserialization function for
- * responses
+ * @param {grpc.Call} call The call object to send data with
+ * @param {function(*):Buffer=} serialize Serialization function for writes.
*/
-function GrpcClientStream(call, serialize, deserialize) {
- Duplex.call(this, {objectMode: true});
- if (!serialize) {
- serialize = function(value) {
- return value;
- };
- }
- if (!deserialize) {
- deserialize = function(value) {
- return value;
- };
- }
- var self = this;
- var finished = false;
- // Indicates that a read is currently pending
- var reading = false;
- // Indicates that a write is currently pending
- var writing = false;
- this._call = call;
+function ClientWritableStream(call, serialize) {
+ Writable.call(this, {objectMode: true});
+ this.call = call;
+ this.serialize = common.wrapIgnoreNull(serialize);
+ this.on('finish', function() {
+ var batch = {};
+ batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ call.startBatch(batch, function() {});
+ });
+}
- /**
- * Serialize a request value to a buffer. Always maps null to null. Otherwise
- * uses the provided serialize function
- * @param {*} value The value to serialize
- * @return {Buffer} The serialized value
- */
- this.serialize = function(value) {
- if (value === null || value === undefined) {
- return null;
+/**
+ * Attempt to write the given chunk. Calls the callback when done. This is an
+ * implementation of a method needed for implementing stream.Writable.
+ * @param {Buffer} chunk The chunk to write
+ * @param {string} encoding Ignored
+ * @param {function(Error=)} callback Called when the write is complete
+ */
+function _write(chunk, encoding, callback) {
+ var batch = {};
+ batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+ this.call.startBatch(batch, function(err, event) {
+ if (err) {
+ throw err;
}
- return serialize(value);
- };
+ callback();
+ });
+};
- /**
- * Deserialize a response buffer to a value. Always maps null to null.
- * Otherwise uses the provided deserialize function.
- * @param {Buffer} buffer The buffer to deserialize
- * @return {*} The deserialized value
- */
- this.deserialize = function(buffer) {
- if (buffer === null) {
- return null;
- }
- return deserialize(buffer);
- };
+ClientWritableStream.prototype._write = _write;
+
+util.inherits(ClientReadableStream, Readable);
+
+/**
+ * A stream that the client can read from. Used for calls that are streaming
+ * from the server side.
+ * @constructor
+ * @param {grpc.Call} call The call object to read data with
+ * @param {function(Buffer):*=} deserialize Deserialization function for reads
+ */
+function ClientReadableStream(call, deserialize) {
+ Readable.call(this, {objectMode: true});
+ this.call = call;
+ this.finished = false;
+ this.reading = false;
+ this.deserialize = common.wrapIgnoreNull(deserialize);
+}
+
+/**
+ * Read the next object from the stream.
+ * @param {*} size Ignored because we use objectMode=true
+ */
+function _read(size) {
+ var self = this;
/**
* Callback to be called when a READ event is received. Pushes the data onto
* the read queue and starts reading again if applicable
* @param {grpc.Event} event READ event object
*/
- function readCallback(event) {
- if (finished) {
+ function readCallback(err, event) {
+ if (err) {
+ throw err;
+ }
+ if (self.finished) {
self.push(null);
return;
}
- var data = event.data;
+ var data = event.read;
if (self.push(self.deserialize(data)) && data != null) {
- self._call.startRead(readCallback);
+ var read_batch = {};
+ read_batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(read_batch, readCallback);
} else {
- reading = false;
+ self.reading = false;
+ }
+ }
+ if (self.finished) {
+ self.push(null);
+ } else {
+ if (!self.reading) {
+ self.reading = true;
+ var read_batch = {};
+ read_batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(read_batch, readCallback);
}
}
- call.invoke(function(event) {
- self.emit('metadata', event.data);
- }, function(event) {
- finished = true;
- self.emit('status', event.data);
- }, 0);
+};
+
+ClientReadableStream.prototype._read = _read;
+
+util.inherits(ClientDuplexStream, Duplex);
+
+/**
+ * A stream that the client can read from or write to. Used for calls with
+ * duplex streaming.
+ * @constructor
+ * @param {grpc.Call} call Call object to proxy
+ * @param {function(*):Buffer=} serialize Serialization function for requests
+ * @param {function(Buffer):*=} deserialize Deserialization function for
+ * responses
+ */
+function ClientDuplexStream(call, serialize, deserialize) {
+ Duplex.call(this, {objectMode: true});
+ this.serialize = common.wrapIgnoreNull(serialize);
+ this.deserialize = common.wrapIgnoreNull(deserialize);
+ var self = this;
+ var finished = false;
+ // Indicates that a read is currently pending
+ var reading = false;
+ this.call = call;
this.on('finish', function() {
- call.writesDone(function() {});
+ var batch = {};
+ batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ call.startBatch(batch, function() {});
});
- /**
- * Start reading if there is not already a pending read. Reading will
- * continue until self.push returns false (indicating reads should slow
- * down) or the read data is null (indicating that there is no more data).
- */
- this.startReading = function() {
- if (finished) {
- self.push(null);
- } else {
- if (!reading) {
- reading = true;
- self._call.startRead(readCallback);
- }
- }
- };
}
+ClientDuplexStream.prototype._read = _read;
+ClientDuplexStream.prototype._write = _write;
+
/**
- * Start reading. This is an implementation of a method needed for implementing
- * stream.Readable.
- * @param {number} size Ignored
+ * Cancel the ongoing call
*/
-GrpcClientStream.prototype._read = function(size) {
- this.startReading();
-};
+function cancel() {
+ this.call.cancel();
+}
+
+ClientReadableStream.prototype.cancel = cancel;
+ClientWritableStream.prototype.cancel = cancel;
+ClientDuplexStream.prototype.cancel = cancel;
/**
- * Attempt to write the given chunk. Calls the callback when done. This is an
- * implementation of a method needed for implementing stream.Writable.
- * @param {Buffer} chunk The chunk to write
- * @param {string} encoding Ignored
- * @param {function(Error=)} callback Ignored
+ * Get a function that can make unary requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeUnaryRequest
*/
-GrpcClientStream.prototype._write = function(chunk, encoding, callback) {
- var self = this;
- self._call.startWrite(self.serialize(chunk), function(event) {
- callback();
- }, 0);
-};
+function makeUnaryRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a unary request with this method on the given channel with the given
+ * argument, callback, etc.
+ * @this {Client} Client object. Must have a channel member.
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {function(?Error, value=)} callback The callback to for when the
+ * response is received
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeUnaryRequest(argument, callback, metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var emitter = new EventEmitter();
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ emitter.cancel = function cancel() {
+ call.cancel();
+ };
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ client_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (response.status.code != grpc.status.OK) {
+ callback(response.status);
+ return;
+ }
+ emitter.emit('status', response.status);
+ emitter.emit('metadata', response.metadata);
+ callback(null, deserialize(response.read));
+ });
+ return emitter;
+ }
+ return makeUnaryRequest;
+}
/**
- * Cancel the ongoing call. If the call has not already finished, it will finish
- * with status CANCELLED.
+ * Get a function that can make client stream requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeClientStreamRequest
*/
-GrpcClientStream.prototype.cancel = function() {
- this._call.cancel();
-};
+function makeClientStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a client stream request with this method on the given channel with the
+ * given callback, etc.
+ * @this {Client} Client object. Must have a channel member.
+ * @param {function(?Error, value=)} callback The callback to for when the
+ * response is received
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeClientStreamRequest(callback, metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ var stream = new ClientWritableStream(call, serialize);
+ var metadata_batch = {};
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ call.startBatch(metadata_batch, function(err, response) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ stream.emit('metadata', response.metadata);
+ });
+ var client_batch = {};
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (response.status.code != grpc.status.OK) {
+ callback(response.status);
+ return;
+ }
+ stream.emit('status', response.status);
+ callback(null, deserialize(response.read));
+ });
+ return stream;
+ }
+ return makeClientStreamRequest;
+}
/**
- * Make a request on the channel to the given method with the given arguments
- * @param {grpc.Channel} channel The channel on which to make the request
- * @param {string} method The method to request
- * @param {function(*):Buffer} serialize Serialization function for requests
- * @param {function(Buffer):*} deserialize Deserialization function for
- * responses
- * @param {array=} metadata Array of metadata key/value pairs to add to the call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future.
- * @return {stream=} The stream of responses
+ * Get a function that can make server stream requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeServerStreamRequest
*/
-function makeRequest(channel,
- method,
- serialize,
- deserialize,
- metadata,
- deadline) {
- if (deadline === undefined) {
- deadline = Infinity;
+function makeServerStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a server stream request with this method on the given channel with the
+ * given argument, etc.
+ * @this {SurfaceClient} Client object. Must have a channel member.
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeServerStreamRequest(argument, metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ var stream = new ClientReadableStream(call, deserialize);
+ var start_batch = {};
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ start_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+ start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ call.startBatch(start_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('metadata', response.metadata);
+ });
+ var status_batch = {};
+ status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(status_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('status', response.status);
+ });
+ return stream;
}
- var call = new grpc.Call(channel, method, deadline);
- if (metadata) {
- call.addMetadata(metadata);
+ return makeServerStreamRequest;
+}
+
+/**
+ * Get a function that can make bidirectional stream requests to the specified
+ * method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeBidiStreamRequest
+ */
+function makeBidiStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a bidirectional stream request with this method on the given channel.
+ * @this {SurfaceClient} Client object. Must have a channel member.
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeBidiStreamRequest(metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ var stream = new ClientDuplexStream(call, serialize, deserialize);
+ var start_batch = {};
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ call.startBatch(start_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('metadata', response.metadata);
+ });
+ var status_batch = {};
+ status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(status_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('status', response.status);
+ });
+ return stream;
}
- return new GrpcClientStream(call, serialize, deserialize);
+ return makeBidiStreamRequest;
}
+
/**
- * See documentation for makeRequest above
+ * Map with short names for each of the requester maker functions. Used in
+ * makeClientConstructor
*/
-exports.makeRequest = makeRequest;
+var requester_makers = {
+ unary: makeUnaryRequestFunction,
+ server_stream: makeServerStreamRequestFunction,
+ client_stream: makeClientStreamRequestFunction,
+ bidi: makeBidiStreamRequestFunction
+};
/**
- * Represents a client side gRPC channel associated with a single host.
+ * Creates a constructor for clients for the given service
+ * @param {ProtoBuf.Reflect.Service} service The service to generate a client
+ * for
+ * @return {function(string, Object)} New client constructor
*/
-exports.Channel = grpc.Channel;
+function makeClientConstructor(service) {
+ var prefix = '/' + common.fullyQualifiedName(service) + '/';
+ /**
+ * Create a client with the given methods
+ * @constructor
+ * @param {string} address The address of the server to connect to
+ * @param {Object} options Options to pass to the underlying channel
+ */
+ function Client(address, options) {
+ this.channel = new grpc.Channel(address, options);
+ }
+
+ _.each(service.children, function(method) {
+ var method_type;
+ if (method.requestStream) {
+ if (method.responseStream) {
+ method_type = 'bidi';
+ } else {
+ method_type = 'client_stream';
+ }
+ } else {
+ if (method.responseStream) {
+ method_type = 'server_stream';
+ } else {
+ method_type = 'unary';
+ }
+ }
+ Client.prototype[decapitalize(method.name)] =
+ requester_makers[method_type](
+ prefix + capitalize(method.name),
+ common.serializeCls(method.resolvedRequestType.build()),
+ common.deserializeCls(method.resolvedResponseType.build()));
+ });
+
+ Client.service = service;
+
+ return Client;
+}
+
+exports.makeClientConstructor = makeClientConstructor;
+
/**
- * Status name to code number mapping
+ * See docs for client.status
*/
exports.status = grpc.status;
/**
- * Call error name to code number mapping
+ * See docs for client.callError
*/
exports.callError = grpc.callError;
diff --git a/src/node/src/common.js b/src/node/src/common.js
index 54247e3fa1..7560cf1bdd 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -31,6 +31,8 @@
*
*/
+var _ = require('underscore');
+
var capitalize = require('underscore.string/capitalize');
/**
@@ -88,6 +90,24 @@ function fullyQualifiedName(value) {
}
/**
+ * Wrap a function to pass null-like values through without calling it. If no
+ * function is given, just uses the identity;
+ * @param {?function} func The function to wrap
+ * @return {function} The wrapped function
+ */
+function wrapIgnoreNull(func) {
+ if (!func) {
+ return _.identity;
+ }
+ return function(arg) {
+ if (arg === null || arg === undefined) {
+ return null;
+ }
+ return func(arg);
+ };
+}
+
+/**
* See docs for deserializeCls
*/
exports.deserializeCls = deserializeCls;
@@ -101,3 +121,8 @@ exports.serializeCls = serializeCls;
* See docs for fullyQualifiedName
*/
exports.fullyQualifiedName = fullyQualifiedName;
+
+/**
+ * See docs for wrapIgnoreNull
+ */
+exports.wrapIgnoreNull = wrapIgnoreNull;
diff --git a/src/node/src/server.js b/src/node/src/server.js
index e4f71ff05f..48c349ef99 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,80 +33,108 @@
var _ = require('underscore');
+var capitalize = require('underscore.string/capitalize');
+var decapitalize = require('underscore.string/decapitalize');
+
var grpc = require('bindings')('grpc.node');
var common = require('./common');
-var Duplex = require('stream').Duplex;
+var stream = require('stream');
+
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+var Duplex = stream.Duplex;
var util = require('util');
-util.inherits(GrpcServerStream, Duplex);
+var EventEmitter = require('events').EventEmitter;
+
+var common = require('./common.js');
/**
- * Class for representing a gRPC server side stream as a Node stream. Extends
- * from stream.Duplex.
- * @constructor
- * @param {grpc.Call} call Call object to proxy
- * @param {function(*):Buffer=} serialize Serialization function for responses
- * @param {function(Buffer):*=} deserialize Deserialization function for
- * requests
+ * Handle an error on a call by sending it as a status
+ * @param {grpc.Call} call The call to send the error on
+ * @param {Object} error The error object
*/
-function GrpcServerStream(call, serialize, deserialize) {
- Duplex.call(this, {objectMode: true});
- if (!serialize) {
- serialize = function(value) {
- return value;
- };
- }
- if (!deserialize) {
- deserialize = function(value) {
- return value;
- };
- }
- this._call = call;
- // Indicate that a status has been sent
- var finished = false;
- var self = this;
+function handleError(call, error) {
var status = {
- 'code' : grpc.status.OK,
- 'details' : 'OK'
+ code: grpc.status.INTERNAL,
+ details: 'Unknown Error',
+ metadata: {}
};
-
- /**
- * Serialize a response value to a buffer. Always maps null to null. Otherwise
- * uses the provided serialize function
- * @param {*} value The value to serialize
- * @return {Buffer} The serialized value
- */
- this.serialize = function(value) {
- if (value === null || value === undefined) {
- return null;
+ if (error.hasOwnProperty('message')) {
+ status.details = error.message;
+ }
+ if (error.hasOwnProperty('code')) {
+ status.code = error.code;
+ if (error.hasOwnProperty('details')) {
+ status.details = error.details;
}
- return serialize(value);
- };
+ }
+ var error_batch = {};
+ error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
+ call.startBatch(error_batch, function(){});
+}
- /**
- * Deserialize a request buffer to a value. Always maps null to null.
- * Otherwise uses the provided deserialize function.
- * @param {Buffer} buffer The buffer to deserialize
- * @return {*} The deserialized value
- */
- this.deserialize = function(buffer) {
- if (buffer === null) {
- return null;
+/**
+ * Wait for the client to close, then emit a cancelled event if the client
+ * cancelled.
+ * @param {grpc.Call} call The call object to wait on
+ * @param {EventEmitter} emitter The event emitter to emit the cancelled event
+ * on
+ */
+function waitForCancel(call, emitter) {
+ var cancel_batch = {};
+ cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ call.startBatch(cancel_batch, function(err, result) {
+ if (err) {
+ emitter.emit('error', err);
}
- return deserialize(buffer);
+ if (result.cancelled) {
+ emitter.cancelled = true;
+ emitter.emit('cancelled');
+ }
+ });
+}
+
+/**
+ * Send a response to a unary or client streaming call.
+ * @param {grpc.Call} call The call to respond on
+ * @param {*} value The value to respond with
+ * @param {function(*):Buffer=} serialize Serialization function for the
+ * response
+ */
+function sendUnaryResponse(call, value, serialize) {
+ var end_batch = {};
+ end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
+ end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ code: grpc.status.OK,
+ details: 'OK',
+ metadata: {}
};
+ call.startBatch(end_batch, function (){});
+}
- /**
- * Send the pending status
- */
+/**
+ * Initialize a writable stream. This is used for both the writable and duplex
+ * stream constructors.
+ * @param {Writable} stream The stream to set up
+ * @param {function(*):Buffer=} Serialization function for responses
+ */
+function setUpWritable(stream, serialize) {
+ stream.finished = false;
+ stream.status = {
+ code : grpc.status.OK,
+ details : 'OK',
+ metadata : {}
+ };
+ stream.serialize = common.wrapIgnoreNull(serialize);
function sendStatus() {
- call.startWriteStatus(status.code, status.details, function() {
- });
- finished = true;
+ var batch = {};
+ batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status;
+ stream.call.startBatch(batch, function(){});
}
- this.on('finish', sendStatus);
+ stream.on('finish', sendStatus);
/**
* Set the pending status to a given error status. If the error does not have
* code or details properties, the code will be set to grpc.status.INTERNAL
@@ -116,14 +144,16 @@ function GrpcServerStream(call, serialize, deserialize) {
function setStatus(err) {
var code = grpc.status.INTERNAL;
var details = 'Unknown Error';
-
+ if (err.hasOwnProperty('message')) {
+ details = err.message;
+ }
if (err.hasOwnProperty('code')) {
code = err.code;
if (err.hasOwnProperty('details')) {
details = err.details;
}
}
- status = {'code': code, 'details': details};
+ stream.status = {code: code, details: details, metadata: {}};
}
/**
* Terminate the call. This includes indicating that reads are done, draining
@@ -133,69 +163,250 @@ function GrpcServerStream(call, serialize, deserialize) {
*/
function terminateCall(err) {
// Drain readable data
- this.on('data', function() {});
setStatus(err);
- this.end();
+ stream.end();
}
- this.on('error', terminateCall);
- // Indicates that a read is pending
- var reading = false;
+ stream.on('error', terminateCall);
+}
+
+/**
+ * Initialize a readable stream. This is used for both the readable and duplex
+ * stream constructors.
+ * @param {Readable} stream The stream to initialize
+ * @param {function(Buffer):*=} deserialize Deserialization function for
+ * incoming data.
+ */
+function setUpReadable(stream, deserialize) {
+ stream.deserialize = common.wrapIgnoreNull(deserialize);
+ stream.finished = false;
+ stream.reading = false;
+
+ stream.terminate = function() {
+ stream.finished = true;
+ stream.on('data', function() {});
+ };
+
+ stream.on('cancelled', function() {
+ stream.terminate();
+ });
+}
+
+util.inherits(ServerWritableStream, Writable);
+
+/**
+ * A stream that the server can write to. Used for calls that are streaming from
+ * the server side.
+ * @constructor
+ * @param {grpc.Call} call The call object to send data with
+ * @param {function(*):Buffer=} serialize Serialization function for writes
+ */
+function ServerWritableStream(call, serialize) {
+ Writable.call(this, {objectMode: true});
+ this.call = call;
+
+ this.finished = false;
+ setUpWritable(this, serialize);
+}
+
+/**
+ * Start writing a chunk of data. This is an implementation of a method required
+ * for implementing stream.Writable.
+ * @param {Buffer} chunk The chunk of data to write
+ * @param {string} encoding Ignored
+ * @param {function(Error=)} callback Callback to indicate that the write is
+ * complete
+ */
+function _write(chunk, encoding, callback) {
+ var batch = {};
+ batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+ this.call.startBatch(batch, function(err, value) {
+ if (err) {
+ this.emit('error', err);
+ return;
+ }
+ callback();
+ });
+}
+
+ServerWritableStream.prototype._write = _write;
+
+util.inherits(ServerReadableStream, Readable);
+
+/**
+ * A stream that the server can read from. Used for calls that are streaming
+ * from the client side.
+ * @constructor
+ * @param {grpc.Call} call The call object to read data with
+ * @param {function(Buffer):*=} deserialize Deserialization function for reads
+ */
+function ServerReadableStream(call, deserialize) {
+ Readable.call(this, {objectMode: true});
+ this.call = call;
+ setUpReadable(this, deserialize);
+}
+
+/**
+ * Start reading from the gRPC data source. This is an implementation of a
+ * method required for implementing stream.Readable
+ * @param {number} size Ignored
+ */
+function _read(size) {
+ var self = this;
/**
* Callback to be called when a READ event is received. Pushes the data onto
* the read queue and starts reading again if applicable
* @param {grpc.Event} event READ event object
*/
- function readCallback(event) {
- if (finished) {
+ function readCallback(err, event) {
+ if (err) {
+ self.terminate();
+ return;
+ }
+ if (self.finished) {
self.push(null);
return;
}
- var data = event.data;
+ var data = event.read;
if (self.push(self.deserialize(data)) && data != null) {
- self._call.startRead(readCallback);
+ var read_batch = {};
+ read_batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(read_batch, readCallback);
} else {
- reading = false;
+ self.reading = false;
}
}
- /**
- * Start reading if there is not already a pending read. Reading will
- * continue until self.push returns false (indicating reads should slow
- * down) or the read data is null (indicating that there is no more data).
- */
- this.startReading = function() {
- if (finished) {
- self.push(null);
- } else {
- if (!reading) {
- reading = true;
- self._call.startRead(readCallback);
+ if (self.finished) {
+ self.push(null);
+ } else {
+ if (!self.reading) {
+ self.reading = true;
+ var batch = {};
+ batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(batch, readCallback);
+ }
+ }
+}
+
+ServerReadableStream.prototype._read = _read;
+
+util.inherits(ServerDuplexStream, Duplex);
+
+/**
+ * A stream that the server can read from or write to. Used for calls with
+ * duplex streaming.
+ * @constructor
+ * @param {grpc.Call} call Call object to proxy
+ * @param {function(*):Buffer=} serialize Serialization function for requests
+ * @param {function(Buffer):*=} deserialize Deserialization function for
+ * responses
+ */
+function ServerDuplexStream(call, serialize, deserialize) {
+ Duplex.call(this, {objectMode: true});
+ this.call = call;
+ setUpWritable(this, serialize);
+ setUpReadable(this, deserialize);
+}
+
+ServerDuplexStream.prototype._read = _read;
+ServerDuplexStream.prototype._write = _write;
+
+/**
+ * Fully handle a unary call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
+ */
+function handleUnary(call, handler, metadata) {
+ var emitter = new EventEmitter();
+ emitter.on('error', function(error) {
+ handleError(call, error);
+ });
+ waitForCancel(call, emitter);
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ batch[grpc.opType.RECV_MESSAGE] = true;
+ call.startBatch(batch, function(err, result) {
+ if (err) {
+ handleError(call, err);
+ return;
+ }
+ emitter.request = handler.deserialize(result.read);
+ if (emitter.cancelled) {
+ return;
+ }
+ handler.func(emitter, function sendUnaryData(err, value) {
+ if (err) {
+ handleError(call, err);
}
+ sendUnaryResponse(call, value, handler.serialize);
+ });
+ });
+}
+
+/**
+ * Fully handle a server streaming call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
+ */
+function handleServerStreaming(call, handler, metadata) {
+ var stream = new ServerWritableStream(call, handler.serialize);
+ waitForCancel(call, stream);
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ batch[grpc.opType.RECV_MESSAGE] = true;
+ call.startBatch(batch, function(err, result) {
+ if (err) {
+ stream.emit('error', err);
+ return;
}
- };
+ stream.request = handler.deserialize(result.read);
+ handler.func(stream);
+ });
}
/**
- * Start reading from the gRPC data source. This is an implementation of a
- * method required for implementing stream.Readable
- * @param {number} size Ignored
+ * Fully handle a client streaming call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
*/
-GrpcServerStream.prototype._read = function(size) {
- this.startReading();
-};
+function handleClientStreaming(call, handler, metadata) {
+ var stream = new ServerReadableStream(call, handler.deserialize);
+ waitForCancel(call, stream);
+ var metadata_batch = {};
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ call.startBatch(metadata_batch, function() {});
+ handler.func(stream, function(err, value) {
+ stream.terminate();
+ if (err) {
+ handleError(call, err);
+ }
+ sendUnaryResponse(call, value, handler.serialize);
+ });
+}
/**
- * Start writing a chunk of data. This is an implementation of a method required
- * for implementing stream.Writable.
- * @param {Buffer} chunk The chunk of data to write
- * @param {string} encoding Ignored
- * @param {function(Error=)} callback Callback to indicate that the write is
- * complete
+ * Fully handle a bidirectional streaming call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
*/
-GrpcServerStream.prototype._write = function(chunk, encoding, callback) {
- var self = this;
- self._call.startWrite(self.serialize(chunk), function(event) {
- callback();
- }, 0);
+function handleBidiStreaming(call, handler, metadata) {
+ var stream = new ServerDuplexStream(call, handler.serialize,
+ handler.deserialize);
+ waitForCancel(call, stream);
+ var metadata_batch = {};
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ call.startBatch(metadata_batch, function() {});
+ handler.func(stream);
+}
+
+var streamHandlers = {
+ unary: handleUnary,
+ server_stream: handleServerStreaming,
+ client_stream: handleClientStreaming,
+ bidi: handleBidiStreaming
};
/**
@@ -218,7 +429,7 @@ function Server(getMetadata, options) {
* Start the server and begin handling requests
* @this Server
*/
- this.start = function() {
+ this.listen = function() {
console.log('Server starting');
_.each(handlers, function(handler, handler_name) {
console.log('Serving', handler_name);
@@ -233,48 +444,39 @@ function Server(getMetadata, options) {
* wait for the next request
* @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW
*/
- function handleNewCall(event) {
- var call = event.call;
- var data = event.data;
- if (data === null) {
+ function handleNewCall(err, event) {
+ if (err) {
+ return;
+ }
+ var details = event['new call'];
+ var call = details.call;
+ var method = details.method;
+ var metadata = details.metadata;
+ if (method === null) {
return;
}
server.requestCall(handleNewCall);
var handler = undefined;
- var deadline = data.absolute_deadline;
- var cancelled = false;
- call.serverAccept(function(event) {
- if (event.data.code === grpc.status.CANCELLED) {
- cancelled = true;
- if (stream) {
- stream.emit('cancelled');
- }
- }
- }, 0);
- if (handlers.hasOwnProperty(data.method)) {
- handler = handlers[data.method];
+ var deadline = details.deadline;
+ if (handlers.hasOwnProperty(method)) {
+ handler = handlers[method];
} else {
- call.serverEndInitialMetadata(0);
- call.startWriteStatus(
- grpc.status.UNIMPLEMENTED,
- "This method is not available on this server.",
- function() {});
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ code: grpc.status.UNIMPLEMENTED,
+ details: "This method is not available on this server.",
+ metadata: {}
+ };
+ batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ call.startBatch(batch, function() {});
return;
}
+ var response_metadata = {};
if (getMetadata) {
- call.addMetadata(getMetadata(data.method, data.metadata));
- }
- call.serverEndInitialMetadata(0);
- var stream = new GrpcServerStream(call, handler.serialize,
- handler.deserialize);
- Object.defineProperty(stream, 'cancelled', {
- get: function() { return cancelled;}
- });
- try {
- handler.func(stream, data.metadata);
- } catch (e) {
- stream.emit('error', e);
+ response_metadata = getMetadata(method, metadata);
}
+ streamHandlers[handler.type](call, handler, response_metadata);
}
server.requestCall(handleNewCall);
};
@@ -294,17 +496,20 @@ function Server(getMetadata, options) {
* returns a stream of response values
* @param {function(*):Buffer} serialize Serialization function for responses
* @param {function(Buffer):*} deserialize Deserialization function for requests
+ * @param {string} type The streaming type of method that this handles
* @return {boolean} True if the handler was set. False if a handler was already
* set for that name.
*/
-Server.prototype.register = function(name, handler, serialize, deserialize) {
+Server.prototype.register = function(name, handler, serialize, deserialize,
+ type) {
if (this.handlers.hasOwnProperty(name)) {
return false;
}
this.handlers[name] = {
func: handler,
serialize: serialize,
- deserialize: deserialize
+ deserialize: deserialize,
+ type: type
};
return true;
};
@@ -324,6 +529,110 @@ Server.prototype.bind = function(port, secure) {
};
/**
- * See documentation for Server
+ * Creates a constructor for servers with a service defined by the methods
+ * object. The methods object has string keys and values of this form:
+ * {serialize: function, deserialize: function, client_stream: bool,
+ * server_stream: bool}
+ * @param {Object} methods Method descriptor for each method the server should
+ * expose
+ * @param {string} prefix The prefex to prepend to each method name
+ * @return {function(Object, Object)} New server constructor
+ */
+function makeServerConstructor(services) {
+ var qual_names = [];
+ _.each(services, function(service) {
+ _.each(service.children, function(method) {
+ var name = common.fullyQualifiedName(method);
+ if (_.indexOf(qual_names, name) !== -1) {
+ throw new Error('Method ' + name + ' exposed by more than one service');
+ }
+ qual_names.push(name);
+ });
+ });
+ /**
+ * Create a server with the given handlers for all of the methods.
+ * @constructor
+ * @param {Object} service_handlers Map from service names to map from method
+ * names to handlers
+ * @param {function(string, Object<string, Array<Buffer>>):
+ Object<string, Array<Buffer|string>>=} getMetadata Callback that
+ * gets metatada for a given method
+ * @param {Object=} options Options to pass to the underlying server
+ */
+ function SurfaceServer(service_handlers, getMetadata, options) {
+ var server = new Server(getMetadata, options);
+ this.inner_server = server;
+ _.each(services, function(service) {
+ var service_name = common.fullyQualifiedName(service);
+ if (service_handlers[service_name] === undefined) {
+ throw new Error('Handlers for service ' +
+ service_name + ' not provided.');
+ }
+ var prefix = '/' + common.fullyQualifiedName(service) + '/';
+ _.each(service.children, function(method) {
+ var method_type;
+ if (method.requestStream) {
+ if (method.responseStream) {
+ method_type = 'bidi';
+ } else {
+ method_type = 'client_stream';
+ }
+ } else {
+ if (method.responseStream) {
+ method_type = 'server_stream';
+ } else {
+ method_type = 'unary';
+ }
+ }
+ if (service_handlers[service_name][decapitalize(method.name)] ===
+ undefined) {
+ throw new Error('Method handler for ' +
+ common.fullyQualifiedName(method) + ' not provided.');
+ }
+ var serialize = common.serializeCls(
+ method.resolvedResponseType.build());
+ var deserialize = common.deserializeCls(
+ method.resolvedRequestType.build());
+ server.register(
+ prefix + capitalize(method.name),
+ service_handlers[service_name][decapitalize(method.name)],
+ serialize, deserialize, method_type);
+ });
+ }, this);
+ }
+
+ /**
+ * Binds the server to the given port, with SSL enabled if secure is specified
+ * @param {string} port The port that the server should bind on, in the format
+ * "address:port"
+ * @param {boolean=} secure Whether the server should open a secure port
+ * @return {SurfaceServer} this
+ */
+ SurfaceServer.prototype.bind = function(port, secure) {
+ return this.inner_server.bind(port, secure);
+ };
+
+ /**
+ * Starts the server listening on any bound ports
+ * @return {SurfaceServer} this
+ */
+ SurfaceServer.prototype.listen = function() {
+ this.inner_server.listen();
+ return this;
+ };
+
+ /**
+ * Shuts the server down; tells it to stop listening for new requests and to
+ * kill old requests.
+ */
+ SurfaceServer.prototype.shutdown = function() {
+ this.inner_server.shutdown();
+ };
+
+ return SurfaceServer;
+}
+
+/**
+ * See documentation for makeServerConstructor
*/
-module.exports = Server;
+exports.makeServerConstructor = makeServerConstructor;
diff --git a/src/node/src/surface_client.js b/src/node/src/surface_client.js
deleted file mode 100644
index 16c31809f4..0000000000
--- a/src/node/src/surface_client.js
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- *
- * Copyright 2014, 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.
- *
- */
-
-var _ = require('underscore');
-
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
-var client = require('./client.js');
-
-var common = require('./common.js');
-
-var EventEmitter = require('events').EventEmitter;
-
-var stream = require('stream');
-
-var Readable = stream.Readable;
-var Writable = stream.Writable;
-var Duplex = stream.Duplex;
-var util = require('util');
-
-
-function forwardEvent(fromEmitter, toEmitter, event) {
- fromEmitter.on(event, function forward() {
- _.partial(toEmitter.emit, event).apply(toEmitter, arguments);
- });
-}
-
-util.inherits(ClientReadableObjectStream, Readable);
-
-/**
- * Class for representing a gRPC server streaming call as a Node stream on the
- * client side. Extends from stream.Readable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ClientReadableObjectStream(stream) {
- var options = {objectMode: true};
- Readable.call(this, options);
- this._stream = stream;
- var self = this;
- forwardEvent(stream, this, 'status');
- forwardEvent(stream, this, 'metadata');
- this._stream.on('data', function forwardData(chunk) {
- if (!self.push(chunk)) {
- self._stream.pause();
- }
- });
- this._stream.pause();
-}
-
-/**
- * _read implementation for both types of streams that allow reading.
- * @this {ClientReadableObjectStream}
- * @param {number} size Ignored
- */
-function _read(size) {
- this._stream.resume();
-}
-
-/**
- * See docs for _read
- */
-ClientReadableObjectStream.prototype._read = _read;
-
-util.inherits(ClientWritableObjectStream, Writable);
-
-/**
- * Class for representing a gRPC client streaming call as a Node stream on the
- * client side. Extends from stream.Writable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ClientWritableObjectStream(stream) {
- var options = {objectMode: true};
- Writable.call(this, options);
- this._stream = stream;
- forwardEvent(stream, this, 'status');
- forwardEvent(stream, this, 'metadata');
- this.on('finish', function() {
- this._stream.end();
- });
-}
-
-/**
- * _write implementation for both types of streams that allow writing
- * @this {ClientWritableObjectStream}
- * @param {*} chunk The value to write to the stream
- * @param {string} encoding Ignored
- * @param {function(Error)} callback Callback to call when finished writing
- */
-function _write(chunk, encoding, callback) {
- this._stream.write(chunk, encoding, callback);
-}
-
-/**
- * See docs for _write
- */
-ClientWritableObjectStream.prototype._write = _write;
-
-/**
- * Cancel the underlying call
- */
-function cancel() {
- this._stream.cancel();
-}
-
-ClientReadableObjectStream.prototype.cancel = cancel;
-ClientWritableObjectStream.prototype.cancel = cancel;
-
-/**
- * Get a function that can make unary requests to the specified method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeUnaryRequest
- */
-function makeUnaryRequestFunction(method, serialize, deserialize) {
- /**
- * Make a unary request with this method on the given channel with the given
- * argument, callback, etc.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {*} argument The argument to the call. Should be serializable with
- * serialize
- * @param {function(?Error, value=)} callback The callback to for when the
- * response is received
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeUnaryRequest(argument, callback, metadata, deadline) {
- var stream = client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- var emitter = new EventEmitter();
- emitter.cancel = function cancel() {
- stream.cancel();
- };
- forwardEvent(stream, emitter, 'status');
- forwardEvent(stream, emitter, 'metadata');
- stream.write(argument);
- stream.end();
- stream.on('data', function forwardData(chunk) {
- try {
- callback(null, chunk);
- } catch (e) {
- callback(e);
- }
- });
- stream.on('status', function forwardStatus(status) {
- if (status.code !== client.status.OK) {
- callback(status);
- }
- });
- return emitter;
- }
- return makeUnaryRequest;
-}
-
-/**
- * Get a function that can make client stream requests to the specified method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeClientStreamRequest
- */
-function makeClientStreamRequestFunction(method, serialize, deserialize) {
- /**
- * Make a client stream request with this method on the given channel with the
- * given callback, etc.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {function(?Error, value=)} callback The callback to for when the
- * response is received
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeClientStreamRequest(callback, metadata, deadline) {
- var stream = client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- var obj_stream = new ClientWritableObjectStream(stream);
- stream.on('data', function forwardData(chunk) {
- try {
- callback(null, chunk);
- } catch (e) {
- callback(e);
- }
- });
- stream.on('status', function forwardStatus(status) {
- if (status.code !== client.status.OK) {
- callback(status);
- }
- });
- return obj_stream;
- }
- return makeClientStreamRequest;
-}
-
-/**
- * Get a function that can make server stream requests to the specified method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeServerStreamRequest
- */
-function makeServerStreamRequestFunction(method, serialize, deserialize) {
- /**
- * Make a server stream request with this method on the given channel with the
- * given argument, etc.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {*} argument The argument to the call. Should be serializable with
- * serialize
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeServerStreamRequest(argument, metadata, deadline) {
- var stream = client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- var obj_stream = new ClientReadableObjectStream(stream);
- stream.write(argument);
- stream.end();
- return obj_stream;
- }
- return makeServerStreamRequest;
-}
-
-/**
- * Get a function that can make bidirectional stream requests to the specified
- * method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeBidiStreamRequest
- */
-function makeBidiStreamRequestFunction(method, serialize, deserialize) {
- /**
- * Make a bidirectional stream request with this method on the given channel.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeBidiStreamRequest(metadata, deadline) {
- return client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- }
- return makeBidiStreamRequest;
-}
-
-/**
- * Map with short names for each of the requester maker functions. Used in
- * makeClientConstructor
- */
-var requester_makers = {
- unary: makeUnaryRequestFunction,
- server_stream: makeServerStreamRequestFunction,
- client_stream: makeClientStreamRequestFunction,
- bidi: makeBidiStreamRequestFunction
-}
-
-/**
- * Creates a constructor for clients for the given service
- * @param {ProtoBuf.Reflect.Service} service The service to generate a client
- * for
- * @return {function(string, Object)} New client constructor
- */
-function makeClientConstructor(service) {
- var prefix = '/' + common.fullyQualifiedName(service) + '/';
- /**
- * Create a client with the given methods
- * @constructor
- * @param {string} address The address of the server to connect to
- * @param {Object} options Options to pass to the underlying channel
- */
- function SurfaceClient(address, options) {
- this.channel = new client.Channel(address, options);
- }
-
- _.each(service.children, function(method) {
- var method_type;
- if (method.requestStream) {
- if (method.responseStream) {
- method_type = 'bidi';
- } else {
- method_type = 'client_stream';
- }
- } else {
- if (method.responseStream) {
- method_type = 'server_stream';
- } else {
- method_type = 'unary';
- }
- }
- SurfaceClient.prototype[decapitalize(method.name)] =
- requester_makers[method_type](
- prefix + capitalize(method.name),
- common.serializeCls(method.resolvedRequestType.build()),
- common.deserializeCls(method.resolvedResponseType.build()));
- });
-
- SurfaceClient.service = service;
-
- return SurfaceClient;
-}
-
-exports.makeClientConstructor = makeClientConstructor;
-
-/**
- * See docs for client.status
- */
-exports.status = client.status;
-/**
- * See docs for client.callError
- */
-exports.callError = client.callError;
diff --git a/src/node/src/surface_server.js b/src/node/src/surface_server.js
deleted file mode 100644
index a47d1fa23d..0000000000
--- a/src/node/src/surface_server.js
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- *
- * Copyright 2014, 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.
- *
- */
-
-var _ = require('underscore');
-
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
-var Server = require('./server.js');
-
-var stream = require('stream');
-
-var Readable = stream.Readable;
-var Writable = stream.Writable;
-var Duplex = stream.Duplex;
-var util = require('util');
-
-var common = require('./common.js');
-
-util.inherits(ServerReadableObjectStream, Readable);
-
-/**
- * Class for representing a gRPC client streaming call as a Node stream on the
- * server side. Extends from stream.Readable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ServerReadableObjectStream(stream) {
- var options = {objectMode: true};
- Readable.call(this, options);
- this._stream = stream;
- Object.defineProperty(this, 'cancelled', {
- get: function() { return stream.cancelled; }
- });
- var self = this;
- this._stream.on('cancelled', function() {
- self.emit('cancelled');
- });
- this._stream.on('data', function forwardData(chunk) {
- if (!self.push(chunk)) {
- self._stream.pause();
- }
- });
- this._stream.on('end', function forwardEnd() {
- self.push(null);
- });
- this._stream.pause();
-}
-
-/**
- * _read implementation for both types of streams that allow reading.
- * @this {ServerReadableObjectStream|ServerBidiObjectStream}
- * @param {number} size Ignored
- */
-function _read(size) {
- this._stream.resume();
-}
-
-/**
- * See docs for _read
- */
-ServerReadableObjectStream.prototype._read = _read;
-
-util.inherits(ServerWritableObjectStream, Writable);
-
-/**
- * Class for representing a gRPC server streaming call as a Node stream on the
- * server side. Extends from stream.Writable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ServerWritableObjectStream(stream) {
- var options = {objectMode: true};
- Writable.call(this, options);
- this._stream = stream;
- this._stream.on('cancelled', function() {
- self.emit('cancelled');
- });
- this.on('finish', function() {
- this._stream.end();
- });
-}
-
-/**
- * _write implementation for both types of streams that allow writing
- * @this {ServerWritableObjectStream}
- * @param {*} chunk The value to write to the stream
- * @param {string} encoding Ignored
- * @param {function(Error)} callback Callback to call when finished writing
- */
-function _write(chunk, encoding, callback) {
- this._stream.write(chunk, encoding, callback);
-}
-
-/**
- * See docs for _write
- */
-ServerWritableObjectStream.prototype._write = _write;
-
-/**
- * Creates a binary stream handler function from a unary handler function
- * @param {function(Object, function(Error, *), metadata=)} handler Unary call
- * handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeUnaryHandler(handler) {
- /**
- * Handles a stream by reading a single data value, passing it to the handler,
- * and writing the response back to the stream.
- * @param {stream} stream Binary data stream
- * @param {metadata=} metadata Incoming metadata array
- */
- return function handleUnaryCall(stream, metadata) {
- stream.on('data', function handleUnaryData(value) {
- var call = {request: value};
- Object.defineProperty(call, 'cancelled', {
- get: function() { return stream.cancelled;}
- });
- stream.on('cancelled', function() {
- call.emit('cancelled');
- });
- handler(call, function sendUnaryData(err, value) {
- if (err) {
- stream.emit('error', err);
- } else {
- stream.write(value);
- stream.end();
- }
- }, metadata);
- });
- };
-}
-
-/**
- * Creates a binary stream handler function from a client stream handler
- * function
- * @param {function(Readable, function(Error, *), metadata=)} handler Client
- * stream call handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeClientStreamHandler(handler) {
- /**
- * Handles a stream by passing a deserializing stream to the handler and
- * writing the response back to the stream.
- * @param {stream} stream Binary data stream
- * @param {metadata=} metadata Incoming metadata array
- */
- return function handleClientStreamCall(stream, metadata) {
- var object_stream = new ServerReadableObjectStream(stream);
- handler(object_stream, function sendClientStreamData(err, value) {
- if (err) {
- stream.emit('error', err);
- } else {
- stream.write(value);
- stream.end();
- }
- }, metadata);
- };
-}
-
-/**
- * Creates a binary stream handler function from a server stream handler
- * function
- * @param {function(Writable, metadata=)} handler Server stream call handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeServerStreamHandler(handler) {
- /**
- * Handles a stream by attaching it to a serializing stream, and passing it to
- * the handler.
- * @param {stream} stream Binary data stream
- * @param {metadata=} metadata Incoming metadata array
- */
- return function handleServerStreamCall(stream, metadata) {
- stream.on('data', function handleClientData(value) {
- var object_stream = new ServerWritableObjectStream(stream);
- object_stream.request = value;
- handler(object_stream, metadata);
- });
- };
-}
-
-/**
- * Creates a binary stream handler function from a bidi stream handler function
- * @param {function(Duplex, metadata=)} handler Unary call handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeBidiStreamHandler(handler) {
- return handler;
-}
-
-/**
- * Map with short names for each of the handler maker functions. Used in
- * makeServerConstructor
- */
-var handler_makers = {
- unary: makeUnaryHandler,
- server_stream: makeServerStreamHandler,
- client_stream: makeClientStreamHandler,
- bidi: makeBidiStreamHandler
-};
-
-/**
- * Creates a constructor for servers with a service defined by the methods
- * object. The methods object has string keys and values of this form:
- * {serialize: function, deserialize: function, client_stream: bool,
- * server_stream: bool}
- * @param {Object} methods Method descriptor for each method the server should
- * expose
- * @param {string} prefix The prefex to prepend to each method name
- * @return {function(Object, Object)} New server constructor
- */
-function makeServerConstructor(services) {
- var qual_names = [];
- _.each(services, function(service) {
- _.each(service.children, function(method) {
- var name = common.fullyQualifiedName(method);
- if (_.indexOf(qual_names, name) !== -1) {
- throw new Error('Method ' + name + ' exposed by more than one service');
- }
- qual_names.push(name);
- });
- });
- /**
- * Create a server with the given handlers for all of the methods.
- * @constructor
- * @param {Object} service_handlers Map from service names to map from method
- * names to handlers
- * @param {function(string, Object<string, Array<Buffer>>):
- Object<string, Array<Buffer|string>>=} getMetadata Callback that
- * gets metatada for a given method
- * @param {Object=} options Options to pass to the underlying server
- */
- function SurfaceServer(service_handlers, getMetadata, options) {
- var server = new Server(getMetadata, options);
- this.inner_server = server;
- _.each(services, function(service) {
- var service_name = common.fullyQualifiedName(service);
- if (service_handlers[service_name] === undefined) {
- throw new Error('Handlers for service ' +
- service_name + ' not provided.');
- }
- var prefix = '/' + common.fullyQualifiedName(service) + '/';
- _.each(service.children, function(method) {
- var method_type;
- if (method.requestStream) {
- if (method.responseStream) {
- method_type = 'bidi';
- } else {
- method_type = 'client_stream';
- }
- } else {
- if (method.responseStream) {
- method_type = 'server_stream';
- } else {
- method_type = 'unary';
- }
- }
- if (service_handlers[service_name][decapitalize(method.name)] ===
- undefined) {
- throw new Error('Method handler for ' +
- common.fullyQualifiedName(method) + ' not provided.');
- }
- var binary_handler = handler_makers[method_type](
- service_handlers[service_name][decapitalize(method.name)]);
- var serialize = common.serializeCls(
- method.resolvedResponseType.build());
- var deserialize = common.deserializeCls(
- method.resolvedRequestType.build());
- server.register(prefix + capitalize(method.name), binary_handler,
- serialize, deserialize);
- });
- }, this);
- }
-
- /**
- * Binds the server to the given port, with SSL enabled if secure is specified
- * @param {string} port The port that the server should bind on, in the format
- * "address:port"
- * @param {boolean=} secure Whether the server should open a secure port
- * @return {SurfaceServer} this
- */
- SurfaceServer.prototype.bind = function(port, secure) {
- return this.inner_server.bind(port, secure);
- };
-
- /**
- * Starts the server listening on any bound ports
- * @return {SurfaceServer} this
- */
- SurfaceServer.prototype.listen = function() {
- this.inner_server.start();
- return this;
- };
-
- /**
- * Shuts the server down; tells it to stop listening for new requests and to
- * kill old requests.
- */
- SurfaceServer.prototype.shutdown = function() {
- this.inner_server.shutdown();
- };
-
- return SurfaceServer;
-}
-
-/**
- * See documentation for makeServerConstructor
- */
-exports.makeServerConstructor = makeServerConstructor;
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index 48db245498..c1a7e95fa0 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -98,100 +98,80 @@ describe('call', function() {
}, TypeError);
});
});
- describe('addMetadata', function() {
- it('should succeed with a map from strings to string arrays', function() {
+ describe('startBatch', function() {
+ it('should fail without an object and a function', function() {
var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.doesNotThrow(function() {
- call.addMetadata({'key': ['value']});
+ assert.throws(function() {
+ call.startBatch();
});
- assert.doesNotThrow(function() {
- call.addMetadata({'key1': ['value1'], 'key2': ['value2']});
+ assert.throws(function() {
+ call.startBatch({});
+ });
+ assert.throws(function() {
+ call.startBatch(null, function(){});
});
});
- it('should succeed with a map from strings to buffer arrays', function() {
+ it('should succeed with an empty object', function(done) {
var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.doesNotThrow(function() {
- call.addMetadata({'key': [new Buffer('value')]});
- });
- assert.doesNotThrow(function() {
- call.addMetadata({'key1': [new Buffer('value1')],
- 'key2': [new Buffer('value2')]});
+ call.startBatch({}, function(err) {
+ assert.ifError(err);
+ done();
+ });
});
});
- it('should fail with other parameter types', function() {
+ });
+ describe('startBatch with metadata', function() {
+ it('should succeed with a map of strings to string arrays', function(done) {
var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.throws(function() {
- call.addMetadata();
+ assert.doesNotThrow(function() {
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = {'key1': ['value1'],
+ 'key2': ['value2']};
+ call.startBatch(batch, function(err, resp) {
+ assert.ifError(err);
+ assert.deepEqual(resp, {'send metadata': true});
+ done();
+ });
});
- assert.throws(function() {
- call.addMetadata(null);
- }, TypeError);
- assert.throws(function() {
- call.addMetadata('value');
- }, TypeError);
- assert.throws(function() {
- call.addMetadata(5);
- }, TypeError);
});
- it.skip('should fail if invoke was already called', function(done) {
+ it('should succeed with a map of strings to buffer arrays', function(done) {
var call = new grpc.Call(channel, 'method', getDeadline(1));
- call.invoke(function() {},
- function() {done();},
- 0);
- assert.throws(function() {
- call.addMetadata({'key': ['value']});
+ assert.doesNotThrow(function() {
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = {
+ 'key1': [new Buffer('value1')],
+ 'key2': [new Buffer('value2')]
+ };
+ call.startBatch(batch, function(err, resp) {
+ assert.ifError(err);
+ assert.deepEqual(resp, {'send metadata': true});
+ done();
+ });
});
- // Cancel to speed up the test
- call.cancel();
});
- });
- describe('invoke', function() {
- it('should fail with fewer than 3 arguments', function() {
+ it('should fail with other parameter types', function() {
var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.throws(function() {
- call.invoke();
- }, TypeError);
- assert.throws(function() {
- call.invoke(function() {});
- }, TypeError);
- assert.throws(function() {
- call.invoke(function() {},
- function() {});
- }, TypeError);
- });
- it('should work with 2 args and an int', function(done) {
- assert.doesNotThrow(function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- call.invoke(function() {},
- function() {done();},
- 0);
- // Cancel to speed up the test
- call.cancel();
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = undefined;
+ call.startBatch(batch, function(){});
});
- });
- it('should reject incorrectly typed arguments', function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.throws(function() {
- call.invoke(0, 0, 0);
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = null;
+ call.startBatch(batch, function(){});
}, TypeError);
assert.throws(function() {
- call.invoke(function() {},
- function() {}, 'test');
- });
- });
- });
- describe('serverAccept', function() {
- it('should fail with fewer than 1 argument1', function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.throws(function() {
- call.serverAccept();
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = 'value';
+ call.startBatch(batch, function(){});
}, TypeError);
- });
- it.skip('should return an error when called on a client Call', function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.throws(function() {
- call.serverAccept(function() {});
- });
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = 5;
+ call.startBatch(batch, function(){});
+ }, TypeError);
});
});
describe('cancel', function() {
diff --git a/src/node/test/client_server_test.js b/src/node/test/client_server_test.js
deleted file mode 100644
index 1db9f69467..0000000000
--- a/src/node/test/client_server_test.js
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- *
- * Copyright 2014, 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.
- *
- */
-
-var assert = require('assert');
-var fs = require('fs');
-var path = require('path');
-var grpc = require('bindings')('grpc.node');
-var Server = require('../src/server');
-var client = require('../src/client');
-var common = require('../src/common');
-
-var ca_path = path.join(__dirname, 'data/ca.pem');
-
-var key_path = path.join(__dirname, 'data/server1.key');
-
-var pem_path = path.join(__dirname, 'data/server1.pem');
-
-/**
- * Helper function to return an absolute deadline given a relative timeout in
- * seconds.
- * @param {number} timeout_secs The number of seconds to wait before timing out
- * @return {Date} A date timeout_secs in the future
- */
-function getDeadline(timeout_secs) {
- var deadline = new Date();
- deadline.setSeconds(deadline.getSeconds() + timeout_secs);
- return deadline;
-}
-
-/**
- * Responds to every request with the same data as a response
- * @param {Stream} stream
- */
-function echoHandler(stream) {
- stream.pipe(stream);
-}
-
-/**
- * Responds to every request with an error status
- * @param {Stream} stream
- */
-function errorHandler(stream) {
- throw {
- 'code' : grpc.status.UNIMPLEMENTED,
- 'details' : 'error details'
- };
-}
-
-/**
- * Wait for a cancellation instead of responding
- * @param {Stream} stream
- */
-function cancelHandler(stream) {
- // do nothing
-}
-
-function metadataHandler(stream, metadata) {
- stream.end();
-}
-
-/**
- * Serialize a string to a Buffer
- * @param {string} value The string to serialize
- * @return {Buffer} The serialized value
- */
-function stringSerialize(value) {
- return new Buffer(value);
-}
-
-/**
- * Deserialize a Buffer to a string
- * @param {Buffer} buffer The buffer to deserialize
- * @return {string} The string value of the buffer
- */
-function stringDeserialize(buffer) {
- return buffer.toString();
-}
-
-describe('echo client', function() {
- var server;
- var channel;
- before(function() {
- server = new Server(function getMetadata(method, metadata) {
- return {method: [method]};
- });
- var port_num = server.bind('0.0.0.0:0');
- server.register('echo', echoHandler);
- server.register('error', errorHandler);
- server.register('cancellation', cancelHandler);
- server.register('metadata', metadataHandler);
- server.start();
-
- channel = new grpc.Channel('localhost:' + port_num);
- });
- after(function() {
- server.shutdown();
- });
- it('should receive echo responses', function(done) {
- var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
- var stream = client.makeRequest(
- channel,
- 'echo',
- stringSerialize,
- stringDeserialize);
- for (var i = 0; i < messages.length; i++) {
- stream.write(messages[i]);
- }
- stream.end();
- var index = 0;
- stream.on('data', function(chunk) {
- assert.equal(messages[index], chunk);
- index += 1;
- });
- stream.on('status', function(status) {
- assert.equal(status.code, client.status.OK);
- });
- stream.on('end', function() {
- assert.equal(index, messages.length);
- done();
- });
- });
- it('should recieve metadata set by the server', function(done) {
- var stream = client.makeRequest(channel, 'metadata');
- stream.on('metadata', function(metadata) {
- assert.strictEqual(metadata.method[0].toString(), 'metadata');
- });
- stream.on('status', function(status) {
- assert.equal(status.code, client.status.OK);
- done();
- });
- stream.end();
- });
- it('should get an error status that the server throws', function(done) {
- var stream = client.makeRequest(channel, 'error');
-
- stream.on('data', function() {});
- stream.write(new Buffer('test'));
- stream.end();
- stream.on('status', function(status) {
- assert.equal(status.code, grpc.status.UNIMPLEMENTED);
- assert.equal(status.details, 'error details');
- done();
- });
- });
- it('should be able to cancel a call', function(done) {
- var stream = client.makeRequest(
- channel,
- 'cancellation',
- null,
- getDeadline(1));
-
- stream.cancel();
- stream.on('status', function(status) {
- assert.equal(status.code, grpc.status.CANCELLED);
- done();
- });
- });
- it('should get correct status for unimplemented method', function(done) {
- var stream = client.makeRequest(channel, 'unimplemented_method');
- stream.end();
- stream.on('status', function(status) {
- assert.equal(status.code, grpc.status.UNIMPLEMENTED);
- done();
- });
- });
-});
-/* TODO(mlumish): explore options for reducing duplication between this test
- * and the insecure echo client test */
-describe('secure echo client', function() {
- var server;
- var channel;
- before(function(done) {
- fs.readFile(ca_path, function(err, ca_data) {
- assert.ifError(err);
- fs.readFile(key_path, function(err, key_data) {
- assert.ifError(err);
- fs.readFile(pem_path, function(err, pem_data) {
- assert.ifError(err);
- var creds = grpc.Credentials.createSsl(ca_data);
- var server_creds = grpc.ServerCredentials.createSsl(null,
- key_data,
- pem_data);
-
- server = new Server(null, {'credentials' : server_creds});
- var port_num = server.bind('0.0.0.0:0', true);
- server.register('echo', echoHandler);
- server.start();
-
- channel = new grpc.Channel('localhost:' + port_num, {
- 'grpc.ssl_target_name_override' : 'foo.test.google.com',
- 'credentials' : creds
- });
- done();
- });
- });
- });
- });
- after(function() {
- server.shutdown();
- });
- it('should recieve echo responses', function(done) {
- var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
- var stream = client.makeRequest(
- channel,
- 'echo',
- stringSerialize,
- stringDeserialize);
- for (var i = 0; i < messages.length; i++) {
- stream.write(messages[i]);
- }
- stream.end();
- var index = 0;
- stream.on('data', function(chunk) {
- assert.equal(messages[index], chunk);
- index += 1;
- });
- stream.on('status', function(status) {
- assert.equal(status.code, client.status.OK);
- });
- stream.on('end', function() {
- assert.equal(index, messages.length);
- done();
- });
- });
-});
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
index 0138a55226..4d11e6f527 100644
--- a/src/node/test/constant_test.js
+++ b/src/node/test/constant_test.js
@@ -76,31 +76,6 @@ var callErrorNames = [
'INVALID_FLAGS'
];
-/**
- * List of all op error names
- * @const
- * @type {Array.<string>}
- */
-var opErrorNames = [
- 'OK',
- 'ERROR'
-];
-
-/**
- * List of all completion type names
- * @const
- * @type {Array.<string>}
- */
-var completionTypeNames = [
- 'QUEUE_SHUTDOWN',
- 'READ',
- 'WRITE_ACCEPTED',
- 'FINISH_ACCEPTED',
- 'CLIENT_METADATA_READ',
- 'FINISHED',
- 'SERVER_RPC_NEW'
-];
-
describe('constants', function() {
it('should have all of the status constants', function() {
for (var i = 0; i < statusNames.length; i++) {
@@ -114,16 +89,4 @@ describe('constants', function() {
'call error missing: ' + callErrorNames[i]);
}
});
- it('should have all of the op errors', function() {
- for (var i = 0; i < opErrorNames.length; i++) {
- assert(grpc.opError.hasOwnProperty(opErrorNames[i]),
- 'op error missing: ' + opErrorNames[i]);
- }
- });
- it('should have all of the completion types', function() {
- for (var i = 0; i < completionTypeNames.length; i++) {
- assert(grpc.completionType.hasOwnProperty(completionTypeNames[i]),
- 'completion type missing: ' + completionTypeNames[i]);
- }
- });
});
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 1f53df23f3..f8899beae8 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -74,40 +74,49 @@ describe('end-to-end', function() {
var status_text = 'xyz';
var call = new grpc.Call(channel,
'dummy_method',
- deadline);
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
+ Infinity);
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ assert.ifError(err);
+ assert.deepEqual(response, {
+ 'send metadata': true,
+ 'client close': true,
+ 'metadata': {},
+ 'status': {
+ 'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}
+ }
+ });
done();
- }, 0);
+ });
- server.requestCall(function(event) {
- assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
- var server_call = event.call;
+ server.requestCall(function(err, call_details) {
+ var new_call = call_details['new call'];
+ assert.notEqual(new_call, null);
+ var server_call = new_call.call;
assert.notEqual(server_call, null);
- server_call.serverAccept(function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- }, 0);
- server_call.serverEndInitialMetadata(0);
- server_call.startWriteStatus(
- grpc.status.OK,
- status_text,
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- });
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
+ var server_batch = {};
+ server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ 'metadata': {},
+ 'code': grpc.status.OK,
+ 'details': status_text
+ };
+ server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ server_call.startBatch(server_batch, function(err, response) {
+ assert.ifError(err);
+ assert.deepEqual(response, {
+ 'send metadata': true,
+ 'send status': true,
+ 'cancelled': false
+ });
+ done();
+ });
});
});
it('should successfully send and receive metadata', function(complete) {
@@ -117,115 +126,110 @@ describe('end-to-end', function() {
var status_text = 'xyz';
var call = new grpc.Call(channel,
'dummy_method',
- deadline);
- call.addMetadata({'client_key': ['client_value']});
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- assert.strictEqual(event.data.server_key[0].toString(), 'server_value');
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
+ Infinity);
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = {
+ 'client_key': ['client_value']
+ };
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send metadata']);
+ assert(response['client close']);
+ assert(response.hasOwnProperty('metadata'));
+ assert.strictEqual(response.metadata.server_key[0].toString(),
+ 'server_value');
+ assert.deepEqual(response.status, {'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}});
done();
- }, 0);
+ });
- server.requestCall(function(event) {
- assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
- assert.strictEqual(event.data.metadata.client_key[0].toString(),
+ server.requestCall(function(err, call_details) {
+ var new_call = call_details['new call'];
+ assert.notEqual(new_call, null);
+ assert.strictEqual(new_call.metadata.client_key[0].toString(),
'client_value');
- var server_call = event.call;
+ var server_call = new_call.call;
assert.notEqual(server_call, null);
- server_call.serverAccept(function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- }, 0);
- server_call.addMetadata({'server_key': ['server_value']});
- server_call.serverEndInitialMetadata(0);
- server_call.startWriteStatus(
- grpc.status.OK,
- status_text,
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- });
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
+ var server_batch = {};
+ server_batch[grpc.opType.SEND_INITIAL_METADATA] = {
+ 'server_key': ['server_value']
+ };
+ server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ 'metadata': {},
+ 'code': grpc.status.OK,
+ 'details': status_text
+ };
+ server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ server_call.startBatch(server_batch, function(err, response) {
+ assert.ifError(err);
+ assert.deepEqual(response, {
+ 'send metadata': true,
+ 'send status': true,
+ 'cancelled': false
+ });
+ done();
+ });
});
});
it('should send and receive data without error', function(complete) {
var req_text = 'client_request';
var reply_text = 'server_response';
- var done = multiDone(complete, 6);
+ var done = multiDone(complete, 2);
var deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 3);
var status_text = 'success';
var call = new grpc.Call(channel,
'dummy_method',
- deadline);
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- done();
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
- done();
- }, 0);
- call.startWrite(
- new Buffer(req_text),
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.WRITE_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- }, 0);
- call.startRead(function(event) {
- assert.strictEqual(event.type, grpc.completionType.READ);
- assert.strictEqual(event.data.toString(), reply_text);
+ Infinity);
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ client_batch[grpc.opType.SEND_MESSAGE] = new Buffer(req_text);
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send metadata']);
+ assert(response['client close']);
+ assert.deepEqual(response.metadata, {});
+ assert(response['send message']);
+ assert.strictEqual(response.read.toString(), reply_text);
+ assert.deepEqual(response.status, {'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}});
done();
});
- server.requestCall(function(event) {
- assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
- var server_call = event.call;
+
+ server.requestCall(function(err, call_details) {
+ var new_call = call_details['new call'];
+ assert.notEqual(new_call, null);
+ var server_call = new_call.call;
assert.notEqual(server_call, null);
- server_call.serverAccept(function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- done();
- });
- server_call.serverEndInitialMetadata(0);
- server_call.startRead(function(event) {
- assert.strictEqual(event.type, grpc.completionType.READ);
- assert.strictEqual(event.data.toString(), req_text);
- server_call.startWrite(
- new Buffer(reply_text),
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.WRITE_ACCEPTED);
- assert.strictEqual(event.data,
- grpc.opError.OK);
- server_call.startWriteStatus(
- grpc.status.OK,
- status_text,
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- }, 0);
+ var server_batch = {};
+ server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ server_batch[grpc.opType.RECV_MESSAGE] = true;
+ server_call.startBatch(server_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send metadata']);
+ assert.strictEqual(response.read.toString(), req_text);
+ var response_batch = {};
+ response_batch[grpc.opType.SEND_MESSAGE] = new Buffer(reply_text);
+ response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ 'metadata': {},
+ 'code': grpc.status.OK,
+ 'details': status_text
+ };
+ response_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ server_call.startBatch(response_batch, function(err, response) {
+ assert(response['send status']);
+ assert(!response['cancelled']);
+ done();
+ });
});
});
});
diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js
index 7ecaad833d..81cd9fa5b9 100644
--- a/src/node/test/interop_sanity_test.js
+++ b/src/node/test/interop_sanity_test.js
@@ -56,7 +56,7 @@ describe('Interop tests', function() {
interop_client.runTest(port, name_override, 'empty_unary', true, done);
});
// This fails due to an unknown bug
- it.skip('should pass large_unary', function(done) {
+ it('should pass large_unary', function(done) {
interop_client.runTest(port, name_override, 'large_unary', true, done);
});
it('should pass client_streaming', function(done) {
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index 0e365bf870..61b4a2fa2f 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -63,9 +63,6 @@ describe('Math client', function() {
assert.ifError(err);
assert.equal(value.quotient, 1);
assert.equal(value.remainder, 3);
- });
- call.on('status', function checkStatus(status) {
- assert.strictEqual(status.code, grpc.status.OK);
done();
});
});
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
deleted file mode 100644
index a3e1edf50f..0000000000
--- a/src/node/test/server_test.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- *
- * Copyright 2014, 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.
- *
- */
-
-var assert = require('assert');
-var grpc = require('bindings')('grpc.node');
-var Server = require('../src/server');
-
-/**
- * This is used for testing functions with multiple asynchronous calls that
- * can happen in different orders. This should be passed the number of async
- * function invocations that can occur last, and each of those should call this
- * function's return value
- * @param {function()} done The function that should be called when a test is
- * complete.
- * @param {number} count The number of calls to the resulting function if the
- * test passes.
- * @return {function()} The function that should be called at the end of each
- * sequence of asynchronous functions.
- */
-function multiDone(done, count) {
- return function() {
- count -= 1;
- if (count <= 0) {
- done();
- }
- };
-}
-
-/**
- * Responds to every request with the same data as a response
- * @param {Stream} stream
- */
-function echoHandler(stream) {
- stream.pipe(stream);
-}
-
-describe('echo server', function() {
- var server;
- var channel;
- before(function() {
- server = new Server();
- var port_num = server.bind('[::]:0');
- server.register('echo', echoHandler);
- server.start();
-
- channel = new grpc.Channel('localhost:' + port_num);
- });
- after(function() {
- server.shutdown();
- });
- it('should echo inputs as responses', function(done) {
- done = multiDone(done, 4);
-
- var req_text = 'echo test string';
- var status_text = 'OK';
-
- var deadline = new Date();
- deadline.setSeconds(deadline.getSeconds() + 3);
- var call = new grpc.Call(channel,
- 'echo',
- deadline);
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- done();
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
- done();
- }, 0);
- call.startWrite(
- new Buffer(req_text),
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.WRITE_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- }, 0);
- call.startRead(function(event) {
- assert.strictEqual(event.type, grpc.completionType.READ);
- assert.strictEqual(event.data.toString(), req_text);
- done();
- });
- });
-});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 1038f9ab33..34e4ab4013 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -33,9 +33,9 @@
var assert = require('assert');
-var surface_server = require('../src/surface_server.js');
+var surface_server = require('../src/server.js');
-var surface_client = require('../src/surface_client.js');
+var surface_client = require('../src/client.js');
var ProtoBuf = require('protobufjs');
diff --git a/src/python/interop/interop/__init__.py b/src/python/interop/interop/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/python/interop/interop/__init__.py
diff --git a/src/python/interop/interop/credentials/README b/src/python/interop/interop/credentials/README
new file mode 100755
index 0000000000..cb20dcb49f
--- /dev/null
+++ b/src/python/interop/interop/credentials/README
@@ -0,0 +1 @@
+These are test keys *NOT* to be used in production.
diff --git a/src/python/interop/interop/credentials/server1.key b/src/python/interop/interop/credentials/server1.key
new file mode 100755
index 0000000000..143a5b8765
--- /dev/null
+++ b/src/python/interop/interop/credentials/server1.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
+M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
+3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
+AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
+V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
+tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
+dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
+K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
+81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
+DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
+aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
+ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
+XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
+F98XJ7tIFfJq
+-----END PRIVATE KEY-----
diff --git a/src/python/interop/interop/credentials/server1.pem b/src/python/interop/interop/credentials/server1.pem
new file mode 100755
index 0000000000..8e582e571f
--- /dev/null
+++ b/src/python/interop/interop/credentials/server1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
+MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
+c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
+JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
+RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
+3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
+BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
+b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
+KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
+wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
+aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+-----END CERTIFICATE-----
diff --git a/src/python/interop/interop/empty_pb2.py b/src/python/interop/interop/empty_pb2.py
new file mode 100644
index 0000000000..753341c7da
--- /dev/null
+++ b/src/python/interop/interop/empty_pb2.py
@@ -0,0 +1,60 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/cpp/interop/empty.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='test/cpp/interop/empty.proto',
+ package='grpc.testing',
+ serialized_pb=_b('\n\x1ctest/cpp/interop/empty.proto\x12\x0cgrpc.testing\"\x07\n\x05\x45mpty')
+)
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+
+
+
+_EMPTY = _descriptor.Descriptor(
+ name='Empty',
+ full_name='grpc.testing.Empty',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=46,
+ serialized_end=53,
+)
+
+DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
+
+Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), dict(
+ DESCRIPTOR = _EMPTY,
+ __module__ = 'test.cpp.interop.empty_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.Empty)
+ ))
+_sym_db.RegisterMessage(Empty)
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/messages_pb2.py b/src/python/interop/interop/messages_pb2.py
new file mode 100644
index 0000000000..79270cdf12
--- /dev/null
+++ b/src/python/interop/interop/messages_pb2.py
@@ -0,0 +1,444 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/cpp/interop/messages.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='test/cpp/interop/messages.proto',
+ package='grpc.testing',
+ serialized_pb=_b('\n\x1ftest/cpp/interop/messages.proto\x12\x0cgrpc.testing\"@\n\x07Payload\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x0c\n\x04\x62ody\x18\x02 \x01(\x0c\"\xb1\x01\n\rSimpleRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x15\n\rresponse_size\x18\x02 \x01(\x05\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x15\n\rfill_username\x18\x04 \x01(\x08\x12\x18\n\x10\x66ill_oauth_scope\x18\x05 \x01(\x08\"_\n\x0eSimpleResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x13\n\x0boauth_scope\x18\x03 \x01(\t\"C\n\x19StreamingInputCallRequest\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\"=\n\x1aStreamingInputCallResponse\x12\x1f\n\x17\x61ggregated_payload_size\x18\x01 \x01(\x05\"7\n\x12ResponseParameters\x12\x0c\n\x04size\x18\x01 \x01(\x05\x12\x13\n\x0binterval_us\x18\x02 \x01(\x05\"\xb5\x01\n\x1aStreamingOutputCallRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12=\n\x13response_parameters\x18\x02 \x03(\x0b\x32 .grpc.testing.ResponseParameters\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\"E\n\x1bStreamingOutputCallResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload*?\n\x0bPayloadType\x12\x10\n\x0c\x43OMPRESSABLE\x10\x00\x12\x12\n\x0eUNCOMPRESSABLE\x10\x01\x12\n\n\x06RANDOM\x10\x02')
+)
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+_PAYLOADTYPE = _descriptor.EnumDescriptor(
+ name='PayloadType',
+ full_name='grpc.testing.PayloadType',
+ filename=None,
+ file=DESCRIPTOR,
+ values=[
+ _descriptor.EnumValueDescriptor(
+ name='COMPRESSABLE', index=0, number=0,
+ options=None,
+ type=None),
+ _descriptor.EnumValueDescriptor(
+ name='UNCOMPRESSABLE', index=1, number=1,
+ options=None,
+ type=None),
+ _descriptor.EnumValueDescriptor(
+ name='RANDOM', index=2, number=2,
+ options=None,
+ type=None),
+ ],
+ containing_type=None,
+ options=None,
+ serialized_start=836,
+ serialized_end=899,
+)
+_sym_db.RegisterEnumDescriptor(_PAYLOADTYPE)
+
+PayloadType = enum_type_wrapper.EnumTypeWrapper(_PAYLOADTYPE)
+COMPRESSABLE = 0
+UNCOMPRESSABLE = 1
+RANDOM = 2
+
+
+
+_PAYLOAD = _descriptor.Descriptor(
+ name='Payload',
+ full_name='grpc.testing.Payload',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='type', full_name='grpc.testing.Payload.type', index=0,
+ number=1, type=14, cpp_type=8, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='body', full_name='grpc.testing.Payload.body', index=1,
+ number=2, type=12, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b(""),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=49,
+ serialized_end=113,
+)
+
+
+_SIMPLEREQUEST = _descriptor.Descriptor(
+ name='SimpleRequest',
+ full_name='grpc.testing.SimpleRequest',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='response_type', full_name='grpc.testing.SimpleRequest.response_type', index=0,
+ number=1, type=14, cpp_type=8, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='response_size', full_name='grpc.testing.SimpleRequest.response_size', index=1,
+ number=2, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.SimpleRequest.payload', index=2,
+ number=3, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='fill_username', full_name='grpc.testing.SimpleRequest.fill_username', index=3,
+ number=4, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='fill_oauth_scope', full_name='grpc.testing.SimpleRequest.fill_oauth_scope', index=4,
+ number=5, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=116,
+ serialized_end=293,
+)
+
+
+_SIMPLERESPONSE = _descriptor.Descriptor(
+ name='SimpleResponse',
+ full_name='grpc.testing.SimpleResponse',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.SimpleResponse.payload', index=0,
+ number=1, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='username', full_name='grpc.testing.SimpleResponse.username', index=1,
+ number=2, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='oauth_scope', full_name='grpc.testing.SimpleResponse.oauth_scope', index=2,
+ number=3, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=295,
+ serialized_end=390,
+)
+
+
+_STREAMINGINPUTCALLREQUEST = _descriptor.Descriptor(
+ name='StreamingInputCallRequest',
+ full_name='grpc.testing.StreamingInputCallRequest',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.StreamingInputCallRequest.payload', index=0,
+ number=1, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=392,
+ serialized_end=459,
+)
+
+
+_STREAMINGINPUTCALLRESPONSE = _descriptor.Descriptor(
+ name='StreamingInputCallResponse',
+ full_name='grpc.testing.StreamingInputCallResponse',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='aggregated_payload_size', full_name='grpc.testing.StreamingInputCallResponse.aggregated_payload_size', index=0,
+ number=1, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=461,
+ serialized_end=522,
+)
+
+
+_RESPONSEPARAMETERS = _descriptor.Descriptor(
+ name='ResponseParameters',
+ full_name='grpc.testing.ResponseParameters',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='size', full_name='grpc.testing.ResponseParameters.size', index=0,
+ number=1, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='interval_us', full_name='grpc.testing.ResponseParameters.interval_us', index=1,
+ number=2, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=524,
+ serialized_end=579,
+)
+
+
+_STREAMINGOUTPUTCALLREQUEST = _descriptor.Descriptor(
+ name='StreamingOutputCallRequest',
+ full_name='grpc.testing.StreamingOutputCallRequest',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='response_type', full_name='grpc.testing.StreamingOutputCallRequest.response_type', index=0,
+ number=1, type=14, cpp_type=8, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='response_parameters', full_name='grpc.testing.StreamingOutputCallRequest.response_parameters', index=1,
+ number=2, type=11, cpp_type=10, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.StreamingOutputCallRequest.payload', index=2,
+ number=3, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=582,
+ serialized_end=763,
+)
+
+
+_STREAMINGOUTPUTCALLRESPONSE = _descriptor.Descriptor(
+ name='StreamingOutputCallResponse',
+ full_name='grpc.testing.StreamingOutputCallResponse',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.StreamingOutputCallResponse.payload', index=0,
+ number=1, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=765,
+ serialized_end=834,
+)
+
+_PAYLOAD.fields_by_name['type'].enum_type = _PAYLOADTYPE
+_SIMPLEREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
+_SIMPLEREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_SIMPLERESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGINPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_parameters'].message_type = _RESPONSEPARAMETERS
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGOUTPUTCALLRESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
+DESCRIPTOR.message_types_by_name['Payload'] = _PAYLOAD
+DESCRIPTOR.message_types_by_name['SimpleRequest'] = _SIMPLEREQUEST
+DESCRIPTOR.message_types_by_name['SimpleResponse'] = _SIMPLERESPONSE
+DESCRIPTOR.message_types_by_name['StreamingInputCallRequest'] = _STREAMINGINPUTCALLREQUEST
+DESCRIPTOR.message_types_by_name['StreamingInputCallResponse'] = _STREAMINGINPUTCALLRESPONSE
+DESCRIPTOR.message_types_by_name['ResponseParameters'] = _RESPONSEPARAMETERS
+DESCRIPTOR.message_types_by_name['StreamingOutputCallRequest'] = _STREAMINGOUTPUTCALLREQUEST
+DESCRIPTOR.message_types_by_name['StreamingOutputCallResponse'] = _STREAMINGOUTPUTCALLRESPONSE
+DESCRIPTOR.enum_types_by_name['PayloadType'] = _PAYLOADTYPE
+
+Payload = _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), dict(
+ DESCRIPTOR = _PAYLOAD,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.Payload)
+ ))
+_sym_db.RegisterMessage(Payload)
+
+SimpleRequest = _reflection.GeneratedProtocolMessageType('SimpleRequest', (_message.Message,), dict(
+ DESCRIPTOR = _SIMPLEREQUEST,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.SimpleRequest)
+ ))
+_sym_db.RegisterMessage(SimpleRequest)
+
+SimpleResponse = _reflection.GeneratedProtocolMessageType('SimpleResponse', (_message.Message,), dict(
+ DESCRIPTOR = _SIMPLERESPONSE,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.SimpleResponse)
+ ))
+_sym_db.RegisterMessage(SimpleResponse)
+
+StreamingInputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingInputCallRequest', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGINPUTCALLREQUEST,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallRequest)
+ ))
+_sym_db.RegisterMessage(StreamingInputCallRequest)
+
+StreamingInputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingInputCallResponse', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGINPUTCALLRESPONSE,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallResponse)
+ ))
+_sym_db.RegisterMessage(StreamingInputCallResponse)
+
+ResponseParameters = _reflection.GeneratedProtocolMessageType('ResponseParameters', (_message.Message,), dict(
+ DESCRIPTOR = _RESPONSEPARAMETERS,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.ResponseParameters)
+ ))
+_sym_db.RegisterMessage(ResponseParameters)
+
+StreamingOutputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingOutputCallRequest', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGOUTPUTCALLREQUEST,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallRequest)
+ ))
+_sym_db.RegisterMessage(StreamingOutputCallRequest)
+
+StreamingOutputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingOutputCallResponse', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGOUTPUTCALLRESPONSE,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallResponse)
+ ))
+_sym_db.RegisterMessage(StreamingOutputCallResponse)
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/methods.py b/src/python/interop/interop/methods.py
new file mode 100644
index 0000000000..e5ce5902ca
--- /dev/null
+++ b/src/python/interop/interop/methods.py
@@ -0,0 +1,109 @@
+# 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 interoperability test methods."""
+
+from grpc_early_adopter import utilities
+
+from interop import empty_pb2
+from interop import messages_pb2
+
+def _empty_call(request):
+ return empty_pb2.Empty()
+
+EMPTY_CALL = utilities.unary_unary_rpc_method(
+ _empty_call, empty_pb2.Empty.SerializeToString, empty_pb2.Empty.FromString,
+ empty_pb2.Empty.SerializeToString, empty_pb2.Empty.FromString)
+
+
+def _unary_call(request):
+ return messages_pb2.SimpleResponse(
+ payload=messages_pb2.Payload(
+ type=messages_pb2.COMPRESSABLE,
+ body=b'\x00' * request.response_size))
+
+UNARY_CALL = utilities.unary_unary_rpc_method(
+ _unary_call, messages_pb2.SimpleRequest.SerializeToString,
+ messages_pb2.SimpleRequest.FromString,
+ messages_pb2.SimpleResponse.SerializeToString,
+ messages_pb2.SimpleResponse.FromString)
+
+
+def _streaming_output_call(request):
+ for response_parameters in request.response_parameters:
+ yield messages_pb2.StreamingOutputCallResponse(
+ payload=messages_pb2.Payload(
+ type=request.response_type,
+ body=b'\x00' * response_parameters.size))
+
+STREAMING_OUTPUT_CALL = utilities.unary_stream_rpc_method(
+ _streaming_output_call,
+ messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ messages_pb2.StreamingOutputCallRequest.FromString,
+ messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ messages_pb2.StreamingOutputCallResponse.FromString)
+
+
+def _streaming_input_call(request_iterator):
+ aggregate_size = 0
+ for request in request_iterator:
+ if request.payload and request.payload.body:
+ aggregate_size += len(request.payload.body)
+ return messages_pb2.StreamingInputCallResponse(
+ aggregated_payload_size=aggregate_size)
+
+STREAMING_INPUT_CALL = utilities.stream_unary_rpc_method(
+ _streaming_input_call,
+ messages_pb2.StreamingInputCallRequest.SerializeToString,
+ messages_pb2.StreamingInputCallRequest.FromString,
+ messages_pb2.StreamingInputCallResponse.SerializeToString,
+ messages_pb2.StreamingInputCallResponse.FromString)
+
+
+def _full_duplex_call(request_iterator):
+ for request in request_iterator:
+ yield messages_pb2.StreamingOutputCallResponse(
+ payload=messages_pb2.Payload(
+ type=request.payload.type,
+ body=b'\x00' * request.response_parameters[0].size))
+
+FULL_DUPLEX_CALL = utilities.stream_stream_rpc_method(
+ _full_duplex_call,
+ messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ messages_pb2.StreamingOutputCallRequest.FromString,
+ messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ messages_pb2.StreamingOutputCallResponse.FromString)
+
+# NOTE(nathaniel): Apparently this is the same as the full-duplex call?
+HALF_DUPLEX_CALL = utilities.stream_stream_rpc_method(
+ _full_duplex_call,
+ messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ messages_pb2.StreamingOutputCallRequest.FromString,
+ messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ messages_pb2.StreamingOutputCallResponse.FromString)
diff --git a/src/python/interop/interop/server.py b/src/python/interop/interop/server.py
new file mode 100644
index 0000000000..404c87dd0a
--- /dev/null
+++ b/src/python/interop/interop/server.py
@@ -0,0 +1,91 @@
+# 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 Python implementation of the GRPC interoperability test server."""
+
+import argparse
+import logging
+import pkg_resources
+import time
+
+from grpc_early_adopter import implementations
+
+from interop import methods
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+
+_PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key'
+_CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem'
+
+_METHODS = {
+ '/grpc.testing.TestService/EmptyCall': methods.EMPTY_CALL,
+ '/grpc.testing.TestService/UnaryCall': methods.UNARY_CALL,
+ '/grpc.testing.TestService/StreamingOutputCall':
+ methods.STREAMING_OUTPUT_CALL,
+ '/grpc.testing.TestService/StreamingInputCall':
+ methods.STREAMING_INPUT_CALL,
+ '/grpc.testing.TestService/FullDuplexCall':
+ methods.FULL_DUPLEX_CALL,
+ '/grpc.testing.TestService/HalfDuplexCall':
+ methods.HALF_DUPLEX_CALL,
+}
+
+
+def serve():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--port', help='the port on which to serve', type=int)
+ parser.add_argument(
+ '--use_tls', help='require a secure connection', dest='use_tls',
+ action='store_true')
+ args = parser.parse_args()
+
+ if args.use_tls:
+ private_key = pkg_resources.resource_string(
+ __name__, _PRIVATE_KEY_RESOURCE_PATH)
+ certificate_chain = pkg_resources.resource_string(
+ __name__, _CERTIFICATE_CHAIN_RESOURCE_PATH)
+ server = implementations.secure_server(
+ _METHODS, args.port, private_key, certificate_chain)
+ else:
+ server = implementations.insecure_server(
+ _METHODS, args.port)
+
+ server.start()
+ logging.info('Server serving.')
+ try:
+ while True:
+ time.sleep(_ONE_DAY_IN_SECONDS)
+ except BaseException as e:
+ logging.info('Caught exception "%s"; stopping server...', e)
+ server.stop()
+ logging.info('Server stopped; exiting.')
+
+if __name__ == '__main__':
+ serve()
diff --git a/src/python/interop/interop/test_pb2.py b/src/python/interop/interop/test_pb2.py
new file mode 100644
index 0000000000..1241453159
--- /dev/null
+++ b/src/python/interop/interop/test_pb2.py
@@ -0,0 +1,32 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/cpp/interop/test.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from test.cpp.interop import empty_pb2 as test_dot_cpp_dot_interop_dot_empty__pb2
+from test.cpp.interop import messages_pb2 as test_dot_cpp_dot_interop_dot_messages__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='test/cpp/interop/test.proto',
+ package='grpc.testing',
+ serialized_pb=_b('\n\x1btest/cpp/interop/test.proto\x12\x0cgrpc.testing\x1a\x1ctest/cpp/interop/empty.proto\x1a\x1ftest/cpp/interop/messages.proto2\xbb\x04\n\x0bTestService\x12\x35\n\tEmptyCall\x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty\x12\x46\n\tUnaryCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleResponse\x12l\n\x13StreamingOutputCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse0\x01\x12i\n\x12StreamingInputCall\x12\'.grpc.testing.StreamingInputCallRequest\x1a(.grpc.testing.StreamingInputCallResponse(\x01\x12i\n\x0e\x46ullDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01\x12i\n\x0eHalfDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01')
+ ,
+ dependencies=[test_dot_cpp_dot_interop_dot_empty__pb2.DESCRIPTOR,test_dot_cpp_dot_interop_dot_messages__pb2.DESCRIPTOR,])
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+
+
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/setup.py b/src/python/interop/setup.py
new file mode 100644
index 0000000000..4b7709f234
--- /dev/null
+++ b/src/python/interop/setup.py
@@ -0,0 +1,51 @@
+# 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.
+
+"""A setup module for the GRPC Python interop testing package."""
+
+from distutils import core as _core
+
+_PACKAGES = (
+ 'interop',
+)
+
+_PACKAGE_DIRECTORIES = {
+ 'interop': 'interop',
+}
+
+_PACKAGE_DATA = {
+ 'interop': ['credentials/server1.key', 'credentials/server1.pem',]
+}
+
+_INSTALL_REQUIRES = ['grpc-2015>=0.0.1']
+
+_core.setup(
+ name='interop', version='0.0.1', packages=_PACKAGES,
+ package_dir=_PACKAGE_DIRECTORIES, package_data=_PACKAGE_DATA,
+ install_requires=_INSTALL_REQUIRES)
diff --git a/src/python/src/_adapter/_face_test_case.py b/src/python/src/_adapter/_face_test_case.py
index 112dcfb928..2c6e6286b5 100644
--- a/src/python/src/_adapter/_face_test_case.py
+++ b/src/python/src/_adapter/_face_test_case.py
@@ -80,7 +80,7 @@ class FaceTestCase(test_case.FaceTestCase, coverage.BlockingCoverage):
fore_link = fore.ForeLink(
pool, serialization.request_deserializers,
- serialization.response_serializers)
+ serialization.response_serializers, None, ())
port = fore_link.start()
rear_link = rear.RearLink(
'localhost', port, pool,
diff --git a/src/python/src/_adapter/_links_test.py b/src/python/src/_adapter/_links_test.py
index 8341460a9a..d8bbb27127 100644
--- a/src/python/src/_adapter/_links_test.py
+++ b/src/python/src/_adapter/_links_test.py
@@ -67,7 +67,7 @@ class RoundTripTest(unittest.TestCase):
test_rear_link = _test_links.RearLink(rear_action, None)
fore_link = fore.ForeLink(
- self.fore_link_pool, {test_method: None}, {test_method: None})
+ self.fore_link_pool, {test_method: None}, {test_method: None}, None, ())
fore_link.join_rear_link(test_rear_link)
test_rear_link.join_fore_link(fore_link)
port = fore_link.start()
@@ -120,7 +120,7 @@ class RoundTripTest(unittest.TestCase):
fore_link = fore.ForeLink(
self.fore_link_pool, {test_method: _IDENTITY},
- {test_method: _IDENTITY})
+ {test_method: _IDENTITY}, None, ())
fore_link.join_rear_link(test_rear_link)
test_rear_link.join_fore_link(fore_link)
port = fore_link.start()
@@ -182,7 +182,7 @@ class RoundTripTest(unittest.TestCase):
fore_link = fore.ForeLink(
self.fore_link_pool, {test_method: scenario.deserialize_request},
- {test_method: scenario.serialize_response})
+ {test_method: scenario.serialize_response}, None, ())
fore_link.join_rear_link(test_rear_link)
test_rear_link.join_fore_link(fore_link)
port = fore_link.start()
diff --git a/src/python/src/_adapter/_low.py b/src/python/src/_adapter/_low.py
index 6c24087dad..09105eafa0 100644
--- a/src/python/src/_adapter/_low.py
+++ b/src/python/src/_adapter/_low.py
@@ -52,4 +52,5 @@ Call = _c.Call
Channel = _c.Channel
CompletionQueue = _c.CompletionQueue
Server = _c.Server
+ServerCredentials = _c.ServerCredentials
# pylint: enable=invalid-name
diff --git a/src/python/src/_adapter/_server.c b/src/python/src/_adapter/_server.c
index 503be61ab4..2f8cc99e44 100644
--- a/src/python/src/_adapter/_server.c
+++ b/src/python/src/_adapter/_server.c
@@ -85,6 +85,19 @@ static PyObject *pygrpc_server_add_http2_addr(Server *self, PyObject *args) {
return PyInt_FromLong(port);
}
+static PyObject *pygrpc_server_add_secure_http2_addr(Server *self,
+ PyObject *args) {
+ const char *addr;
+ int port;
+ PyArg_ParseTuple(args, "s", &addr);
+ port = grpc_server_add_secure_http2_port(self->c_server, addr);
+ if (port == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "Couldn't add port to server!");
+ return NULL;
+ }
+ return PyInt_FromLong(port);
+}
+
static PyObject *pygrpc_server_start(Server *self) {
grpc_server_start(self->c_server);
@@ -118,6 +131,8 @@ static PyObject *pygrpc_server_stop(Server *self) {
static PyMethodDef methods[] = {
{"add_http2_addr", (PyCFunction)pygrpc_server_add_http2_addr, METH_VARARGS,
"Add an HTTP2 address."},
+ {"add_secure_http2_addr", (PyCFunction)pygrpc_server_add_secure_http2_addr,
+ METH_VARARGS, "Add a secure HTTP2 address."},
{"start", (PyCFunction)pygrpc_server_start, METH_NOARGS,
"Starts the server."},
{"service", (PyCFunction)pygrpc_server_service, METH_VARARGS,
diff --git a/src/python/src/_adapter/fore.py b/src/python/src/_adapter/fore.py
index 2f102751f2..28aede1fd9 100644
--- a/src/python/src/_adapter/fore.py
+++ b/src/python/src/_adapter/fore.py
@@ -69,7 +69,8 @@ class ForeLink(ticket_interfaces.ForeLink):
"""A service-side bridge between RPC Framework and the C-ish _low code."""
def __init__(
- self, pool, request_deserializers, response_serializers, port=None):
+ self, pool, request_deserializers, response_serializers,
+ root_certificates, key_chain_pairs, port=None):
"""Constructor.
Args:
@@ -78,6 +79,10 @@ class ForeLink(ticket_interfaces.ForeLink):
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.
"""
@@ -85,6 +90,8 @@ class ForeLink(ticket_interfaces.ForeLink):
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._port = port
self._rear_link = null.NULL_REAR_LINK
@@ -264,10 +271,16 @@ class ForeLink(ticket_interfaces.ForeLink):
object.
"""
with self._condition:
+ address = '[::]:%d' % (0 if self._port is None else self._port)
self._completion_queue = _low.CompletionQueue()
- self._server = _low.Server(self._completion_queue, None)
- port = self._server.add_http2_addr(
- '[::]:%d' % (0 if self._port is None else self._port))
+ if self._root_certificates is None and not self._key_chain_pairs:
+ self._server = _low.Server(self._completion_queue, None)
+ port = self._server.add_http2_addr(address)
+ else:
+ server_credentials = _low.ServerCredentials(
+ self._root_certificates, self._key_chain_pairs)
+ self._server = _low.Server(self._completion_queue, server_credentials)
+ port = self._server.add_secure_http2_addr(address)
self._server.start()
self._server.service(None)
diff --git a/src/python/src/_framework/base/packets/_ingestion.py b/src/python/src/_framework/base/packets/_ingestion.py
index abc1e7a043..91f5a35359 100644
--- a/src/python/src/_framework/base/packets/_ingestion.py
+++ b/src/python/src/_framework/base/packets/_ingestion.py
@@ -183,7 +183,7 @@ class _WrappedConsumer(object):
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.
- May be False only if payload is not None.
+ Must be True if payload is None.
Returns:
True if the wrapped consumer made progress or False if the wrapped
@@ -191,13 +191,12 @@ class _WrappedConsumer(object):
progress.
"""
try:
- if payload:
- if complete:
- self._consumer.consume_and_terminate(payload)
- else:
- self._consumer.consume(payload)
- else:
+ 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
diff --git a/src/python/src/_framework/face/_calls.py b/src/python/src/_framework/face/_calls.py
index 9128aef7c4..a7d8be5e43 100644
--- a/src/python/src/_framework/face/_calls.py
+++ b/src/python/src/_framework/face/_calls.py
@@ -29,6 +29,7 @@
"""Utility functions for invoking RPCs."""
+import sys
import threading
from _framework.base import interfaces as base_interfaces
@@ -79,20 +80,46 @@ def _stream_event_subscription(result_consumer, abortion_callback):
_EventServicedIngestor(result_consumer, abortion_callback))
+# NOTE(nathaniel): This class has some extremely special semantics around
+# cancellation that allow it to be used by both "blocking" APIs and "futures"
+# APIs.
+#
+# Since futures.Future defines its own exception for cancellation, we want these
+# objects, when returned by methods of a returning-Futures-from-other-methods
+# object, to raise the same exception for cancellation. But that's weird in a
+# blocking API - why should this object, also returned by methods of blocking
+# APIs, raise exceptions from the "future" module? Should we do something like
+# have this class be parameterized by the type of exception that it raises in
+# cancellation circumstances?
+#
+# We don't have to take such a dramatic step: since blocking APIs define no
+# cancellation semantics whatsoever, there is no supported way for
+# blocking-API-users of these objects to cancel RPCs, and thus no supported way
+# for them to see an exception the type of which would be weird to them.
+#
+# Bonus: in both blocking and futures APIs, this object still properly raises
+# exceptions.CancellationError for any *server-side cancellation* of an RPC.
class _OperationCancellableIterator(interfaces.CancellableIterator):
"""An interfaces.CancellableIterator for response-streaming operations."""
def __init__(self, rendezvous, operation):
+ self._lock = threading.Lock()
self._rendezvous = rendezvous
self._operation = operation
+ self._cancelled = False
def __iter__(self):
return self
def next(self):
+ with self._lock:
+ if self._cancelled:
+ raise future.CancelledError()
return next(self._rendezvous)
def cancel(self):
+ with self._lock:
+ self._cancelled = True
self._operation.cancel()
self._rendezvous.set_outcome(base_interfaces.Outcome.CANCELLED)
@@ -105,46 +132,126 @@ class _OperationFuture(future.Future):
self._rendezvous = rendezvous
self._operation = operation
- self._outcome = None
+ self._cancelled = False
+ self._computed = False
+ self._payload = None
+ self._exception = None
+ self._traceback = None
self._callbacks = []
def cancel(self):
"""See future.Future.cancel for specification."""
with self._condition:
- if self._outcome is None:
+ if not self._cancelled and not self._computed:
self._operation.cancel()
- self._outcome = future.aborted()
+ self._cancelled = True
self._condition.notify_all()
return False
def cancelled(self):
"""See future.Future.cancelled for specification."""
- return False
+ with self._condition:
+ return self._cancelled
+
+ def running(self):
+ """See future.Future.running for specification."""
+ with self._condition:
+ return not self._cancelled and not self._computed
def done(self):
"""See future.Future.done for specification."""
with self._condition:
- return (self._outcome is not None and
- self._outcome.category is not future.ABORTED)
+ return self._cancelled or self._computed
+
+ def result(self, timeout=None):
+ """See future.Future.result for specification."""
+ with self._condition:
+ if self._cancelled:
+ raise future.CancelledError()
+ if self._computed:
+ if self._payload is None:
+ raise self._exception # pylint: disable=raising-bad-type
+ else:
+ return self._payload
+
+ condition = threading.Condition()
+ def notify_condition(unused_future):
+ with condition:
+ condition.notify()
+ self._callbacks.append(notify_condition)
+
+ with condition:
+ condition.wait(timeout=timeout)
+
+ with self._condition:
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ if self._payload is None:
+ raise self._exception # pylint: disable=raising-bad-type
+ else:
+ return self._payload
+ else:
+ raise future.TimeoutError()
+
+ def exception(self, timeout=None):
+ """See future.Future.exception for specification."""
+ with self._condition:
+ if self._cancelled:
+ raise future.CancelledError()
+ if self._computed:
+ return self._exception
+
+ condition = threading.Condition()
+ def notify_condition(unused_future):
+ with condition:
+ condition.notify()
+ self._callbacks.append(notify_condition)
+
+ with condition:
+ condition.wait(timeout=timeout)
- def outcome(self):
- """See future.Future.outcome for specification."""
with self._condition:
- while self._outcome is None:
- self._condition.wait()
- return self._outcome
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ return self._exception
+ else:
+ raise future.TimeoutError()
- def add_done_callback(self, callback):
+ def traceback(self, timeout=None):
+ """See future.Future.traceback for specification."""
+ with self._condition:
+ if self._cancelled:
+ raise future.CancelledError()
+ if self._computed:
+ return self._traceback
+
+ condition = threading.Condition()
+ def notify_condition(unused_future):
+ with condition:
+ condition.notify()
+ self._callbacks.append(notify_condition)
+
+ with condition:
+ condition.wait(timeout=timeout)
+
+ with self._condition:
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ return self._traceback
+ else:
+ raise future.TimeoutError()
+
+ def add_done_callback(self, fn):
"""See future.Future.add_done_callback for specification."""
with self._condition:
if self._callbacks is not None:
- self._callbacks.add(callback)
+ self._callbacks.add(fn)
return
- outcome = self._outcome
-
- callable_util.call_logging_exceptions(
- callback, _DONE_CALLBACK_LOG_MESSAGE, outcome)
+ callable_util.call_logging_exceptions(fn, _DONE_CALLBACK_LOG_MESSAGE, self)
def on_operation_termination(self, operation_outcome):
"""Indicates to this object that the operation has terminated.
@@ -154,34 +261,42 @@ class _OperationFuture(future.Future):
outcome of the operation.
"""
with self._condition:
- if (self._outcome is None and
- operation_outcome is not base_interfaces.Outcome.COMPLETED):
- self._outcome = future.raised(
- _control.abortion_outcome_to_exception(operation_outcome))
- self._condition.notify_all()
-
- outcome = self._outcome
- rendezvous = self._rendezvous
- callbacks = list(self._callbacks)
- self._callbacks = None
-
- if outcome is None:
- try:
- return_value = next(rendezvous)
- except Exception as e: # pylint: disable=broad-except
- outcome = future.raised(e)
+ cancelled = self._cancelled
+ if cancelled:
+ callbacks = list(self._callbacks)
+ self._callbacks = None
else:
- outcome = future.returned(return_value)
+ rendezvous = self._rendezvous
+
+ if not cancelled:
+ payload = None
+ exception = None
+ traceback = None
+ if operation_outcome == base_interfaces.Outcome.COMPLETED:
+ try:
+ payload = next(rendezvous)
+ except Exception as e: # pylint: disable=broad-except
+ exception = e
+ traceback = sys.exc_info()[2]
+ else:
+ try:
+ # We raise and then immediately catch in order to create a traceback.
+ raise _control.abortion_outcome_to_exception(operation_outcome)
+ except Exception as e: # pylint: disable=broad-except
+ exception = e
+ traceback = sys.exc_info()[2]
with self._condition:
- if self._outcome is None:
- self._outcome = outcome
- self._condition.notify_all()
- else:
- outcome = self._outcome
+ if not self._cancelled:
+ self._computed = True
+ self._payload = payload
+ self._exception = exception
+ self._traceback = traceback
+ callbacks = list(self._callbacks)
+ self._callbacks = None
for callback in callbacks:
callable_util.call_logging_exceptions(
- callback, _DONE_CALLBACK_LOG_MESSAGE, outcome)
+ callback, _DONE_CALLBACK_LOG_MESSAGE, self)
class _Call(interfaces.Call):
diff --git a/src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
index cf8b2eeb95..939b238b66 100644
--- a/src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
+++ b/src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
@@ -116,7 +116,7 @@ class FutureInvocationAsynchronousEventServiceTestCase(
response_future = self.stub.future_value_in_value_out(
name, request, _TIMEOUT)
- response = response_future.outcome().return_value
+ response = response_future.result()
test_messages.verify(request, response, self)
@@ -144,7 +144,7 @@ class FutureInvocationAsynchronousEventServiceTestCase(
with request_iterator.pause():
response_future = self.stub.future_stream_in_value_out(
name, request_iterator, _TIMEOUT)
- response = response_future.outcome().return_value
+ response = response_future.result()
test_messages.verify(requests, response, self)
@@ -173,13 +173,13 @@ class FutureInvocationAsynchronousEventServiceTestCase(
first_response_future = self.stub.future_value_in_value_out(
name, first_request, _TIMEOUT)
- first_response = first_response_future.outcome().return_value
+ first_response = first_response_future.result()
test_messages.verify(first_request, first_response, self)
second_response_future = self.stub.future_value_in_value_out(
name, second_request, _TIMEOUT)
- second_response = second_response_future.outcome().return_value
+ second_response = second_response_future.result()
test_messages.verify(second_request, second_response, self)
@@ -192,10 +192,10 @@ class FutureInvocationAsynchronousEventServiceTestCase(
with self.control.pause():
response_future = self.stub.future_value_in_value_out(
name, request, _TIMEOUT)
- outcome = response_future.outcome()
-
- self.assertIsInstance(
- outcome.exception, exceptions.ExpirationError)
+ self.assertIsInstance(
+ response_future.exception(), exceptions.ExpirationError)
+ with self.assertRaises(exceptions.ExpirationError):
+ response_future.result()
def testExpiredUnaryRequestStreamResponse(self):
for name, test_messages_sequence in (
@@ -203,11 +203,11 @@ class FutureInvocationAsynchronousEventServiceTestCase(
for test_messages in test_messages_sequence:
request = test_messages.request()
- with self.control.pause(), self.assertRaises(
- exceptions.ExpirationError):
+ with self.control.pause():
response_iterator = self.stub.inline_value_in_stream_out(
name, request, _TIMEOUT)
- list(response_iterator)
+ with self.assertRaises(exceptions.ExpirationError):
+ list(response_iterator)
def testExpiredStreamRequestUnaryResponse(self):
for name, test_messages_sequence in (
@@ -218,10 +218,10 @@ class FutureInvocationAsynchronousEventServiceTestCase(
with self.control.pause():
response_future = self.stub.future_stream_in_value_out(
name, iter(requests), _TIMEOUT)
- outcome = response_future.outcome()
-
- self.assertIsInstance(
- outcome.exception, exceptions.ExpirationError)
+ self.assertIsInstance(
+ response_future.exception(), exceptions.ExpirationError)
+ with self.assertRaises(exceptions.ExpirationError):
+ response_future.result()
def testExpiredStreamRequestStreamResponse(self):
for name, test_messages_sequence in (
@@ -229,11 +229,11 @@ class FutureInvocationAsynchronousEventServiceTestCase(
for test_messages in test_messages_sequence:
requests = test_messages.requests()
- with self.control.pause(), self.assertRaises(
- exceptions.ExpirationError):
+ with self.control.pause():
response_iterator = self.stub.inline_stream_in_stream_out(
name, iter(requests), _TIMEOUT)
- list(response_iterator)
+ with self.assertRaises(exceptions.ExpirationError):
+ list(response_iterator)
def testFailedUnaryRequestUnaryResponse(self):
for name, test_messages_sequence in (
@@ -244,13 +244,15 @@ class FutureInvocationAsynchronousEventServiceTestCase(
with self.control.fail():
response_future = self.stub.future_value_in_value_out(
name, request, _TIMEOUT)
- outcome = response_future.outcome()
- # Because the servicer fails outside of the thread from which the
- # servicer-side runtime called into it its failure is indistinguishable
- # from simply not having called its response_callback before the
- # expiration of the RPC.
- self.assertIsInstance(outcome.exception, exceptions.ExpirationError)
+ # Because the servicer fails outside of the thread from which the
+ # servicer-side runtime called into it its failure is
+ # indistinguishable from simply not having called its
+ # response_callback before the expiration of the RPC.
+ self.assertIsInstance(
+ response_future.exception(), exceptions.ExpirationError)
+ with self.assertRaises(exceptions.ExpirationError):
+ response_future.result()
def testFailedUnaryRequestStreamResponse(self):
for name, test_messages_sequence in (
@@ -276,13 +278,15 @@ class FutureInvocationAsynchronousEventServiceTestCase(
with self.control.fail():
response_future = self.stub.future_stream_in_value_out(
name, iter(requests), _TIMEOUT)
- outcome = response_future.outcome()
- # Because the servicer fails outside of the thread from which the
- # servicer-side runtime called into it its failure is indistinguishable
- # from simply not having called its response_callback before the
- # expiration of the RPC.
- self.assertIsInstance(outcome.exception, exceptions.ExpirationError)
+ # Because the servicer fails outside of the thread from which the
+ # servicer-side runtime called into it its failure is
+ # indistinguishable from simply not having called its
+ # response_callback before the expiration of the RPC.
+ self.assertIsInstance(
+ response_future.exception(), exceptions.ExpirationError)
+ with self.assertRaises(exceptions.ExpirationError):
+ response_future.result()
def testFailedStreamRequestStreamResponse(self):
for name, test_messages_sequence in (
@@ -310,8 +314,8 @@ class FutureInvocationAsynchronousEventServiceTestCase(
name, first_request, _TIMEOUT)
second_response_future = self.stub.future_value_in_value_out(
name, second_request, _TIMEOUT)
- first_response = first_response_future.outcome().return_value
- second_response = second_response_future.outcome().return_value
+ first_response = first_response_future.result()
+ second_response = second_response_future.result()
test_messages.verify(first_request, first_response, self)
test_messages.verify(second_request, second_response, self)
@@ -329,10 +333,10 @@ class FutureInvocationAsynchronousEventServiceTestCase(
with self.control.pause():
response_future = self.stub.future_value_in_value_out(
name, request, _TIMEOUT)
- cancelled = response_future.cancel()
+ cancel_method_return_value = response_future.cancel()
- self.assertFalse(cancelled)
- self.assertEqual(future.ABORTED, response_future.outcome().category)
+ self.assertFalse(cancel_method_return_value)
+ self.assertTrue(response_future.cancelled())
def testCancelledUnaryRequestStreamResponse(self):
for name, test_messages_sequence in (
@@ -345,7 +349,7 @@ class FutureInvocationAsynchronousEventServiceTestCase(
name, request, _TIMEOUT)
response_iterator.cancel()
- with self.assertRaises(exceptions.CancellationError):
+ with self.assertRaises(future.CancelledError):
next(response_iterator)
def testCancelledStreamRequestUnaryResponse(self):
@@ -357,10 +361,10 @@ class FutureInvocationAsynchronousEventServiceTestCase(
with self.control.pause():
response_future = self.stub.future_stream_in_value_out(
name, iter(requests), _TIMEOUT)
- cancelled = response_future.cancel()
+ cancel_method_return_value = response_future.cancel()
- self.assertFalse(cancelled)
- self.assertEqual(future.ABORTED, response_future.outcome().category)
+ self.assertFalse(cancel_method_return_value)
+ self.assertTrue(response_future.cancelled())
def testCancelledStreamRequestStreamResponse(self):
for name, test_messages_sequence in (
@@ -373,5 +377,5 @@ class FutureInvocationAsynchronousEventServiceTestCase(
name, iter(requests), _TIMEOUT)
response_iterator.cancel()
- with self.assertRaises(exceptions.CancellationError):
+ with self.assertRaises(future.CancelledError):
next(response_iterator)
diff --git a/src/python/src/_framework/foundation/_later_test.py b/src/python/src/_framework/foundation/_later_test.py
index fbd17a4ad9..50b67907db 100644
--- a/src/python/src/_framework/foundation/_later_test.py
+++ b/src/python/src/_framework/foundation/_later_test.py
@@ -33,7 +33,6 @@ import threading
import time
import unittest
-from _framework.foundation import future
from _framework.foundation import later
TICK = 0.1
@@ -44,10 +43,14 @@ class LaterTest(unittest.TestCase):
def test_simple_delay(self):
lock = threading.Lock()
cell = [0]
- def increment_cell():
+ return_value = object()
+
+ def computation():
with lock:
cell[0] += 1
- computation_future = later.later(TICK * 2, increment_cell)
+ return return_value
+ computation_future = later.later(TICK * 2, computation)
+
self.assertFalse(computation_future.done())
self.assertFalse(computation_future.cancelled())
time.sleep(TICK)
@@ -60,22 +63,21 @@ class LaterTest(unittest.TestCase):
self.assertFalse(computation_future.cancelled())
with lock:
self.assertEqual(1, cell[0])
- outcome = computation_future.outcome()
- self.assertEqual(future.RETURNED, outcome.category)
+ self.assertEqual(return_value, computation_future.result())
def test_callback(self):
lock = threading.Lock()
cell = [0]
callback_called = [False]
- outcome_passed_to_callback = [None]
- def increment_cell():
+ future_passed_to_callback = [None]
+ def computation():
with lock:
cell[0] += 1
- computation_future = later.later(TICK * 2, increment_cell)
+ computation_future = later.later(TICK * 2, computation)
def callback(outcome):
with lock:
callback_called[0] = True
- outcome_passed_to_callback[0] = outcome
+ future_passed_to_callback[0] = outcome
computation_future.add_done_callback(callback)
time.sleep(TICK)
with lock:
@@ -83,63 +85,67 @@ class LaterTest(unittest.TestCase):
time.sleep(TICK * 2)
with lock:
self.assertTrue(callback_called[0])
- self.assertEqual(future.RETURNED, outcome_passed_to_callback[0].category)
+ self.assertTrue(future_passed_to_callback[0].done())
callback_called[0] = False
- outcome_passed_to_callback[0] = None
+ future_passed_to_callback[0] = None
computation_future.add_done_callback(callback)
with lock:
self.assertTrue(callback_called[0])
- self.assertEqual(future.RETURNED, outcome_passed_to_callback[0].category)
+ self.assertTrue(future_passed_to_callback[0].done())
def test_cancel(self):
lock = threading.Lock()
cell = [0]
callback_called = [False]
- outcome_passed_to_callback = [None]
- def increment_cell():
+ future_passed_to_callback = [None]
+ def computation():
with lock:
cell[0] += 1
- computation_future = later.later(TICK * 2, increment_cell)
+ computation_future = later.later(TICK * 2, computation)
def callback(outcome):
with lock:
callback_called[0] = True
- outcome_passed_to_callback[0] = outcome
+ future_passed_to_callback[0] = outcome
computation_future.add_done_callback(callback)
time.sleep(TICK)
with lock:
self.assertFalse(callback_called[0])
computation_future.cancel()
self.assertTrue(computation_future.cancelled())
- self.assertFalse(computation_future.done())
- self.assertEqual(future.ABORTED, computation_future.outcome().category)
+ self.assertFalse(computation_future.running())
+ self.assertTrue(computation_future.done())
with lock:
self.assertTrue(callback_called[0])
- self.assertEqual(future.ABORTED, outcome_passed_to_callback[0].category)
+ self.assertTrue(future_passed_to_callback[0].cancelled())
- def test_outcome(self):
+ def test_result(self):
lock = threading.Lock()
cell = [0]
callback_called = [False]
- outcome_passed_to_callback = [None]
- def increment_cell():
+ future_passed_to_callback_cell = [None]
+ return_value = object()
+
+ def computation():
with lock:
cell[0] += 1
- computation_future = later.later(TICK * 2, increment_cell)
- def callback(outcome):
+ return return_value
+ computation_future = later.later(TICK * 2, computation)
+
+ def callback(future_passed_to_callback):
with lock:
callback_called[0] = True
- outcome_passed_to_callback[0] = outcome
+ future_passed_to_callback_cell[0] = future_passed_to_callback
computation_future.add_done_callback(callback)
- returned_outcome = computation_future.outcome()
- self.assertEqual(future.RETURNED, returned_outcome.category)
+ returned_value = computation_future.result()
+ self.assertEqual(return_value, returned_value)
# The callback may not yet have been called! Sleep a tick.
time.sleep(TICK)
with lock:
self.assertTrue(callback_called[0])
- self.assertEqual(future.RETURNED, outcome_passed_to_callback[0].category)
+ self.assertEqual(return_value, future_passed_to_callback_cell[0].result())
if __name__ == '__main__':
unittest.main()
diff --git a/src/python/src/_framework/foundation/_timer_future.py b/src/python/src/_framework/foundation/_timer_future.py
index 86bc073d56..4aa66991c5 100644
--- a/src/python/src/_framework/foundation/_timer_future.py
+++ b/src/python/src/_framework/foundation/_timer_future.py
@@ -29,6 +29,7 @@
"""Affords a Future implementation based on Python's threading.Timer."""
+import sys
import threading
import time
@@ -52,7 +53,9 @@ class TimerFuture(future.Future):
self._computing = False
self._computed = False
self._cancelled = False
- self._outcome = None
+ self._result = None
+ self._exception = None
+ self._traceback = None
self._waiting = []
def _compute(self):
@@ -70,19 +73,24 @@ class TimerFuture(future.Future):
self._computing = True
try:
- returned_value = self._computation()
- outcome = future.returned(returned_value)
+ return_value = self._computation()
+ exception = None
+ traceback = None
except Exception as e: # pylint: disable=broad-except
- outcome = future.raised(e)
+ return_value = None
+ exception = e
+ traceback = sys.exc_info()[2]
with self._lock:
self._computing = False
self._computed = True
- self._outcome = outcome
+ self._return_value = return_value
+ self._exception = exception
+ self._traceback = traceback
waiting = self._waiting
for callback in waiting:
- callback(outcome)
+ callback(self)
def start(self):
"""Starts this Future.
@@ -104,13 +112,11 @@ class TimerFuture(future.Future):
else:
self._timer.cancel()
self._cancelled = True
- self._outcome = future.aborted()
- outcome = self._outcome
waiting = self._waiting
for callback in waiting:
try:
- callback(outcome)
+ callback(self)
except Exception: # pylint: disable=broad-except
pass
@@ -121,36 +127,102 @@ class TimerFuture(future.Future):
with self._lock:
return self._cancelled
+ def running(self):
+ """See future.Future.running for specification."""
+ with self._lock:
+ return not self._computed and not self._cancelled
+
def done(self):
"""See future.Future.done for specification."""
with self._lock:
- return self._computed
+ return self._computed or self._cancelled
+
+ def result(self, timeout=None):
+ """See future.Future.result for specification."""
+ with self._lock:
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ if self._exception is None:
+ return self._return_value
+ else:
+ raise self._exception # pylint: disable=raising-bad-type
+
+ condition = threading.Condition()
+ def notify_condition(unused_future):
+ with condition:
+ condition.notify()
+ self._waiting.append(notify_condition)
+
+ with condition:
+ condition.wait(timeout=timeout)
+
+ with self._lock:
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ if self._exception is None:
+ return self._return_value
+ else:
+ raise self._exception # pylint: disable=raising-bad-type
+ else:
+ raise future.TimeoutError()
+
+ def exception(self, timeout=None):
+ """See future.Future.exception for specification."""
+ with self._lock:
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ return self._exception
+
+ condition = threading.Condition()
+ def notify_condition(unused_future):
+ with condition:
+ condition.notify()
+ self._waiting.append(notify_condition)
+
+ with condition:
+ condition.wait(timeout=timeout)
+
+ with self._lock:
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ return self._exception
+ else:
+ raise future.TimeoutError()
- def outcome(self):
- """See future.Future.outcome for specification."""
+ def traceback(self, timeout=None):
+ """See future.Future.traceback for specification."""
with self._lock:
- if self._computed or self._cancelled:
- return self._outcome
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ return self._traceback
condition = threading.Condition()
- def notify_condition(unused_outcome):
+ def notify_condition(unused_future):
with condition:
condition.notify()
self._waiting.append(notify_condition)
with condition:
- condition.wait()
+ condition.wait(timeout=timeout)
with self._lock:
- return self._outcome
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._computed:
+ return self._traceback
+ else:
+ raise future.TimeoutError()
- def add_done_callback(self, callback):
+ def add_done_callback(self, fn):
"""See future.Future.add_done_callback for specification."""
with self._lock:
if not self._computed and not self._cancelled:
- self._waiting.append(callback)
+ self._waiting.append(fn)
return
- else:
- outcome = self._outcome
- callback(outcome)
+ fn(self)
diff --git a/src/python/src/_framework/foundation/callable_util.py b/src/python/src/_framework/foundation/callable_util.py
index 1f7546cb76..32b0751a01 100644
--- a/src/python/src/_framework/foundation/callable_util.py
+++ b/src/python/src/_framework/foundation/callable_util.py
@@ -29,18 +29,47 @@
"""Utilities for working with callables."""
+import abc
+import collections
+import enum
import functools
import logging
-from _framework.foundation import future
+
+class Outcome(object):
+ """A sum type describing the outcome of some call.
+
+ Attributes:
+ kind: One of Kind.RETURNED or Kind.RAISED respectively indicating that the
+ call returned a value or raised an exception.
+ return_value: The value returned by the call. Must be present if kind is
+ Kind.RETURNED.
+ exception: The exception raised by the call. Must be present if kind is
+ Kind.RAISED.
+ """
+ __metaclass__ = abc.ABCMeta
+
+ @enum.unique
+ class Kind(enum.Enum):
+ """Identifies the general kind of the outcome of some call."""
+
+ RETURNED = object()
+ RAISED = object()
+
+
+class _EasyOutcome(
+ collections.namedtuple(
+ '_EasyOutcome', ['kind', 'return_value', 'exception']),
+ Outcome):
+ """A trivial implementation of Outcome."""
def _call_logging_exceptions(behavior, message, *args, **kwargs):
try:
- return future.returned(behavior(*args, **kwargs))
+ return _EasyOutcome(Outcome.Kind.RETURNED, behavior(*args, **kwargs), None)
except Exception as e: # pylint: disable=broad-except
logging.exception(message)
- return future.raised(e)
+ return _EasyOutcome(Outcome.Kind.RAISED, None, e)
def with_exceptions_logged(behavior, message):
@@ -72,7 +101,7 @@ def call_logging_exceptions(behavior, message, *args, **kwargs):
**kwargs: Keyword arguments to pass to the given behavior.
Returns:
- A future.Outcome describing whether the given behavior returned a value or
- raised an exception.
+ An Outcome describing whether the given behavior returned a value or raised
+ an exception.
"""
return _call_logging_exceptions(behavior, message, *args, **kwargs)
diff --git a/src/python/src/_framework/foundation/future.py b/src/python/src/_framework/foundation/future.py
index f00c503257..bfc16fc1ea 100644
--- a/src/python/src/_framework/foundation/future.py
+++ b/src/python/src/_framework/foundation/future.py
@@ -27,146 +27,210 @@
# (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 Future interface missing from Python's standard library.
+"""A Future interface.
-Python's concurrent.futures library defines a Future class very much like the
-Future defined here, but since that class is concrete and without construction
-semantics it is only available within the concurrent.futures library itself.
-The Future class defined here is an entirely abstract interface that anyone may
+Python doesn't have a Future interface in its standard library. In the absence
+of such a standard, three separate, incompatible implementations
+(concurrent.futures.Future, ndb.Future, and asyncio.Future) have appeared. This
+interface attempts to be as compatible as possible with
+concurrent.futures.Future. From ndb.Future it adopts a traceback-object accessor
+method.
+
+Unlike the concrete and implemented Future classes listed above, the Future
+class defined in this module is an entirely abstract interface that anyone may
implement and use.
+
+The one known incompatibility between this interface and the interface of
+concurrent.futures.Future is that this interface defines its own CancelledError
+and TimeoutError exceptions rather than raising the implementation-private
+concurrent.futures._base.CancelledError and the
+built-in-but-only-in-3.3-and-later TimeoutError.
"""
import abc
-import collections
-
-RETURNED = object()
-RAISED = object()
-ABORTED = object()
-
-class Outcome(object):
- """A sum type describing the outcome of some computation.
-
- Attributes:
- category: One of RETURNED, RAISED, or ABORTED, respectively indicating
- that the computation returned a value, raised an exception, or was
- aborted.
- return_value: The value returned by the computation. Must be present if
- category is RETURNED.
- exception: The exception raised by the computation. Must be present if
- category is RAISED.
- """
- __metaclass__ = abc.ABCMeta
+class TimeoutError(Exception):
+ """Indicates that a particular call timed out."""
-class _EasyOutcome(
- collections.namedtuple('_EasyOutcome',
- ['category', 'return_value', 'exception']),
- Outcome):
- """A trivial implementation of Outcome."""
-# All Outcomes describing abortion are indistinguishable so there might as well
-# be only one.
-_ABORTED_OUTCOME = _EasyOutcome(ABORTED, None, None)
+class CancelledError(Exception):
+ """Indicates that the computation underlying a Future was cancelled."""
-def aborted():
- """Returns an Outcome indicating that a computation was aborted.
+class Future(object):
+ """A representation of a computation in another control flow.
- Returns:
- An Outcome indicating that a computation was aborted.
+ Computations represented by a Future may be yet to be begun, may be ongoing,
+ or may have already completed.
"""
- return _ABORTED_OUTCOME
-
-
-def raised(exception):
- """Returns an Outcome indicating that a computation raised an exception.
-
- Args:
- exception: The exception raised by the computation.
+ __metaclass__ = abc.ABCMeta
- Returns:
- An Outcome indicating that a computation raised the given exception.
- """
- return _EasyOutcome(RAISED, None, exception)
+ # NOTE(nathaniel): This isn't the return type that I would want to have if it
+ # were up to me. Were this interface being written from scratch, the return
+ # type of this method would probably be a sum type like:
+ #
+ # NOT_COMMENCED
+ # COMMENCED_AND_NOT_COMPLETED
+ # PARTIAL_RESULT<Partial_Result_Type>
+ # COMPLETED<Result_Type>
+ # UNCANCELLABLE
+ # NOT_IMMEDIATELY_DETERMINABLE
+ @abc.abstractmethod
+ def cancel(self):
+ """Attempts to cancel the computation.
+ This method does not block.
-def returned(value):
- """Returns an Outcome indicating that a computation returned a value.
+ Returns:
+ True if the computation has not yet begun, will not be allowed to take
+ place, and determination of both was possible without blocking. False
+ under all other circumstances including but not limited to the
+ computation's already having begun, the computation's already having
+ finished, and the computation's having been scheduled for execution on a
+ remote system for which a determination of whether or not it commenced
+ before being cancelled cannot be made without blocking.
+ """
+ raise NotImplementedError()
- Args:
- value: The value returned by the computation.
+ # NOTE(nathaniel): Here too this isn't the return type that I'd want this
+ # method to have if it were up to me. I think I'd go with another sum type
+ # like:
+ #
+ # NOT_CANCELLED (this object's cancel method hasn't been called)
+ # NOT_COMMENCED
+ # COMMENCED_AND_NOT_COMPLETED
+ # PARTIAL_RESULT<Partial_Result_Type>
+ # COMPLETED<Result_Type>
+ # UNCANCELLABLE
+ # NOT_IMMEDIATELY_DETERMINABLE
+ #
+ # Notice how giving the cancel method the right semantics obviates most
+ # reasons for this method to exist.
+ @abc.abstractmethod
+ def cancelled(self):
+ """Describes whether the computation was cancelled.
- Returns:
- An Outcome indicating that a computation returned the given value.
- """
- return _EasyOutcome(RETURNED, value, None)
+ This method does not block.
+ Returns:
+ True if the computation was cancelled any time before its result became
+ immediately available. False under all other circumstances including but
+ not limited to this object's cancel method not having been called and
+ the computation's result having become immediately available.
+ """
+ raise NotImplementedError()
-class Future(object):
- """A representation of a computation happening in another control flow.
+ @abc.abstractmethod
+ def running(self):
+ """Describes whether the computation is taking place.
- Computations represented by a Future may have already completed, may be
- ongoing, or may be yet to be begun.
+ This method does not block.
- Computations represented by a Future are considered uninterruptable; once
- started they will be allowed to terminate either by returning or raising
- an exception.
- """
- __metaclass__ = abc.ABCMeta
+ Returns:
+ True if the computation is scheduled to take place in the future or is
+ taking place now, or False if the computation took place in the past or
+ was cancelled.
+ """
+ raise NotImplementedError()
+ # NOTE(nathaniel): These aren't quite the semantics I'd like here either. I
+ # would rather this only returned True in cases in which the underlying
+ # computation completed successfully. A computation's having been cancelled
+ # conflicts with considering that computation "done".
@abc.abstractmethod
- def cancel(self):
- """Attempts to cancel the computation.
+ def done(self):
+ """Describes whether the computation has taken place.
+
+ This method does not block.
Returns:
- True if the computation will not be allowed to take place or False if
- the computation has already taken place or is currently taking place.
+ True if the computation is known to have either completed or have been
+ unscheduled or interrupted. False if the computation may possibly be
+ executing or scheduled to execute later.
"""
raise NotImplementedError()
@abc.abstractmethod
- def cancelled(self):
- """Describes whether the computation was cancelled.
+ def result(self, timeout=None):
+ """Accesses the outcome of the computation or raises its exception.
+
+ This method may return immediately or may block.
+
+ Args:
+ timeout: The length of time in seconds to wait for the computation to
+ finish or be cancelled, or None if this method should block until the
+ computation has finished or is cancelled no matter how long that takes.
Returns:
- True if the computation was cancelled and did not take place or False
- if the computation took place, is taking place, or is scheduled to
- take place in the future.
+ The return value of the computation.
+
+ Raises:
+ TimeoutError: If a timeout value is passed and the computation does not
+ terminate within the allotted time.
+ CancelledError: If the computation was cancelled.
+ Exception: If the computation raised an exception, this call will raise
+ the same exception.
"""
raise NotImplementedError()
@abc.abstractmethod
- def done(self):
- """Describes whether the computation has taken place.
+ def exception(self, timeout=None):
+ """Return the exception raised by the computation.
+
+ This method may return immediately or may block.
+
+ Args:
+ timeout: The length of time in seconds to wait for the computation to
+ terminate or be cancelled, or None if this method should block until
+ the computation is terminated or is cancelled no matter how long that
+ takes.
Returns:
- True if the computation took place; False otherwise.
+ The exception raised by the computation, or None if the computation did
+ not raise an exception.
+
+ Raises:
+ TimeoutError: If a timeout value is passed and the computation does not
+ terminate within the allotted time.
+ CancelledError: If the computation was cancelled.
"""
raise NotImplementedError()
@abc.abstractmethod
- def outcome(self):
- """Accesses the outcome of the computation.
+ def traceback(self, timeout=None):
+ """Access the traceback of the exception raised by the computation.
- If the computation has not yet completed, this method blocks until it has.
+ This method may return immediately or may block.
+
+ Args:
+ timeout: The length of time in seconds to wait for the computation to
+ terminate or be cancelled, or None if this method should block until
+ the computation is terminated or is cancelled no matter how long that
+ takes.
Returns:
- An Outcome describing the outcome of the computation.
+ The traceback of the exception raised by the computation, or None if the
+ computation did not raise an exception.
+
+ Raises:
+ TimeoutError: If a timeout value is passed and the computation does not
+ terminate within the allotted time.
+ CancelledError: If the computation was cancelled.
"""
raise NotImplementedError()
@abc.abstractmethod
- def add_done_callback(self, callback):
+ def add_done_callback(self, fn):
"""Adds a function to be called at completion of the computation.
- The callback will be passed an Outcome object describing the outcome of
+ The callback will be passed this Future object describing the outcome of
the computation.
If the computation has already completed, the callback will be called
immediately.
Args:
- callback: A callable taking an Outcome as its single parameter.
+ fn: A callable taking a this Future object as its single parameter.
"""
raise NotImplementedError()
diff --git a/src/python/src/grpc_early_adopter/__init__.py b/src/python/src/grpc_early_adopter/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/python/src/grpc_early_adopter/__init__.py
diff --git a/src/python/src/grpc_early_adopter/_face_utilities.py b/src/python/src/grpc_early_adopter/_face_utilities.py
new file mode 100644
index 0000000000..8b10be729b
--- /dev/null
+++ b/src/python/src/grpc_early_adopter/_face_utilities.py
@@ -0,0 +1,143 @@
+# 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
+
+from _framework.face import interfaces as face_interfaces
+
+from grpc_early_adopter import interfaces
+
+
+class _InlineUnaryUnaryMethod(face_interfaces.InlineValueInValueOutMethod):
+
+ def __init__(self, unary_unary_rpc_method):
+ self._method = unary_unary_rpc_method
+
+ def service(self, request, context):
+ """See face_interfaces.InlineValueInValueOutMethod.service for spec."""
+ return self._method.service_unary_unary(request)
+
+
+class _InlineUnaryStreamMethod(face_interfaces.InlineValueInStreamOutMethod):
+
+ def __init__(self, unary_stream_rpc_method):
+ self._method = unary_stream_rpc_method
+
+ def service(self, request, context):
+ """See face_interfaces.InlineValueInStreamOutMethod.service for spec."""
+ return self._method.service_unary_stream(request)
+
+
+class _InlineStreamUnaryMethod(face_interfaces.InlineStreamInValueOutMethod):
+
+ def __init__(self, stream_unary_rpc_method):
+ self._method = stream_unary_rpc_method
+
+ def service(self, request_iterator, context):
+ """See face_interfaces.InlineStreamInValueOutMethod.service for spec."""
+ return self._method.service_stream_unary(request_iterator)
+
+
+class _InlineStreamStreamMethod(face_interfaces.InlineStreamInStreamOutMethod):
+
+ def __init__(self, stream_stream_rpc_method):
+ self._method = stream_stream_rpc_method
+
+ def service(self, request_iterator, context):
+ """See face_interfaces.InlineStreamInStreamOutMethod.service for spec."""
+ return self._method.service_stream_stream(request_iterator)
+
+
+class Breakdown(object):
+ """An intermediate representation of implementations of RPC methods.
+
+ Attributes:
+ unary_unary_methods:
+ unary_stream_methods:
+ stream_unary_methods:
+ stream_stream_methods:
+ request_serializers:
+ request_deserializers:
+ response_serializers:
+ response_deserializers:
+ """
+ __metaclass__ = abc.ABCMeta
+
+
+
+class _EasyBreakdown(
+ Breakdown,
+ collections.namedtuple(
+ '_EasyBreakdown',
+ ['unary_unary_methods', 'unary_stream_methods', 'stream_unary_methods',
+ 'stream_stream_methods', 'request_serializers',
+ 'request_deserializers', 'response_serializers',
+ 'response_deserializers'])):
+ pass
+
+
+def break_down(methods):
+ """Breaks down RPC methods.
+
+ Args:
+ methods: A dictionary from RPC mthod name to
+ interfaces.RpcMethod object describing the RPCs.
+
+ Returns:
+ A Breakdown corresponding to the given methods.
+ """
+ unary_unary = {}
+ unary_stream = {}
+ stream_unary = {}
+ stream_stream = {}
+ request_serializers = {}
+ request_deserializers = {}
+ response_serializers = {}
+ response_deserializers = {}
+
+ for name, method in methods.iteritems():
+ cardinality = method.cardinality()
+ if cardinality is interfaces.Cardinality.UNARY_UNARY:
+ unary_unary[name] = _InlineUnaryUnaryMethod(method)
+ elif cardinality is interfaces.Cardinality.UNARY_STREAM:
+ unary_stream[name] = _InlineUnaryStreamMethod(method)
+ elif cardinality is interfaces.Cardinality.STREAM_UNARY:
+ stream_unary[name] = _InlineStreamUnaryMethod(method)
+ elif cardinality is interfaces.Cardinality.STREAM_STREAM:
+ stream_stream[name] = _InlineStreamStreamMethod(method)
+ request_serializers[name] = method.serialize_request
+ request_deserializers[name] = method.deserialize_request
+ response_serializers[name] = method.serialize_response
+ response_deserializers[name] = method.deserialize_response
+
+ return _EasyBreakdown(
+ unary_unary, unary_stream, stream_unary, stream_stream,
+ request_serializers, request_deserializers, response_serializers,
+ response_deserializers)
diff --git a/src/python/src/grpc_early_adopter/implementations.py b/src/python/src/grpc_early_adopter/implementations.py
new file mode 100644
index 0000000000..8a2f7fde61
--- /dev/null
+++ b/src/python/src/grpc_early_adopter/implementations.py
@@ -0,0 +1,129 @@
+# 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 _adapter import fore
+from _framework.base.packets import implementations as _tickets_implementations
+from _framework.face import implementations as _face_implementations
+from _framework.foundation import logging_pool
+from grpc_early_adopter import _face_utilities
+from grpc_early_adopter import interfaces
+
+_MEGA_TIMEOUT = 60 * 60 * 24
+_THREAD_POOL_SIZE = 80
+
+
+class _Server(interfaces.Server):
+
+ def __init__(self, breakdown, port, private_key, certificate_chain):
+ self._lock = threading.Lock()
+ self._breakdown = breakdown
+ self._port = port
+ self._private_key = private_key
+ self._certificate_chain = certificate_chain
+
+ self._pool = None
+ self._fore_link = None
+ self._back = None
+
+ def start(self):
+ """See interfaces.Server.start for specification."""
+ with self._lock:
+ if self._pool is None:
+ self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+ servicer = _face_implementations.servicer(
+ self._pool,
+ inline_value_in_value_out_methods=self._breakdown.unary_unary_methods,
+ inline_value_in_stream_out_methods=self._breakdown.unary_stream_methods,
+ inline_stream_in_value_out_methods=self._breakdown.stream_unary_methods,
+ inline_stream_in_stream_out_methods=self._breakdown.stream_stream_methods)
+ self._fore_link = fore.ForeLink(
+ self._pool, self._breakdown.request_deserializers,
+ self._breakdown.response_serializers, None,
+ ((self._private_key, self._certificate_chain),), port=self._port)
+ port = self._fore_link.start()
+ self._back = _tickets_implementations.back(
+ servicer, self._pool, self._pool, self._pool, _MEGA_TIMEOUT,
+ _MEGA_TIMEOUT)
+ self._fore_link.join_rear_link(self._back)
+ self._back.join_fore_link(self._fore_link)
+ return port
+ else:
+ raise ValueError('Server currently running!')
+
+ def stop(self):
+ """See interfaces.Server.stop for specification."""
+ with self._lock:
+ if self._pool is None:
+ raise ValueError('Server not running!')
+ else:
+ self._fore_link.stop()
+ self._pool.shutdown(wait=True)
+ self._pool = None
+
+
+def _build_server(methods, port, private_key, certificate_chain):
+ breakdown = _face_utilities.break_down(methods)
+ return _Server(breakdown, port, private_key, certificate_chain)
+
+
+def insecure_server(methods, port):
+ """Constructs an insecure interfaces.Server.
+
+ Args:
+ methods: A dictionary from RPC method name to
+ interfaces.RpcMethod object describing the RPCs to be
+ serviced by the created server.
+ port: The port on which to serve.
+
+ Returns:
+ An interfaces.Server that will run with no security and
+ service unsecured raw requests.
+ """
+ return _build_server(methods, port, None, None)
+
+
+def secure_server(methods, port, private_key, certificate_chain):
+ """Constructs a secure interfaces.Server.
+
+ Args:
+ methods: A dictionary from RPC method name to
+ interfaces.RpcMethod object describing the RPCs to be
+ serviced by the created server.
+ port: The port on which to serve.
+ private_key: A pem-encoded private key.
+ certificate_chain: A pem-encoded certificate chain.
+
+ Returns:
+ An interfaces.Server that will serve secure traffic.
+ """
+ return _build_server(methods, port, private_key, certificate_chain)
diff --git a/src/python/src/grpc_early_adopter/interfaces.py b/src/python/src/grpc_early_adopter/interfaces.py
new file mode 100644
index 0000000000..c2806c235c
--- /dev/null
+++ b/src/python/src/grpc_early_adopter/interfaces.py
@@ -0,0 +1,194 @@
+# 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
+
+
+@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'
+
+
+class RpcMethod(object):
+ """A sum type for the implementation of an RPC method."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def cardinality(self):
+ """Identifies the cardinality of this RpcMethod.
+
+ Returns:
+ A Cardinality value identifying whether or not this
+ RpcMethod is request-unary or request-streaming and
+ whether or not it is response-unary or
+ response-streaming.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def serialize_request(self, request):
+ """Serializes a request value.
+
+ Args:
+ request: A request value appropriate for this RpcMethod.
+
+ Returns:
+ The serialization of the given request value as a
+ bytestring.
+ """
+ raise NotImplementedError()
+
+ @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 this
+ RpcMethod.
+
+ 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 this RpcMethod.
+
+ Returns:
+ The serialization of the given response 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 this
+ RpcMethod.
+
+ Returns:
+ A response value corresponding to the given bytestring.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_unary_unary(self, request):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.UNARY_UNARY.
+
+ Args:
+ request: A request value appropriate for this RpcMethod.
+
+ Returns:
+ A response value appropriate for this RpcMethod.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_unary_stream(self, request):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.UNARY_STREAM.
+
+ Args:
+ request: A request value appropriate for this RpcMethod.
+
+ Yields:
+ Zero or more response values appropriate for this
+ RpcMethod.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_stream_unary(self, request_iterator):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.STREAM_UNARY.
+
+ Args:
+ request_iterator: An iterator of request values
+ appropriate for this RpcMethod.
+
+ Returns:
+ A response value appropriate for this RpcMethod.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_stream_stream(self, request_iterator):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.STREAM_STREAM.
+
+ Args:
+ request_iterator: An iterator of request values
+ appropriate for this RpcMethod.
+
+ Yields:
+ Zero or more response values appropraite for this
+ RpcMethod.
+ """
+ raise NotImplementedError()
+
+
+class Server(object):
+ """A GRPC Server."""
+ __metaclass__ = abc.ABCMeta
+
+
+ @abc.abstractmethod
+ def start(self):
+ """Instructs this server to commence service of RPCs."""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def stop(self):
+ """Instructs this server to halt service of RPCs."""
+ raise NotImplementedError()
diff --git a/src/python/src/grpc_early_adopter/utilities.py b/src/python/src/grpc_early_adopter/utilities.py
new file mode 100644
index 0000000000..333ed3a9db
--- /dev/null
+++ b/src/python/src/grpc_early_adopter/utilities.py
@@ -0,0 +1,213 @@
+# 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_early_adopter import interfaces
+
+
+class _RpcMethod(interfaces.RpcMethod):
+
+ 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.RpcMethod.cardinality for specification."""
+ return self._cardinality
+
+ def serialize_request(self, request):
+ """See interfaces.RpcMethod.serialize_request for specification."""
+ return self._request_serializer(request)
+
+ def deserialize_request(self, serialized_request):
+ """See interfaces.RpcMethod.deserialize_request for specification."""
+ return self._request_deserializer(serialized_request)
+
+ def serialize_response(self, response):
+ """See interfaces.RpcMethod.serialize_response for specification."""
+ return self._response_serializer(response)
+
+ def deserialize_response(self, serialized_response):
+ """See interfaces.RpcMethod.deserialize_response for specification."""
+ return self._response_deserializer(serialized_response)
+
+ def service_unary_unary(self, request):
+ """See interfaces.RpcMethod.service_unary_unary for specification."""
+ return self._unary_unary(request)
+
+ def service_unary_stream(self, request):
+ """See interfaces.RpcMethod.service_unary_stream for specification."""
+ return self._unary_stream(request)
+
+ def service_stream_unary(self, request_iterator):
+ """See interfaces.RpcMethod.service_stream_unary for specification."""
+ return self._stream_unary(request_iterator)
+
+ def service_stream_stream(self, request_iterator):
+ """See interfaces.RpcMethod.service_stream_stream for specification."""
+ return self._stream_stream(request_iterator)
+
+
+def unary_unary_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod for the given behavior.
+
+ Args:
+ behavior: A callable that implements a unary-unary RPC
+ method that accepts a single request and returns a single
+ response.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ 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.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a unary-request/unary-response RPC
+ method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.UNARY_UNARY, behavior, None, None, None,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
+
+
+def unary_stream_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod for the given behavior.
+
+ Args:
+ behavior: A callable that implements a unary-stream RPC
+ method that accepts a single request and returns an
+ iterator of zero or more responses.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ 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.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a unary-request/streaming-response
+ RPC method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.UNARY_STREAM, None, behavior, None, None,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
+
+
+def stream_unary_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod 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 returns a single response.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ 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.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a streaming-request/unary-response
+ RPC method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.STREAM_UNARY, None, None, behavior, None,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
+
+
+def stream_stream_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod 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 returns an iterator of zero or more responses.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ 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.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a
+ streaming-request/streaming-response RPC method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.STREAM_STREAM, None, None, None, behavior,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
diff --git a/src/python/setup.py b/src/python/src/setup.py
index 5e566bad4f..93af4d68ca 100644
--- a/src/python/setup.py
+++ b/src/python/src/setup.py
@@ -32,19 +32,17 @@
from distutils import core as _core
_EXTENSION_SOURCES = (
- 'src/_adapter/_c.c',
- 'src/_adapter/_call.c',
- 'src/_adapter/_channel.c',
- 'src/_adapter/_completion_queue.c',
- 'src/_adapter/_error.c',
- 'src/_adapter/_server.c',
- 'src/_adapter/_server_credentials.c',
+ '_adapter/_c.c',
+ '_adapter/_call.c',
+ '_adapter/_channel.c',
+ '_adapter/_completion_queue.c',
+ '_adapter/_error.c',
+ '_adapter/_server.c',
+ '_adapter/_server_credentials.c',
)
_EXTENSION_INCLUDE_DIRECTORIES = (
- 'src',
- # TODO(nathaniel): Can this path specification be made to work?
- #'../../include',
+ '.',
)
_EXTENSION_LIBRARIES = (
@@ -52,16 +50,11 @@ _EXTENSION_LIBRARIES = (
'grpc',
)
-_EXTENSION_LIBRARY_DIRECTORIES = (
- # TODO(nathaniel): Can this path specification be made to work?
- #'../../libs/dbg',
-)
-
_EXTENSION_MODULE = _core.Extension(
'_adapter._c', sources=list(_EXTENSION_SOURCES),
include_dirs=_EXTENSION_INCLUDE_DIRECTORIES,
libraries=_EXTENSION_LIBRARIES,
- library_dirs=_EXTENSION_LIBRARY_DIRECTORIES)
+ )
_PACKAGES=(
'_adapter',
@@ -73,15 +66,17 @@ _PACKAGES=(
'_framework.face.testing',
'_framework.foundation',
'_junkdrawer',
+ 'grpc_early_adopter',
)
_PACKAGE_DIRECTORIES = {
- '_adapter': 'src/_adapter',
- '_framework': 'src/_framework',
- '_junkdrawer': 'src/_junkdrawer',
+ '_adapter': '_adapter',
+ '_framework': '_framework',
+ '_junkdrawer': '_junkdrawer',
+ 'grpc_early_adopter': 'grpc_early_adopter',
}
_core.setup(
- name='grpc', version='0.0.1',
+ name='grpc-2015', version='0.0.1',
ext_modules=[_EXTENSION_MODULE], packages=_PACKAGES,
package_dir=_PACKAGE_DIRECTORIES)
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index f5acae896a..1321727f5c 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -362,9 +362,11 @@ describe 'the secure http client/server' do
@server.close
end
- it_behaves_like 'basic GRPC message delivery is OK' do
- end
+ # TODO: uncomment after updating the to the new c api
+ # it_behaves_like 'basic GRPC message delivery is OK' do
+ # end
- it_behaves_like 'GRPC metadata delivery works OK' do
- end
+ # TODO: uncomment after updating the to the new c api
+ # it_behaves_like 'GRPC metadata delivery works OK' do
+ # end
end