aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/node/ext
diff options
context:
space:
mode:
Diffstat (limited to 'src/node/ext')
-rw-r--r--src/node/ext/byte_buffer.cc79
-rw-r--r--src/node/ext/byte_buffer.h56
-rw-r--r--src/node/ext/call.cc385
-rw-r--r--src/node/ext/call.h82
-rw-r--r--src/node/ext/channel.cc182
-rw-r--r--src/node/ext/channel.h79
-rw-r--r--src/node/ext/completion_queue_async_worker.cc89
-rw-r--r--src/node/ext/completion_queue_async_worker.h79
-rw-r--r--src/node/ext/credentials.cc204
-rw-r--r--src/node/ext/credentials.h81
-rw-r--r--src/node/ext/event.cc164
-rw-r--r--src/node/ext/event.h48
-rw-r--r--src/node/ext/node_grpc.cc180
-rw-r--r--src/node/ext/server.cc236
-rw-r--r--src/node/ext/server.h79
-rw-r--r--src/node/ext/server_credentials.cc155
-rw-r--r--src/node/ext/server_credentials.h77
-rw-r--r--src/node/ext/tag.cc101
-rw-r--r--src/node/ext/tag.h59
-rw-r--r--src/node/ext/timeval.cc66
-rw-r--r--src/node/ext/timeval.h48
21 files changed, 2529 insertions, 0 deletions
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
new file mode 100644
index 0000000000..142951475a
--- /dev/null
+++ b/src/node/ext/byte_buffer.cc
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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 <string.h>
+#include <malloc.h>
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/support/slice.h"
+
+namespace grpc {
+namespace node {
+
+#include "byte_buffer.h"
+
+using ::node::Buffer;
+using v8::Handle;
+using v8::Value;
+
+grpc_byte_buffer *BufferToByteBuffer(Handle<Value> buffer) {
+ NanScope();
+ int length = Buffer::Length(buffer);
+ char *data = Buffer::Data(buffer);
+ gpr_slice slice = gpr_slice_malloc(length);
+ memcpy(GPR_SLICE_START_PTR(slice), data, length);
+ grpc_byte_buffer *byte_buffer(grpc_byte_buffer_create(&slice, 1));
+ gpr_slice_unref(slice);
+ return byte_buffer;
+}
+
+Handle<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
+ NanEscapableScope();
+ if (buffer == NULL) {
+ NanReturnNull();
+ }
+ size_t length = grpc_byte_buffer_length(buffer);
+ char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
+ size_t offset = 0;
+ grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
+ gpr_slice next;
+ while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
+ memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
+ offset += GPR_SLICE_LENGTH(next);
+ }
+ return NanEscapeScope(NanNewBufferHandle(result, length));
+}
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/byte_buffer.h b/src/node/ext/byte_buffer.h
new file mode 100644
index 0000000000..ee2b4c0d15
--- /dev/null
+++ b/src/node/ext/byte_buffer.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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_BYTE_BUFFER_H_
+#define NET_GRPC_NODE_BYTE_BUFFER_H_
+
+#include <string.h>
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* Convert a Node.js Buffer to grpc_byte_buffer. Requires that
+ ::node::Buffer::HasInstance(buffer) */
+grpc_byte_buffer *BufferToByteBuffer(v8::Handle<v8::Value> buffer);
+
+/* Convert a grpc_byte_buffer to a Node.js Buffer */
+v8::Handle<v8::Value> ByteBufferToBuffer(grpc_byte_buffer *buffer);
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_BYTE_BUFFER_H_
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
new file mode 100644
index 0000000000..6434c2f0d5
--- /dev/null
+++ b/src/node/ext/call.cc
@@ -0,0 +1,385 @@
+/*
+ *
+ * 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 <node.h>
+
+#include "grpc/grpc.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"
+
+namespace grpc {
+namespace node {
+
+using ::node::Buffer;
+using v8::Arguments;
+using v8::Array;
+using v8::Exception;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::Uint32;
+using v8::String;
+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); }
+
+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, "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"),
+ NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
+ constructor->Set(NanNew("WRITE_NO_COMPRESS"),
+ NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
+ exports->Set(String::NewSymbol("Call"), constructor);
+}
+
+bool Call::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+Handle<Value> Call::WrapStruct(grpc_call *call) {
+ NanEscapableScope();
+ if (call == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ const int argc = 1;
+ Handle<Value> argv[argc] = {External::New(reinterpret_cast<void *>(call))};
+ return NanEscapeScope(constructor->NewInstance(argc, argv));
+}
+
+NAN_METHOD(Call::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ Call *call;
+ if (args[0]->IsExternal()) {
+ // This option is used for wrapping an existing call
+ grpc_call *call_value =
+ reinterpret_cast<grpc_call *>(External::Unwrap(args[0]));
+ call = new Call(call_value);
+ } else {
+ if (!Channel::HasInstance(args[0])) {
+ return NanThrowTypeError("Call's first argument must be a Channel");
+ }
+ if (!args[1]->IsString()) {
+ return NanThrowTypeError("Call's second argument must be a string");
+ }
+ if (!(args[2]->IsNumber() || args[2]->IsDate())) {
+ return NanThrowTypeError(
+ "Call's third argument must be a date or a number");
+ }
+ Handle<Object> channel_object = args[0]->ToObject();
+ Channel *channel = ObjectWrap::Unwrap<Channel>(channel_object);
+ if (channel->GetWrappedChannel() == NULL) {
+ return NanThrowError("Call cannot be created from a closed channel");
+ }
+ NanUtf8String method(args[1]);
+ double deadline = args[2]->NumberValue();
+ grpc_channel *wrapped_channel = channel->GetWrappedChannel();
+ grpc_call *wrapped_call =
+ grpc_channel_create_call(wrapped_channel, *method, channel->GetHost(),
+ MillisecondsToTimespec(deadline));
+ call = new Call(wrapped_call);
+ args.This()->SetHiddenValue(String::NewSymbol("channel_"),
+ channel_object);
+ }
+ call->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 4;
+ Local<Value> argv[argc] = {args[0], args[1], args[2], args[3]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(Call::AddMetadata) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("addMetadata can only be called on Call objects");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ for (int i = 0; !args[i]->IsUndefined(); i++) {
+ if (!args[i]->IsObject()) {
+ return NanThrowTypeError(
+ "addMetadata arguments must be objects with key and value");
+ }
+ Handle<Object> item = args[i]->ToObject();
+ Handle<Value> key = item->Get(NanNew("key"));
+ if (!key->IsString()) {
+ return NanThrowTypeError(
+ "objects passed to addMetadata must have key->string");
+ }
+ Handle<Value> value = item->Get(NanNew("value"));
+ if (!Buffer::HasInstance(value)) {
+ return NanThrowTypeError(
+ "objects passed to addMetadata must have value->Buffer");
+ }
+ grpc_metadata metadata;
+ NanUtf8String utf8_key(key);
+ metadata.key = *utf8_key;
+ metadata.value = Buffer::Data(value);
+ metadata.value_length = Buffer::Length(value);
+ grpc_call_error error =
+ grpc_call_add_metadata(call->wrapped_call, &metadata, 0);
+ 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");
+ }
+ 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(
+ 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");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_call_error error = grpc_call_server_accept(
+ 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");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ unsigned int flags = args[1]->Uint32Value();
+ grpc_call_error error =
+ grpc_call_server_end_initial_metadata(call->wrapped_call, flags);
+ if (error != GRPC_CALL_OK) {
+ return NanThrowError("serverEndInitialMetadata failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::Cancel) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("cancel can only be called on Call objects");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_call_error error = grpc_call_cancel(call->wrapped_call);
+ if (error != GRPC_CALL_OK) {
+ return NanThrowError("cancel failed", error);
+ }
+ 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(
+ 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(
+ 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(
+ 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(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
new file mode 100644
index 0000000000..1924a1bf42
--- /dev/null
+++ b/src/node/ext/call.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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_CALL_H_
+#define NET_GRPC_NODE_CALL_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+#include "channel.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_call structs. */
+class Call : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* Wrap a grpc_call struct in a javascript object */
+ static v8::Handle<v8::Value> WrapStruct(grpc_call *call);
+
+ private:
+ explicit Call(grpc_call *call);
+ ~Call();
+
+ // Prevent copying
+ Call(const Call &);
+ 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(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;
+
+ grpc_call *wrapped_call;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_CALL_H_
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
new file mode 100644
index 0000000000..9087d6f919
--- /dev/null
+++ b/src/node/ext/channel.cc
@@ -0,0 +1,182 @@
+/*
+ *
+ * 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 <malloc.h>
+
+#include <vector>
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "channel.h"
+#include "credentials.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Arguments;
+using v8::Array;
+using v8::Exception;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> Channel::constructor;
+Persistent<FunctionTemplate> Channel::fun_tpl;
+
+Channel::Channel(grpc_channel *channel, NanUtf8String *host)
+ : wrapped_channel(channel), host(host) {}
+
+Channel::~Channel() {
+ if (wrapped_channel != NULL) {
+ grpc_channel_destroy(wrapped_channel);
+ }
+ delete host;
+}
+
+void Channel::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(NanNew("Channel"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanSetPrototypeTemplate(tpl, "close",
+ FunctionTemplate::New(Close)->GetFunction());
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ exports->Set(NanNew("Channel"), constructor);
+}
+
+bool Channel::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; }
+
+char *Channel::GetHost() { return **this->host; }
+
+NAN_METHOD(Channel::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("Channel expects a string and an object");
+ }
+ grpc_channel *wrapped_channel;
+ // Owned by the Channel object
+ NanUtf8String *host = new NanUtf8String(args[0]);
+ if (args[1]->IsUndefined()) {
+ wrapped_channel = grpc_channel_create(**host, NULL);
+ } else if (args[1]->IsObject()) {
+ grpc_credentials *creds = NULL;
+ Handle<Object> args_hash(args[1]->ToObject()->Clone());
+ if (args_hash->HasOwnProperty(NanNew("credentials"))) {
+ Handle<Value> creds_value = args_hash->Get(NanNew("credentials"));
+ if (!Credentials::HasInstance(creds_value)) {
+ return NanThrowTypeError(
+ "credentials arg must be a Credentials object");
+ }
+ Credentials *creds_object =
+ ObjectWrap::Unwrap<Credentials>(creds_value->ToObject());
+ creds = creds_object->GetWrappedCredentials();
+ args_hash->Delete(NanNew("credentials"));
+ }
+ Handle<Array> keys(args_hash->GetOwnPropertyNames());
+ grpc_channel_args channel_args;
+ channel_args.num_args = keys->Length();
+ channel_args.args = reinterpret_cast<grpc_arg *>(
+ calloc(channel_args.num_args, sizeof(grpc_arg)));
+ /* These are used to keep all strings until then end of the block, then
+ destroy them */
+ std::vector<NanUtf8String *> key_strings(keys->Length());
+ std::vector<NanUtf8String *> value_strings(keys->Length());
+ for (unsigned int i = 0; i < channel_args.num_args; i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ Handle<Value> current_value(args_hash->Get(current_key));
+ key_strings[i] = new NanUtf8String(current_key);
+ channel_args.args[i].key = **key_strings[i];
+ if (current_value->IsInt32()) {
+ channel_args.args[i].type = GRPC_ARG_INTEGER;
+ channel_args.args[i].value.integer = current_value->Int32Value();
+ } else if (current_value->IsString()) {
+ channel_args.args[i].type = GRPC_ARG_STRING;
+ value_strings[i] = new NanUtf8String(current_value);
+ channel_args.args[i].value.string = **value_strings[i];
+ } else {
+ free(channel_args.args);
+ return NanThrowTypeError("Arg values must be strings");
+ }
+ }
+ if (creds == NULL) {
+ wrapped_channel = grpc_channel_create(**host, &channel_args);
+ } else {
+ wrapped_channel =
+ grpc_secure_channel_create(creds, **host, &channel_args);
+ }
+ free(channel_args.args);
+ } else {
+ return NanThrowTypeError("Channel expects a string and an object");
+ }
+ Channel *channel = new Channel(wrapped_channel, host);
+ channel->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 2;
+ Local<Value> argv[argc] = {args[0], args[1]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(Channel::Close) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("close can only be called on Channel objects");
+ }
+ Channel *channel = ObjectWrap::Unwrap<Channel>(args.This());
+ if (channel->wrapped_channel != NULL) {
+ grpc_channel_destroy(channel->wrapped_channel);
+ channel->wrapped_channel = NULL;
+ }
+ NanReturnUndefined();
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/channel.h b/src/node/ext/channel.h
new file mode 100644
index 0000000000..140cbf201a
--- /dev/null
+++ b/src/node/ext/channel.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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_CHANNEL_H_
+#define NET_GRPC_NODE_CHANNEL_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_channel structs */
+class Channel : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* This is used to typecheck javascript objects before converting them to
+ this type */
+ static v8::Persistent<v8::Value> prototype;
+
+ /* Returns the grpc_channel struct that this object wraps */
+ grpc_channel *GetWrappedChannel();
+
+ /* Return the hostname that this channel connects to */
+ char *GetHost();
+
+ private:
+ explicit Channel(grpc_channel *channel, NanUtf8String *host);
+ ~Channel();
+
+ // Prevent copying
+ Channel(const Channel &);
+ Channel &operator=(const Channel &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(Close);
+ static v8::Persistent<v8::Function> constructor;
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_channel *wrapped_channel;
+ NanUtf8String *host;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_CHANNEL_H_
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
new file mode 100644
index 0000000000..8de7db66d5
--- /dev/null
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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 <node.h>
+#include <nan.h>
+
+#include "grpc/grpc.h"
+#include "grpc/support/time.h"
+#include "completion_queue_async_worker.h"
+#include "event.h"
+#include "tag.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Function;
+using v8::Handle;
+using v8::Object;
+using v8::Persistent;
+using v8::Value;
+
+grpc_completion_queue *CompletionQueueAsyncWorker::queue;
+
+CompletionQueueAsyncWorker::CompletionQueueAsyncWorker()
+ : NanAsyncWorker(NULL) {}
+
+CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {}
+
+void CompletionQueueAsyncWorker::Execute() {
+ result = grpc_completion_queue_next(queue, gpr_inf_future);
+}
+
+grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; }
+
+void CompletionQueueAsyncWorker::Next() {
+ NanScope();
+ CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker();
+ NanAsyncQueueWorker(worker);
+}
+
+void CompletionQueueAsyncWorker::Init(Handle<Object> exports) {
+ NanScope();
+ queue = grpc_completion_queue_create();
+}
+
+void CompletionQueueAsyncWorker::HandleOKCallback() {
+ NanScope();
+ NanCallback event_callback(GetTagHandle(result->tag).As<Function>());
+ Handle<Value> argv[] = {CreateEventObject(result)};
+
+ DestroyTag(result->tag);
+ grpc_event_finish(result);
+ result = NULL;
+
+ event_callback.Call(1, argv);
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/completion_queue_async_worker.h b/src/node/ext/completion_queue_async_worker.h
new file mode 100644
index 0000000000..2c928b7024
--- /dev/null
+++ b/src/node/ext/completion_queue_async_worker.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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_COMPLETION_QUEUE_ASYNC_WORKER_H_
+#define NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
+#include <nan.h>
+
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* A worker that asynchronously calls completion_queue_next, and queues onto the
+ node event loop a call to the function stored in the event's tag. */
+class CompletionQueueAsyncWorker : public NanAsyncWorker {
+ public:
+ CompletionQueueAsyncWorker();
+
+ ~CompletionQueueAsyncWorker();
+ /* Calls completion_queue_next with the provided deadline, and stores the
+ event if there was one or sets an error message if there was not */
+ void Execute();
+
+ /* Returns the completion queue attached to this class */
+ static grpc_completion_queue *GetQueue();
+
+ /* Convenience function to create a worker with the given arguments and queue
+ it to run asynchronously */
+ static void Next();
+
+ /* Initialize the CompletionQueueAsyncWorker class */
+ static void Init(v8::Handle<v8::Object> exports);
+
+ protected:
+ /* Called when Execute has succeeded (completed without setting an error
+ message). Calls the saved callback with the event that came from
+ completion_queue_next */
+ void HandleOKCallback();
+
+ private:
+ grpc_event *result;
+
+ static grpc_completion_queue *queue;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc
new file mode 100644
index 0000000000..c8859ed941
--- /dev/null
+++ b/src/node/ext/credentials.cc
@@ -0,0 +1,204 @@
+/*
+ *
+ * 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 <node.h>
+
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpc/support/log.h"
+#include "credentials.h"
+
+namespace grpc {
+namespace node {
+
+using ::node::Buffer;
+using v8::Arguments;
+using v8::Exception;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::Value;
+
+Persistent<Function> Credentials::constructor;
+Persistent<FunctionTemplate> Credentials::fun_tpl;
+
+Credentials::Credentials(grpc_credentials *credentials)
+ : wrapped_credentials(credentials) {}
+
+Credentials::~Credentials() {
+ gpr_log(GPR_DEBUG, "Destroying credentials object");
+ grpc_credentials_release(wrapped_credentials);
+}
+
+void Credentials::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(NanNew("Credentials"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ constructor->Set(NanNew("createDefault"),
+ FunctionTemplate::New(CreateDefault)->GetFunction());
+ constructor->Set(NanNew("createSsl"),
+ FunctionTemplate::New(CreateSsl)->GetFunction());
+ constructor->Set(NanNew("createComposite"),
+ FunctionTemplate::New(CreateComposite)->GetFunction());
+ constructor->Set(NanNew("createGce"),
+ FunctionTemplate::New(CreateGce)->GetFunction());
+ constructor->Set(NanNew("createFake"),
+ FunctionTemplate::New(CreateFake)->GetFunction());
+ constructor->Set(NanNew("createIam"),
+ FunctionTemplate::New(CreateIam)->GetFunction());
+ exports->Set(NanNew("Credentials"), constructor);
+}
+
+bool Credentials::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+Handle<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
+ NanEscapableScope();
+ if (credentials == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ const int argc = 1;
+ Handle<Value> argv[argc] = {
+ External::New(reinterpret_cast<void *>(credentials))};
+ return NanEscapeScope(constructor->NewInstance(argc, argv));
+}
+
+grpc_credentials *Credentials::GetWrappedCredentials() {
+ return wrapped_credentials;
+}
+
+NAN_METHOD(Credentials::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ if (!args[0]->IsExternal()) {
+ return NanThrowTypeError(
+ "Credentials can only be created with the provided functions");
+ }
+ grpc_credentials *creds_value =
+ reinterpret_cast<grpc_credentials *>(External::Unwrap(args[0]));
+ Credentials *credentials = new Credentials(creds_value);
+ credentials->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 1;
+ Local<Value> argv[argc] = {args[0]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(Credentials::CreateDefault) {
+ NanScope();
+ NanReturnValue(WrapStruct(grpc_default_credentials_create()));
+}
+
+NAN_METHOD(Credentials::CreateSsl) {
+ NanScope();
+ char *root_certs = NULL;
+ grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
+ if (Buffer::HasInstance(args[0])) {
+ root_certs = Buffer::Data(args[0]);
+ } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) {
+ return NanThrowTypeError("createSsl's first argument must be a Buffer");
+ }
+ if (Buffer::HasInstance(args[1])) {
+ key_cert_pair.private_key = Buffer::Data(args[1]);
+ } else if (!(args[1]->IsNull() || args[1]->IsUndefined())) {
+ return NanThrowTypeError(
+ "createSSl's second argument must be a Buffer if provided");
+ }
+ if (Buffer::HasInstance(args[2])) {
+ key_cert_pair.cert_chain = Buffer::Data(args[2]);
+ } else if (!(args[2]->IsNull() || args[2]->IsUndefined())) {
+ return NanThrowTypeError(
+ "createSSl's third argument must be a Buffer if provided");
+ }
+
+ NanReturnValue(WrapStruct(grpc_ssl_credentials_create(
+ root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair)));
+}
+
+NAN_METHOD(Credentials::CreateComposite) {
+ NanScope();
+ if (!HasInstance(args[0])) {
+ return NanThrowTypeError(
+ "createComposite's first argument must be a Credentials object");
+ }
+ if (!HasInstance(args[1])) {
+ return NanThrowTypeError(
+ "createComposite's second argument must be a Credentials object");
+ }
+ Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(args[0]->ToObject());
+ Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(args[1]->ToObject());
+ NanReturnValue(WrapStruct(grpc_composite_credentials_create(
+ creds1->wrapped_credentials, creds2->wrapped_credentials)));
+}
+
+NAN_METHOD(Credentials::CreateGce) {
+ NanScope();
+ NanReturnValue(WrapStruct(grpc_compute_engine_credentials_create()));
+}
+
+NAN_METHOD(Credentials::CreateFake) {
+ NanScope();
+ NanReturnValue(WrapStruct(grpc_fake_transport_security_credentials_create()));
+}
+
+NAN_METHOD(Credentials::CreateIam) {
+ NanScope();
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("createIam's first argument must be a string");
+ }
+ if (!args[1]->IsString()) {
+ return NanThrowTypeError("createIam's second argument must be a string");
+ }
+ NanUtf8String auth_token(args[0]);
+ NanUtf8String auth_selector(args[1]);
+ NanReturnValue(
+ WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector)));
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/credentials.h b/src/node/ext/credentials.h
new file mode 100644
index 0000000000..981e5a99bc
--- /dev/null
+++ b/src/node/ext/credentials.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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_CREDENTIALS_H_
+#define NET_GRPC_NODE_CREDENTIALS_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_credentials structs */
+class Credentials : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* Wrap a grpc_credentials struct in a javascript object */
+ static v8::Handle<v8::Value> WrapStruct(grpc_credentials *credentials);
+
+ /* Returns the grpc_credentials struct that this object wraps */
+ grpc_credentials *GetWrappedCredentials();
+
+ private:
+ explicit Credentials(grpc_credentials *credentials);
+ ~Credentials();
+
+ // Prevent copying
+ Credentials(const Credentials &);
+ Credentials &operator=(const Credentials &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(CreateDefault);
+ static NAN_METHOD(CreateSsl);
+ static NAN_METHOD(CreateComposite);
+ static NAN_METHOD(CreateGce);
+ static NAN_METHOD(CreateFake);
+ static NAN_METHOD(CreateIam);
+ static v8::Persistent<v8::Function> constructor;
+ // Used for typechecking instances of this javascript class
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_credentials *wrapped_credentials;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_CREDENTIALS_H_
diff --git a/src/node/ext/event.cc b/src/node/ext/event.cc
new file mode 100644
index 0000000000..2ca38b7448
--- /dev/null
+++ b/src/node/ext/event.cc
@@ -0,0 +1,164 @@
+/*
+ *
+ * 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 <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 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> 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_INVOKE_ACCEPTED:
+ return NanEscapeScope(NanNew<Number>(event->data.invoke_accepted));
+ 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;
+ metadata = NanNew<Array>(static_cast<int>(count));
+ for (unsigned int i = 0; i < count; i++) {
+ Handle<Object> item_obj = NanNew<Object>();
+ item_obj->Set(NanNew<String, const char *>("key"),
+ NanNew<String, char *>(items[i].key));
+ item_obj->Set(
+ NanNew<String, const char *>("value"),
+ NanNew<String, char *>(items[i].value,
+ static_cast<int>(items[i].value_length)));
+ metadata->Set(i, item_obj);
+ }
+ return NanEscapeScope(metadata);
+ 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;
+ metadata = NanNew<Array>(static_cast<int>(count));
+ for (unsigned int i = 0; i < count; i++) {
+ Handle<Object> item_obj = NanNew<Object>();
+ item_obj->Set(NanNew<String, const char *>("key"),
+ NanNew<String, char *>(items[i].key));
+ item_obj->Set(
+ NanNew<String, const char *>("value"),
+ NanNew<String, char *>(items[i].value,
+ static_cast<int>(items[i].value_length)));
+ metadata->Set(i, item_obj);
+ }
+ status->Set(NanNew("metadata"), metadata);
+ 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<String, const char *>("method"),
+ NanNew<String, const char *>(event->data.server_rpc_new.method));
+ rpc_new->Set(
+ NanNew<String, const char *>("host"),
+ NanNew<String, const char *>(event->data.server_rpc_new.host));
+ rpc_new->Set(NanNew<String, const char *>("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<String, const char *>("key"),
+ NanNew<String, char *>(items[i].key));
+ item_obj->Set(
+ NanNew<String, const char *>("value"),
+ NanNew<String, char *>(items[i].value,
+ static_cast<int>(items[i].value_length)));
+ metadata->Set(i, item_obj);
+ }
+ rpc_new->Set(NanNew<String, const char *>("metadata"), metadata);
+ 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
new file mode 100644
index 0000000000..e06d8f0168
--- /dev/null
+++ b/src/node/ext/event.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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
new file mode 100644
index 0000000000..bc1dfaf899
--- /dev/null
+++ b/src/node/ext/node_grpc.cc
@@ -0,0 +1,180 @@
+/*
+ *
+ * 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 <node.h>
+#include <nan.h>
+#include <v8.h>
+#include "grpc/grpc.h"
+
+#include "call.h"
+#include "channel.h"
+#include "event.h"
+#include "server.h"
+#include "completion_queue_async_worker.h"
+#include "credentials.h"
+#include "server_credentials.h"
+
+using v8::Handle;
+using v8::Value;
+using v8::Object;
+using v8::Uint32;
+using v8::String;
+
+void InitStatusConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> status = Object::New();
+ exports->Set(NanNew("status"), status);
+ Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_STATUS_OK));
+ status->Set(NanNew("OK"), OK);
+ Handle<Value> CANCELLED(NanNew<Uint32, uint32_t>(GRPC_STATUS_CANCELLED));
+ status->Set(NanNew("CANCELLED"), CANCELLED);
+ Handle<Value> UNKNOWN(NanNew<Uint32, uint32_t>(GRPC_STATUS_UNKNOWN));
+ status->Set(NanNew("UNKNOWN"), UNKNOWN);
+ Handle<Value> INVALID_ARGUMENT(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_INVALID_ARGUMENT));
+ status->Set(NanNew("INVALID_ARGUMENT"), INVALID_ARGUMENT);
+ Handle<Value> DEADLINE_EXCEEDED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_DEADLINE_EXCEEDED));
+ status->Set(NanNew("DEADLINE_EXCEEDED"), DEADLINE_EXCEEDED);
+ Handle<Value> NOT_FOUND(NanNew<Uint32, uint32_t>(GRPC_STATUS_NOT_FOUND));
+ status->Set(NanNew("NOT_FOUND"), NOT_FOUND);
+ Handle<Value> ALREADY_EXISTS(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_ALREADY_EXISTS));
+ status->Set(NanNew("ALREADY_EXISTS"), ALREADY_EXISTS);
+ Handle<Value> PERMISSION_DENIED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_PERMISSION_DENIED));
+ status->Set(NanNew("PERMISSION_DENIED"), PERMISSION_DENIED);
+ Handle<Value> UNAUTHENTICATED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_UNAUTHENTICATED));
+ status->Set(NanNew("UNAUTHENTICATED"), UNAUTHENTICATED);
+ Handle<Value> RESOURCE_EXHAUSTED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_RESOURCE_EXHAUSTED));
+ status->Set(NanNew("RESOURCE_EXHAUSTED"), RESOURCE_EXHAUSTED);
+ Handle<Value> FAILED_PRECONDITION(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_FAILED_PRECONDITION));
+ status->Set(NanNew("FAILED_PRECONDITION"), FAILED_PRECONDITION);
+ Handle<Value> ABORTED(NanNew<Uint32, uint32_t>(GRPC_STATUS_ABORTED));
+ status->Set(NanNew("ABORTED"), ABORTED);
+ Handle<Value> OUT_OF_RANGE(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_OUT_OF_RANGE));
+ status->Set(NanNew("OUT_OF_RANGE"), OUT_OF_RANGE);
+ Handle<Value> UNIMPLEMENTED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_UNIMPLEMENTED));
+ status->Set(NanNew("UNIMPLEMENTED"), UNIMPLEMENTED);
+ Handle<Value> INTERNAL(NanNew<Uint32, uint32_t>(GRPC_STATUS_INTERNAL));
+ status->Set(NanNew("INTERNAL"), INTERNAL);
+ Handle<Value> UNAVAILABLE(NanNew<Uint32, uint32_t>(GRPC_STATUS_UNAVAILABLE));
+ status->Set(NanNew("UNAVAILABLE"), UNAVAILABLE);
+ Handle<Value> DATA_LOSS(NanNew<Uint32, uint32_t>(GRPC_STATUS_DATA_LOSS));
+ status->Set(NanNew("DATA_LOSS"), DATA_LOSS);
+}
+
+void InitCallErrorConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> call_error = Object::New();
+ exports->Set(NanNew("callError"), call_error);
+ Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_CALL_OK));
+ call_error->Set(NanNew("OK"), OK);
+ Handle<Value> ERROR(NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR));
+ call_error->Set(NanNew("ERROR"), ERROR);
+ Handle<Value> NOT_ON_SERVER(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_ON_SERVER));
+ call_error->Set(NanNew("NOT_ON_SERVER"), NOT_ON_SERVER);
+ Handle<Value> NOT_ON_CLIENT(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_ON_CLIENT));
+ call_error->Set(NanNew("NOT_ON_CLIENT"), NOT_ON_CLIENT);
+ Handle<Value> ALREADY_INVOKED(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_ALREADY_INVOKED));
+ call_error->Set(NanNew("ALREADY_INVOKED"), ALREADY_INVOKED);
+ Handle<Value> NOT_INVOKED(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_INVOKED));
+ call_error->Set(NanNew("NOT_INVOKED"), NOT_INVOKED);
+ Handle<Value> ALREADY_FINISHED(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_ALREADY_FINISHED));
+ call_error->Set(NanNew("ALREADY_FINISHED"), ALREADY_FINISHED);
+ Handle<Value> TOO_MANY_OPERATIONS(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
+ call_error->Set(NanNew("TOO_MANY_OPERATIONS"), TOO_MANY_OPERATIONS);
+ Handle<Value> INVALID_FLAGS(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_INVALID_FLAGS));
+ call_error->Set(NanNew("INVALID_FLAGS"), INVALID_FLAGS);
+}
+
+void InitOpErrorConstants(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);
+}
+
+void init(Handle<Object> exports) {
+ NanScope();
+ grpc_init();
+ InitStatusConstants(exports);
+ InitCallErrorConstants(exports);
+ InitOpErrorConstants(exports);
+ InitCompletionTypeConstants(exports);
+
+ grpc::node::Call::Init(exports);
+ grpc::node::Channel::Init(exports);
+ grpc::node::Server::Init(exports);
+ grpc::node::CompletionQueueAsyncWorker::Init(exports);
+ grpc::node::Credentials::Init(exports);
+ grpc::node::ServerCredentials::Init(exports);
+}
+
+NODE_MODULE(grpc, init)
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
new file mode 100644
index 0000000000..b102775d33
--- /dev/null
+++ b/src/node/ext/server.cc
@@ -0,0 +1,236 @@
+/*
+ *
+ * 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 "server.h"
+
+#include <node.h>
+#include <nan.h>
+
+#include <malloc.h>
+
+#include <vector>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "call.h"
+#include "completion_queue_async_worker.h"
+#include "tag.h"
+#include "server_credentials.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Arguments;
+using v8::Array;
+using v8::Boolean;
+using v8::Exception;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> Server::constructor;
+Persistent<FunctionTemplate> Server::fun_tpl;
+
+Server::Server(grpc_server *server) : wrapped_server(server) {}
+
+Server::~Server() { grpc_server_destroy(wrapped_server); }
+
+void Server::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(String::NewSymbol("Server"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanSetPrototypeTemplate(tpl, "requestCall",
+ FunctionTemplate::New(RequestCall)->GetFunction());
+
+ NanSetPrototypeTemplate(tpl, "addHttp2Port",
+ FunctionTemplate::New(AddHttp2Port)->GetFunction());
+
+ NanSetPrototypeTemplate(
+ tpl, "addSecureHttp2Port",
+ FunctionTemplate::New(AddSecureHttp2Port)->GetFunction());
+
+ NanSetPrototypeTemplate(tpl, "start",
+ FunctionTemplate::New(Start)->GetFunction());
+
+ NanSetPrototypeTemplate(tpl, "shutdown",
+ FunctionTemplate::New(Shutdown)->GetFunction());
+
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ exports->Set(String::NewSymbol("Server"), constructor);
+}
+
+bool Server::HasInstance(Handle<Value> val) {
+ return NanHasInstance(fun_tpl, val);
+}
+
+NAN_METHOD(Server::New) {
+ NanScope();
+
+ /* If this is not a constructor call, make a constructor call and return
+ the result */
+ if (!args.IsConstructCall()) {
+ const int argc = 1;
+ Local<Value> argv[argc] = {args[0]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+ grpc_server *wrapped_server;
+ grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue();
+ if (args[0]->IsUndefined()) {
+ wrapped_server = grpc_server_create(queue, NULL);
+ } else if (args[0]->IsObject()) {
+ grpc_server_credentials *creds = NULL;
+ Handle<Object> args_hash(args[0]->ToObject()->Clone());
+ if (args_hash->HasOwnProperty(NanNew("credentials"))) {
+ Handle<Value> creds_value = args_hash->Get(NanNew("credentials"));
+ if (!ServerCredentials::HasInstance(creds_value)) {
+ return NanThrowTypeError(
+ "credentials arg must be a ServerCredentials object");
+ }
+ ServerCredentials *creds_object =
+ ObjectWrap::Unwrap<ServerCredentials>(creds_value->ToObject());
+ creds = creds_object->GetWrappedServerCredentials();
+ args_hash->Delete(NanNew("credentials"));
+ }
+ Handle<Array> keys(args_hash->GetOwnPropertyNames());
+ grpc_channel_args channel_args;
+ channel_args.num_args = keys->Length();
+ channel_args.args = reinterpret_cast<grpc_arg *>(
+ calloc(channel_args.num_args, sizeof(grpc_arg)));
+ /* These are used to keep all strings until then end of the block, then
+ destroy them */
+ std::vector<NanUtf8String *> key_strings(keys->Length());
+ std::vector<NanUtf8String *> value_strings(keys->Length());
+ for (unsigned int i = 0; i < channel_args.num_args; i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ Handle<Value> current_value(args_hash->Get(current_key));
+ key_strings[i] = new NanUtf8String(current_key);
+ channel_args.args[i].key = **key_strings[i];
+ if (current_value->IsInt32()) {
+ channel_args.args[i].type = GRPC_ARG_INTEGER;
+ channel_args.args[i].value.integer = current_value->Int32Value();
+ } else if (current_value->IsString()) {
+ channel_args.args[i].type = GRPC_ARG_STRING;
+ value_strings[i] = new NanUtf8String(current_value);
+ channel_args.args[i].value.string = **value_strings[i];
+ } else {
+ free(channel_args.args);
+ return NanThrowTypeError("Arg values must be strings");
+ }
+ }
+ if (creds == NULL) {
+ wrapped_server = grpc_server_create(queue, &channel_args);
+ } else {
+ wrapped_server = grpc_secure_server_create(creds, queue, &channel_args);
+ }
+ free(channel_args.args);
+ } else {
+ return NanThrowTypeError("Server expects an object");
+ }
+ Server *server = new Server(wrapped_server);
+ server->Wrap(args.This());
+ NanReturnValue(args.This());
+}
+
+NAN_METHOD(Server::RequestCall) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ 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(
+ server->wrapped_server, CreateTag(args[0], NanNull()));
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("requestCall failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Server::AddHttp2Port) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("addHttp2Port can only be called on a Server");
+ }
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("addHttp2Port's argument must be a String");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ NanReturnValue(NanNew<Number>(grpc_server_add_http2_port(
+ server->wrapped_server, *NanUtf8String(args[0]))));
+}
+
+NAN_METHOD(Server::AddSecureHttp2Port) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError(
+ "addSecureHttp2Port can only be called on a Server");
+ }
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("addSecureHttp2Port's argument must be a String");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ NanReturnValue(NanNew<Number>(grpc_server_add_secure_http2_port(
+ server->wrapped_server, *NanUtf8String(args[0]))));
+}
+
+NAN_METHOD(Server::Start) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("start can only be called on a Server");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ grpc_server_start(server->wrapped_server);
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Server::Shutdown) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("shutdown can only be called on a Server");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ grpc_server_shutdown(server->wrapped_server);
+ NanReturnUndefined();
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/server.h b/src/node/ext/server.h
new file mode 100644
index 0000000000..d50f1fb6c5
--- /dev/null
+++ b/src/node/ext/server.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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_SERVER_H_
+#define NET_GRPC_NODE_SERVER_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* Wraps grpc_server as a JavaScript object. Provides a constructor
+ and wrapper methods for grpc_server_create, grpc_server_request_call,
+ grpc_server_add_http2_port, and grpc_server_start. */
+class Server : public ::node::ObjectWrap {
+ public:
+ /* Initializes the Server class and exposes the constructor and
+ wrapper methods to JavaScript */
+ static void Init(v8::Handle<v8::Object> exports);
+ /* Tests whether the given value was constructed by this class's
+ JavaScript constructor */
+ static bool HasInstance(v8::Handle<v8::Value> val);
+
+ private:
+ explicit Server(grpc_server *server);
+ ~Server();
+
+ // Prevent copying
+ Server(const Server &);
+ Server &operator=(const Server &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(RequestCall);
+ static NAN_METHOD(AddHttp2Port);
+ static NAN_METHOD(AddSecureHttp2Port);
+ static NAN_METHOD(Start);
+ static NAN_METHOD(Shutdown);
+ static v8::Persistent<v8::Function> constructor;
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_server *wrapped_server;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_SERVER_H_
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
new file mode 100644
index 0000000000..393f3a6305
--- /dev/null
+++ b/src/node/ext/server_credentials.cc
@@ -0,0 +1,155 @@
+/*
+ *
+ * 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 <node.h>
+
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpc/support/log.h"
+#include "server_credentials.h"
+
+namespace grpc {
+namespace node {
+
+using ::node::Buffer;
+using v8::Arguments;
+using v8::Exception;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::Value;
+
+Persistent<Function> ServerCredentials::constructor;
+Persistent<FunctionTemplate> ServerCredentials::fun_tpl;
+
+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);
+}
+
+void ServerCredentials::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(NanNew("ServerCredentials"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ constructor->Set(NanNew("createSsl"),
+ FunctionTemplate::New(CreateSsl)->GetFunction());
+ constructor->Set(NanNew("createFake"),
+ FunctionTemplate::New(CreateFake)->GetFunction());
+ exports->Set(NanNew("ServerCredentials"), constructor);
+}
+
+bool ServerCredentials::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+Handle<Value> ServerCredentials::WrapStruct(
+ grpc_server_credentials *credentials) {
+ NanEscapableScope();
+ if (credentials == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ const int argc = 1;
+ Handle<Value> argv[argc] = {
+ External::New(reinterpret_cast<void *>(credentials))};
+ return NanEscapeScope(constructor->NewInstance(argc, argv));
+}
+
+grpc_server_credentials *ServerCredentials::GetWrappedServerCredentials() {
+ return wrapped_credentials;
+}
+
+NAN_METHOD(ServerCredentials::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ if (!args[0]->IsExternal()) {
+ return NanThrowTypeError(
+ "ServerCredentials can only be created with the provide functions");
+ }
+ grpc_server_credentials *creds_value =
+ reinterpret_cast<grpc_server_credentials *>(External::Unwrap(args[0]));
+ ServerCredentials *credentials = new ServerCredentials(creds_value);
+ credentials->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 1;
+ Local<Value> argv[argc] = {args[0]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(ServerCredentials::CreateSsl) {
+ // TODO: have the node API support multiple key/cert pairs.
+ NanScope();
+ char *root_certs = NULL;
+ grpc_ssl_pem_key_cert_pair key_cert_pair;
+ if (Buffer::HasInstance(args[0])) {
+ root_certs = Buffer::Data(args[0]);
+ } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) {
+ return NanThrowTypeError(
+ "createSSl's first argument must be a Buffer if provided");
+ }
+ if (!Buffer::HasInstance(args[1])) {
+ return NanThrowTypeError("createSsl's second argument must be a Buffer");
+ }
+ key_cert_pair.private_key = Buffer::Data(args[1]);
+ if (!Buffer::HasInstance(args[2])) {
+ return NanThrowTypeError("createSsl's third argument must be a Buffer");
+ }
+ key_cert_pair.cert_chain = Buffer::Data(args[2]);
+ NanReturnValue(WrapStruct(
+ grpc_ssl_server_credentials_create(root_certs, &key_cert_pair, 1)));
+}
+
+NAN_METHOD(ServerCredentials::CreateFake) {
+ NanScope();
+ NanReturnValue(
+ WrapStruct(grpc_fake_transport_security_server_credentials_create()));
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/server_credentials.h b/src/node/ext/server_credentials.h
new file mode 100644
index 0000000000..8baae3f185
--- /dev/null
+++ b/src/node/ext/server_credentials.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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_SERVER_CREDENTIALS_H_
+#define NET_GRPC_NODE_SERVER_CREDENTIALS_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_server_credentials structs */
+class ServerCredentials : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* Wrap a grpc_server_credentials struct in a javascript object */
+ static v8::Handle<v8::Value> WrapStruct(grpc_server_credentials *credentials);
+
+ /* Returns the grpc_server_credentials struct that this object wraps */
+ grpc_server_credentials *GetWrappedServerCredentials();
+
+ private:
+ explicit ServerCredentials(grpc_server_credentials *credentials);
+ ~ServerCredentials();
+
+ // Prevent copying
+ ServerCredentials(const ServerCredentials &);
+ ServerCredentials &operator=(const ServerCredentials &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(CreateSsl);
+ static NAN_METHOD(CreateFake);
+ static v8::Persistent<v8::Function> constructor;
+ // Used for typechecking instances of this javascript class
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_server_credentials *wrapped_credentials;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_SERVER_CREDENTIALS_H_
diff --git a/src/node/ext/tag.cc b/src/node/ext/tag.cc
new file mode 100644
index 0000000000..dc8e523e12
--- /dev/null
+++ b/src/node/ext/tag.cc
@@ -0,0 +1,101 @@
+/*
+ *
+ * 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
new file mode 100644
index 0000000000..bdb09252d9
--- /dev/null
+++ b/src/node/ext/tag.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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/ext/timeval.cc b/src/node/ext/timeval.cc
new file mode 100644
index 0000000000..687e33576b
--- /dev/null
+++ b/src/node/ext/timeval.cc
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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 <limits>
+
+#include "grpc/grpc.h"
+#include "grpc/support/time.h"
+#include "timeval.h"
+
+namespace grpc {
+namespace node {
+
+gpr_timespec MillisecondsToTimespec(double millis) {
+ if (millis == std::numeric_limits<double>::infinity()) {
+ return gpr_inf_future;
+ } else if (millis == -std::numeric_limits<double>::infinity()) {
+ return gpr_inf_past;
+ } else {
+ return gpr_time_from_micros(static_cast<int64_t>(millis * 1000));
+ }
+}
+
+double TimespecToMilliseconds(gpr_timespec timespec) {
+ if (gpr_time_cmp(timespec, gpr_inf_future) == 0) {
+ return std::numeric_limits<double>::infinity();
+ } else if (gpr_time_cmp(timespec, gpr_inf_past) == 0) {
+ return -std::numeric_limits<double>::infinity();
+ } else {
+ struct timeval time = gpr_timeval_from_timespec(timespec);
+ return (static_cast<double>(time.tv_sec) * 1000 +
+ static_cast<double>(time.tv_usec) / 1000);
+ }
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/timeval.h b/src/node/ext/timeval.h
new file mode 100644
index 0000000000..1fb0f2c690
--- /dev/null
+++ b/src/node/ext/timeval.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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_TIMEVAL_H_
+#define NET_GRPC_NODE_TIMEVAL_H_
+
+#include "grpc/support/time.h"
+
+namespace grpc {
+namespace node {
+
+double TimespecToMilliseconds(gpr_timespec time);
+gpr_timespec MillisecondsToTimespec(double millis);
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_TIMEVAL_H_