channel.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. *
  3. * Copyright 2015 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <vector>
  19. #include "grpc/support/log.h"
  20. #include <nan.h>
  21. #include <node.h>
  22. #include "call.h"
  23. #include "channel.h"
  24. #include "channel_credentials.h"
  25. #include "completion_queue.h"
  26. #include "grpc/grpc.h"
  27. #include "grpc/grpc_security.h"
  28. #include "timeval.h"
  29. namespace grpc {
  30. namespace node {
  31. using Nan::Callback;
  32. using Nan::EscapableHandleScope;
  33. using Nan::HandleScope;
  34. using Nan::Maybe;
  35. using Nan::MaybeLocal;
  36. using Nan::ObjectWrap;
  37. using Nan::Persistent;
  38. using Nan::Utf8String;
  39. using v8::Array;
  40. using v8::Exception;
  41. using v8::Function;
  42. using v8::FunctionTemplate;
  43. using v8::Integer;
  44. using v8::Local;
  45. using v8::Number;
  46. using v8::Object;
  47. using v8::String;
  48. using v8::Value;
  49. Callback *Channel::constructor;
  50. Persistent<FunctionTemplate> Channel::fun_tpl;
  51. bool ParseChannelArgs(Local<Value> args_val,
  52. grpc_channel_args **channel_args_ptr) {
  53. if (args_val->IsUndefined() || args_val->IsNull()) {
  54. *channel_args_ptr = NULL;
  55. return true;
  56. }
  57. if (!args_val->IsObject()) {
  58. *channel_args_ptr = NULL;
  59. return false;
  60. }
  61. grpc_channel_args *channel_args =
  62. reinterpret_cast<grpc_channel_args *>(malloc(sizeof(grpc_channel_args)));
  63. *channel_args_ptr = channel_args;
  64. Local<Object> args_hash = Nan::To<Object>(args_val).ToLocalChecked();
  65. Local<Array> keys = Nan::GetOwnPropertyNames(args_hash).ToLocalChecked();
  66. channel_args->num_args = keys->Length();
  67. channel_args->args = reinterpret_cast<grpc_arg *>(
  68. calloc(channel_args->num_args, sizeof(grpc_arg)));
  69. for (unsigned int i = 0; i < channel_args->num_args; i++) {
  70. Local<Value> key = Nan::Get(keys, i).ToLocalChecked();
  71. Utf8String key_str(key);
  72. if (*key_str == NULL) {
  73. // Key string onversion failed
  74. return false;
  75. }
  76. Local<Value> value = Nan::Get(args_hash, key).ToLocalChecked();
  77. if (value->IsInt32()) {
  78. channel_args->args[i].type = GRPC_ARG_INTEGER;
  79. channel_args->args[i].value.integer = Nan::To<int32_t>(value).FromJust();
  80. } else if (value->IsString()) {
  81. Utf8String val_str(value);
  82. channel_args->args[i].type = GRPC_ARG_STRING;
  83. channel_args->args[i].value.string =
  84. reinterpret_cast<char *>(calloc(val_str.length() + 1, sizeof(char)));
  85. memcpy(channel_args->args[i].value.string, *val_str,
  86. val_str.length() + 1);
  87. } else {
  88. // The value does not match either of the accepted types
  89. return false;
  90. }
  91. channel_args->args[i].key =
  92. reinterpret_cast<char *>(calloc(key_str.length() + 1, sizeof(char)));
  93. memcpy(channel_args->args[i].key, *key_str, key_str.length() + 1);
  94. }
  95. return true;
  96. }
  97. void DeallocateChannelArgs(grpc_channel_args *channel_args) {
  98. if (channel_args == NULL) {
  99. return;
  100. }
  101. for (size_t i = 0; i < channel_args->num_args; i++) {
  102. if (channel_args->args[i].key == NULL) {
  103. /* NULL key implies that this argument and all subsequent arguments failed
  104. * to parse */
  105. break;
  106. }
  107. free(channel_args->args[i].key);
  108. if (channel_args->args[i].type == GRPC_ARG_STRING) {
  109. free(channel_args->args[i].value.string);
  110. }
  111. }
  112. free(channel_args->args);
  113. free(channel_args);
  114. }
  115. Channel::Channel(grpc_channel *channel) : wrapped_channel(channel) {}
  116. Channel::~Channel() {
  117. gpr_log(GPR_DEBUG, "Destroying channel");
  118. if (wrapped_channel != NULL) {
  119. grpc_channel_destroy(wrapped_channel);
  120. }
  121. }
  122. void Channel::Init(Local<Object> exports) {
  123. Nan::HandleScope scope;
  124. Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
  125. tpl->SetClassName(Nan::New("Channel").ToLocalChecked());
  126. tpl->InstanceTemplate()->SetInternalFieldCount(1);
  127. Nan::SetPrototypeMethod(tpl, "close", Close);
  128. Nan::SetPrototypeMethod(tpl, "getTarget", GetTarget);
  129. Nan::SetPrototypeMethod(tpl, "getConnectivityState", GetConnectivityState);
  130. Nan::SetPrototypeMethod(tpl, "watchConnectivityState",
  131. WatchConnectivityState);
  132. fun_tpl.Reset(tpl);
  133. Local<Function> ctr = Nan::GetFunction(tpl).ToLocalChecked();
  134. Nan::Set(exports, Nan::New("Channel").ToLocalChecked(), ctr);
  135. constructor = new Callback(ctr);
  136. }
  137. bool Channel::HasInstance(Local<Value> val) {
  138. HandleScope scope;
  139. return Nan::New(fun_tpl)->HasInstance(val);
  140. }
  141. grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; }
  142. NAN_METHOD(Channel::New) {
  143. if (info.IsConstructCall()) {
  144. if (!info[0]->IsString()) {
  145. return Nan::ThrowTypeError(
  146. "Channel expects a string, a credential and an object");
  147. }
  148. grpc_channel *wrapped_channel;
  149. // Owned by the Channel object
  150. Utf8String host(info[0]);
  151. grpc_channel_credentials *creds;
  152. if (!ChannelCredentials::HasInstance(info[1])) {
  153. return Nan::ThrowTypeError(
  154. "Channel's second argument must be a ChannelCredentials");
  155. }
  156. ChannelCredentials *creds_object = ObjectWrap::Unwrap<ChannelCredentials>(
  157. Nan::To<Object>(info[1]).ToLocalChecked());
  158. creds = creds_object->GetWrappedCredentials();
  159. grpc_channel_args *channel_args_ptr = NULL;
  160. if (!ParseChannelArgs(info[2], &channel_args_ptr)) {
  161. DeallocateChannelArgs(channel_args_ptr);
  162. return Nan::ThrowTypeError(
  163. "Channel options must be an object with "
  164. "string keys and integer or string values");
  165. }
  166. if (creds == NULL) {
  167. wrapped_channel =
  168. grpc_insecure_channel_create(*host, channel_args_ptr, NULL);
  169. } else {
  170. wrapped_channel =
  171. grpc_secure_channel_create(creds, *host, channel_args_ptr, NULL);
  172. }
  173. DeallocateChannelArgs(channel_args_ptr);
  174. Channel *channel = new Channel(wrapped_channel);
  175. channel->Wrap(info.This());
  176. info.GetReturnValue().Set(info.This());
  177. return;
  178. } else {
  179. const int argc = 3;
  180. Local<Value> argv[argc] = {info[0], info[1], info[2]};
  181. MaybeLocal<Object> maybe_instance =
  182. Nan::NewInstance(constructor->GetFunction(), argc, argv);
  183. if (maybe_instance.IsEmpty()) {
  184. // There's probably a pending exception
  185. return;
  186. } else {
  187. info.GetReturnValue().Set(maybe_instance.ToLocalChecked());
  188. }
  189. }
  190. }
  191. NAN_METHOD(Channel::Close) {
  192. if (!HasInstance(info.This())) {
  193. return Nan::ThrowTypeError("close can only be called on Channel objects");
  194. }
  195. Channel *channel = ObjectWrap::Unwrap<Channel>(info.This());
  196. if (channel->wrapped_channel != NULL) {
  197. grpc_channel_destroy(channel->wrapped_channel);
  198. channel->wrapped_channel = NULL;
  199. }
  200. }
  201. NAN_METHOD(Channel::GetTarget) {
  202. if (!HasInstance(info.This())) {
  203. return Nan::ThrowTypeError(
  204. "getTarget can only be called on Channel objects");
  205. }
  206. Channel *channel = ObjectWrap::Unwrap<Channel>(info.This());
  207. info.GetReturnValue().Set(
  208. Nan::New(grpc_channel_get_target(channel->wrapped_channel))
  209. .ToLocalChecked());
  210. }
  211. NAN_METHOD(Channel::GetConnectivityState) {
  212. if (!HasInstance(info.This())) {
  213. return Nan::ThrowTypeError(
  214. "getConnectivityState can only be called on Channel objects");
  215. }
  216. Channel *channel = ObjectWrap::Unwrap<Channel>(info.This());
  217. int try_to_connect = (int)info[0]->Equals(Nan::True());
  218. info.GetReturnValue().Set(grpc_channel_check_connectivity_state(
  219. channel->wrapped_channel, try_to_connect));
  220. }
  221. NAN_METHOD(Channel::WatchConnectivityState) {
  222. if (!HasInstance(info.This())) {
  223. return Nan::ThrowTypeError(
  224. "watchConnectivityState can only be called on Channel objects");
  225. }
  226. if (!info[0]->IsUint32()) {
  227. return Nan::ThrowTypeError(
  228. "watchConnectivityState's first argument must be a channel state");
  229. }
  230. if (!(info[1]->IsNumber() || info[1]->IsDate())) {
  231. return Nan::ThrowTypeError(
  232. "watchConnectivityState's second argument must be a date or a number");
  233. }
  234. if (!info[2]->IsFunction()) {
  235. return Nan::ThrowTypeError(
  236. "watchConnectivityState's third argument must be a callback");
  237. }
  238. grpc_connectivity_state last_state = static_cast<grpc_connectivity_state>(
  239. Nan::To<uint32_t>(info[0]).FromJust());
  240. double deadline = Nan::To<double>(info[1]).FromJust();
  241. Local<Function> callback_func = info[2].As<Function>();
  242. Nan::Callback *callback = new Callback(callback_func);
  243. Channel *channel = ObjectWrap::Unwrap<Channel>(info.This());
  244. unique_ptr<OpVec> ops(new OpVec());
  245. grpc_channel_watch_connectivity_state(
  246. channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline),
  247. GetCompletionQueue(),
  248. new struct tag(callback, ops.release(), NULL, Nan::Null()));
  249. CompletionQueueNext();
  250. }
  251. } // namespace node
  252. } // namespace grpc