diff options
Diffstat (limited to 'src/node/ext/channel.cc')
-rw-r--r-- | src/node/ext/channel.cc | 260 |
1 files changed, 149 insertions, 111 deletions
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index 9aed96bbf5..584a0cf8ab 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -42,29 +42,101 @@ #include "call.h" #include "channel.h" #include "completion_queue_async_worker.h" -#include "credentials.h" +#include "channel_credentials.h" #include "timeval.h" namespace grpc { namespace node { +using Nan::Callback; +using Nan::EscapableHandleScope; +using Nan::HandleScope; +using Nan::Maybe; +using Nan::MaybeLocal; +using Nan::ObjectWrap; +using Nan::Persistent; +using Nan::Utf8String; + 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::Number; using v8::Object; -using v8::Persistent; using v8::String; using v8::Value; -NanCallback *Channel::constructor; +Callback *Channel::constructor; Persistent<FunctionTemplate> Channel::fun_tpl; +bool ParseChannelArgs(Local<Value> args_val, + grpc_channel_args **channel_args_ptr) { + if (args_val->IsUndefined() || args_val->IsNull()) { + *channel_args_ptr = NULL; + return true; + } + if (!args_val->IsObject()) { + *channel_args_ptr = NULL; + return false; + } + grpc_channel_args *channel_args = reinterpret_cast<grpc_channel_args*>( + malloc(sizeof(channel_args))); + *channel_args_ptr = channel_args; + Local<Object> args_hash = Nan::To<Object>(args_val).ToLocalChecked(); + Local<Array> keys = Nan::GetOwnPropertyNames(args_hash).ToLocalChecked(); + channel_args->num_args = keys->Length(); + channel_args->args = reinterpret_cast<grpc_arg *>( + calloc(channel_args->num_args, sizeof(grpc_arg))); + for (unsigned int i = 0; i < channel_args->num_args; i++) { + Local<Value> key = Nan::Get(keys, i).ToLocalChecked(); + Utf8String key_str(key); + if (*key_str == NULL) { + // Key string onversion failed + return false; + } + Local<Value> value = Nan::Get(args_hash, key).ToLocalChecked(); + if (value->IsInt32()) { + channel_args->args[i].type = GRPC_ARG_INTEGER; + channel_args->args[i].value.integer = Nan::To<int32_t>(value).FromJust(); + } else if (value->IsString()) { + Utf8String val_str(value); + channel_args->args[i].type = GRPC_ARG_STRING; + channel_args->args[i].value.string = reinterpret_cast<char*>( + calloc(val_str.length() + 1,sizeof(char))); + memcpy(channel_args->args[i].value.string, + *val_str, val_str.length() + 1); + } else { + // The value does not match either of the accepted types + return false; + } + channel_args->args[i].key = reinterpret_cast<char*>( + calloc(key_str.length() + 1, sizeof(char))); + memcpy(channel_args->args[i].key, *key_str, key_str.length() + 1); + } + return true; +} + +void DeallocateChannelArgs(grpc_channel_args *channel_args) { + if (channel_args == NULL) { + return; + } + for (size_t i = 0; i < channel_args->num_args; i++) { + if (channel_args->args[i].key == NULL) { + /* NULL key implies that this argument and all subsequent arguments failed + * to parse */ + break; + } + free(channel_args->args[i].key); + if (channel_args->args[i].type == GRPC_ARG_STRING) { + free(channel_args->args[i].value.string); + } + } + free(channel_args->args); + free(channel_args); +} + Channel::Channel(grpc_channel *channel) : wrapped_channel(channel) {} Channel::~Channel() { @@ -73,88 +145,51 @@ Channel::~Channel() { } } -void Channel::Init(Handle<Object> exports) { - NanScope(); - Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New); - tpl->SetClassName(NanNew("Channel")); +void Channel::Init(Local<Object> exports) { + Nan::HandleScope scope; + Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New); + tpl->SetClassName(Nan::New("Channel").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); - NanSetPrototypeTemplate(tpl, "close", - NanNew<FunctionTemplate>(Close)->GetFunction()); - NanSetPrototypeTemplate(tpl, "getTarget", - NanNew<FunctionTemplate>(GetTarget)->GetFunction()); - NanSetPrototypeTemplate( - tpl, "getConnectivityState", - NanNew<FunctionTemplate>(GetConnectivityState)->GetFunction()); - NanSetPrototypeTemplate( - tpl, "watchConnectivityState", - NanNew<FunctionTemplate>(WatchConnectivityState)->GetFunction()); - NanAssignPersistent(fun_tpl, tpl); - Handle<Function> ctr = tpl->GetFunction(); - constructor = new NanCallback(ctr); - exports->Set(NanNew("Channel"), ctr); + Nan::SetPrototypeMethod(tpl, "close", Close); + Nan::SetPrototypeMethod(tpl, "getTarget", GetTarget); + Nan::SetPrototypeMethod(tpl, "getConnectivityState", GetConnectivityState); + Nan::SetPrototypeMethod(tpl, "watchConnectivityState", + WatchConnectivityState); + fun_tpl.Reset(tpl); + Local<Function> ctr = Nan::GetFunction(tpl).ToLocalChecked(); + Nan::Set(exports, Nan::New("Channel").ToLocalChecked(), ctr); + constructor = new Callback(ctr); } -bool Channel::HasInstance(Handle<Value> val) { - NanScope(); - return NanHasInstance(fun_tpl, val); +bool Channel::HasInstance(Local<Value> val) { + HandleScope scope; + return Nan::New(fun_tpl)->HasInstance(val); } grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; } NAN_METHOD(Channel::New) { - NanScope(); - - if (args.IsConstructCall()) { - if (!args[0]->IsString()) { - return NanThrowTypeError( + if (info.IsConstructCall()) { + if (!info[0]->IsString()) { + return Nan::ThrowTypeError( "Channel expects a string, a credential and an object"); } grpc_channel *wrapped_channel; // Owned by the Channel object - NanUtf8String host(args[0]); + Utf8String host(info[0]); grpc_credentials *creds; - if (!Credentials::HasInstance(args[1])) { - return NanThrowTypeError( - "Channel's second argument must be a credential"); + if (!ChannelCredentials::HasInstance(info[1])) { + return Nan::ThrowTypeError( + "Channel's second argument must be a ChannelCredentials"); } - Credentials *creds_object = ObjectWrap::Unwrap<Credentials>( - args[1]->ToObject()); + ChannelCredentials *creds_object = ObjectWrap::Unwrap<ChannelCredentials>( + Nan::To<Object>(info[1]).ToLocalChecked()); creds = creds_object->GetWrappedCredentials(); - grpc_channel_args *channel_args_ptr; - if (args[2]->IsUndefined()) { - channel_args_ptr = NULL; - wrapped_channel = grpc_insecure_channel_create(*host, NULL, NULL); - } else if (args[2]->IsObject()) { - Handle<Object> args_hash(args[2]->ToObject()->Clone()); - 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"); - } - } - channel_args_ptr = &channel_args; - } else { - return NanThrowTypeError("Channel expects a string and an object"); + grpc_channel_args *channel_args_ptr = NULL; + if (!ParseChannelArgs(info[2], &channel_args_ptr)) { + DeallocateChannelArgs(channel_args_ptr); + return Nan::ThrowTypeError("Channel options must be an object with " + "string keys and integer or string values"); } if (creds == NULL) { wrapped_channel = grpc_insecure_channel_create(*host, channel_args_ptr, @@ -163,77 +198,81 @@ NAN_METHOD(Channel::New) { wrapped_channel = grpc_secure_channel_create(creds, *host, channel_args_ptr, NULL); } - if (channel_args_ptr != NULL) { - free(channel_args_ptr->args); - } + DeallocateChannelArgs(channel_args_ptr); Channel *channel = new Channel(wrapped_channel); - channel->Wrap(args.This()); - NanReturnValue(args.This()); + channel->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + return; } else { const int argc = 3; - Local<Value> argv[argc] = {args[0], args[1], args[2]}; - NanReturnValue(constructor->GetFunction()->NewInstance(argc, argv)); + Local<Value> argv[argc] = {info[0], info[1], info[2]}; + MaybeLocal<Object> maybe_instance = constructor->GetFunction()->NewInstance( + argc, argv); + if (maybe_instance.IsEmpty()) { + // There's probably a pending exception + return; + } else { + info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); + } } } NAN_METHOD(Channel::Close) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("close can only be called on Channel objects"); + if (!HasInstance(info.This())) { + return Nan::ThrowTypeError("close can only be called on Channel objects"); } - Channel *channel = ObjectWrap::Unwrap<Channel>(args.This()); + Channel *channel = ObjectWrap::Unwrap<Channel>(info.This()); if (channel->wrapped_channel != NULL) { grpc_channel_destroy(channel->wrapped_channel); channel->wrapped_channel = NULL; } - NanReturnUndefined(); } NAN_METHOD(Channel::GetTarget) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("getTarget can only be called on Channel objects"); + if (!HasInstance(info.This())) { + return Nan::ThrowTypeError("getTarget can only be called on Channel objects"); } - Channel *channel = ObjectWrap::Unwrap<Channel>(args.This()); - NanReturnValue(NanNew(grpc_channel_get_target(channel->wrapped_channel))); + Channel *channel = ObjectWrap::Unwrap<Channel>(info.This()); + info.GetReturnValue().Set(Nan::New( + grpc_channel_get_target(channel->wrapped_channel)).ToLocalChecked()); } NAN_METHOD(Channel::GetConnectivityState) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError( + if (!HasInstance(info.This())) { + return Nan::ThrowTypeError( "getConnectivityState can only be called on Channel objects"); } - Channel *channel = ObjectWrap::Unwrap<Channel>(args.This()); - int try_to_connect = (int)args[0]->Equals(NanTrue()); - NanReturnValue(grpc_channel_check_connectivity_state(channel->wrapped_channel, - try_to_connect)); + Channel *channel = ObjectWrap::Unwrap<Channel>(info.This()); + int try_to_connect = (int)info[0]->Equals(Nan::True()); + info.GetReturnValue().Set( + grpc_channel_check_connectivity_state(channel->wrapped_channel, + try_to_connect)); } NAN_METHOD(Channel::WatchConnectivityState) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError( + if (!HasInstance(info.This())) { + return Nan::ThrowTypeError( "watchConnectivityState can only be called on Channel objects"); } - if (!args[0]->IsUint32()) { - return NanThrowTypeError( + if (!info[0]->IsUint32()) { + return Nan::ThrowTypeError( "watchConnectivityState's first argument must be a channel state"); } - if (!(args[1]->IsNumber() || args[1]->IsDate())) { - return NanThrowTypeError( + if (!(info[1]->IsNumber() || info[1]->IsDate())) { + return Nan::ThrowTypeError( "watchConnectivityState's second argument must be a date or a number"); } - if (!args[2]->IsFunction()) { - return NanThrowTypeError( + if (!info[2]->IsFunction()) { + return Nan::ThrowTypeError( "watchConnectivityState's third argument must be a callback"); } grpc_connectivity_state last_state = - static_cast<grpc_connectivity_state>(args[0]->Uint32Value()); - double deadline = args[1]->NumberValue(); - Handle<Function> callback_func = args[2].As<Function>(); - NanCallback *callback = new NanCallback(callback_func); - Channel *channel = ObjectWrap::Unwrap<Channel>(args.This()); + static_cast<grpc_connectivity_state>( + Nan::To<uint32_t>(info[0]).FromJust()); + double deadline = Nan::To<double>(info[1]).FromJust(); + Local<Function> callback_func = info[2].As<Function>(); + Nan::Callback *callback = new Callback(callback_func); + Channel *channel = ObjectWrap::Unwrap<Channel>(info.This()); unique_ptr<OpVec> ops(new OpVec()); grpc_channel_watch_connectivity_state( channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline), @@ -242,7 +281,6 @@ NAN_METHOD(Channel::WatchConnectivityState) { ops.release(), shared_ptr<Resources>(nullptr))); CompletionQueueAsyncWorker::Next(); - NanReturnUndefined(); } } // namespace node |