blob: 15c9b2d97d6df4e6f37297a0e9d9e08005ac8c8b [file] [log] [blame]
murgatroid99749666e2015-01-12 18:25:58 -08001/*
2 *
murgatroid99ff43c092015-02-09 11:41:23 -08003 * Copyright 2015, Google Inc.
murgatroid99749666e2015-01-12 18:25:58 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
murgatroid99d4d67ad2015-02-09 10:43:21 -080034#include <memory>
murgatroid99a9b99c92015-02-05 17:42:01 -080035#include <vector>
murgatroid99ff43c092015-02-09 11:41:23 -080036#include <map>
murgatroid99a9b99c92015-02-05 17:42:01 -080037
murgatroid99e5061512015-01-12 18:14:35 -080038#include <node.h>
39
murgatroid997625db42015-01-28 15:36:27 -080040#include "grpc/support/log.h"
murgatroid99e5061512015-01-12 18:14:35 -080041#include "grpc/grpc.h"
murgatroid99d4d67ad2015-02-09 10:43:21 -080042#include "grpc/support/alloc.h"
murgatroid99e5061512015-01-12 18:14:35 -080043#include "grpc/support/time.h"
44#include "byte_buffer.h"
45#include "call.h"
46#include "channel.h"
47#include "completion_queue_async_worker.h"
48#include "timeval.h"
murgatroid99e5061512015-01-12 18:14:35 -080049
murgatroid99ff43c092015-02-09 11:41:23 -080050using std::unique_ptr;
murgatroid9917be5892015-02-13 10:19:10 -080051using std::shared_ptr;
murgatroid99e0123662015-02-13 11:14:03 -080052using std::vector;
murgatroid99ff43c092015-02-09 11:41:23 -080053
murgatroid99e5061512015-01-12 18:14:35 -080054namespace grpc {
55namespace node {
56
murgatroid99e5061512015-01-12 18:14:35 -080057using v8::Array;
murgatroid99016bb502015-02-09 15:55:10 -080058using v8::Boolean;
murgatroid99e5061512015-01-12 18:14:35 -080059using v8::Exception;
60using v8::External;
61using v8::Function;
62using v8::FunctionTemplate;
63using v8::Handle;
64using v8::HandleScope;
65using v8::Integer;
66using v8::Local;
67using v8::Number;
68using v8::Object;
69using v8::ObjectTemplate;
70using v8::Persistent;
71using v8::Uint32;
72using v8::String;
73using v8::Value;
74
murgatroid995f875d22015-03-04 11:28:37 -080075NanCallback *Call::constructor;
murgatroid99e5061512015-01-12 18:14:35 -080076Persistent<FunctionTemplate> Call::fun_tpl;
77
murgatroid99da771512015-03-17 18:13:55 -070078bool EndsWith(const char *str, const char *substr) {
79 return strcmp(str+strlen(str)-strlen(substr), substr) == 0;
80}
murgatroid99d4d67ad2015-02-09 10:43:21 -080081
murgatroid9917be5892015-02-13 10:19:10 -080082bool CreateMetadataArray(Handle<Object> metadata, grpc_metadata_array *array,
83 shared_ptr<Resources> resources) {
murgatroid99a9b99c92015-02-05 17:42:01 -080084 NanScope();
murgatroid99016bb502015-02-09 15:55:10 -080085 grpc_metadata_array_init(array);
murgatroid99a9b99c92015-02-05 17:42:01 -080086 Handle<Array> keys(metadata->GetOwnPropertyNames());
87 for (unsigned int i = 0; i < keys->Length(); i++) {
88 Handle<String> current_key(keys->Get(i)->ToString());
89 if (!metadata->Get(current_key)->IsArray()) {
90 return false;
91 }
92 array->capacity += Local<Array>::Cast(metadata->Get(current_key))->Length();
93 }
murgatroid99d4d67ad2015-02-09 10:43:21 -080094 array->metadata = reinterpret_cast<grpc_metadata*>(
95 gpr_malloc(array->capacity * sizeof(grpc_metadata)));
murgatroid99a9b99c92015-02-05 17:42:01 -080096 for (unsigned int i = 0; i < keys->Length(); i++) {
97 Handle<String> current_key(keys->Get(i)->ToString());
98 NanUtf8String *utf8_key = new NanUtf8String(current_key);
murgatroid9917be5892015-02-13 10:19:10 -080099 resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_key));
murgatroid99a9b99c92015-02-05 17:42:01 -0800100 Handle<Array> values = Local<Array>::Cast(metadata->Get(current_key));
101 for (unsigned int j = 0; j < values->Length(); j++) {
102 Handle<Value> value = values->Get(j);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800103 grpc_metadata *current = &array->metadata[array->count];
murgatroid99a9b99c92015-02-05 17:42:01 -0800104 current->key = **utf8_key;
murgatroid99da771512015-03-17 18:13:55 -0700105 // Only allow binary headers for "-bin" keys
106 if (EndsWith(current->key, "-bin")) {
107 if (::node::Buffer::HasInstance(value)) {
108 current->value = ::node::Buffer::Data(value);
109 current->value_length = ::node::Buffer::Length(value);
110 Persistent<Value> *handle = new Persistent<Value>();
111 NanAssignPersistent(*handle, value);
112 resources->handles.push_back(unique_ptr<PersistentHolder>(
113 new PersistentHolder(handle)));
114 continue;
115 }
116 }
117 if (value->IsString()) {
murgatroid99a9b99c92015-02-05 17:42:01 -0800118 Handle<String> string_value = value->ToString();
119 NanUtf8String *utf8_value = new NanUtf8String(string_value);
murgatroid9917be5892015-02-13 10:19:10 -0800120 resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_value));
murgatroid99a9b99c92015-02-05 17:42:01 -0800121 current->value = **utf8_value;
122 current->value_length = string_value->Length();
123 } else {
124 return false;
125 }
126 array->count += 1;
127 }
128 }
129 return true;
130}
131
murgatroid99ff43c092015-02-09 11:41:23 -0800132Handle<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800133 NanEscapableScope();
134 grpc_metadata *metadata_elements = metadata_array->metadata;
135 size_t length = metadata_array->count;
murgatroid99ff43c092015-02-09 11:41:23 -0800136 std::map<const char*, size_t> size_map;
137 std::map<const char*, size_t> index_map;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800138
139 for (unsigned int i = 0; i < length; i++) {
murgatroid99ff43c092015-02-09 11:41:23 -0800140 const char *key = metadata_elements[i].key;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800141 if (size_map.count(key)) {
142 size_map[key] += 1;
143 }
144 index_map[key] = 0;
145 }
146 Handle<Object> metadata_object = NanNew<Object>();
147 for (unsigned int i = 0; i < length; i++) {
148 grpc_metadata* elem = &metadata_elements[i];
murgatroid995f875d22015-03-04 11:28:37 -0800149 Handle<String> key_string = NanNew(elem->key);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800150 Handle<Array> array;
151 if (metadata_object->Has(key_string)) {
152 array = Handle<Array>::Cast(metadata_object->Get(key_string));
153 } else {
154 array = NanNew<Array>(size_map[elem->key]);
155 metadata_object->Set(key_string, array);
156 }
murgatroid99da771512015-03-17 18:13:55 -0700157 if (EndsWith(elem->key, "-bin")) {
158 array->Set(index_map[elem->key],
159 MakeFastBuffer(
160 NanNewBufferHandle(elem->value, elem->value_length)));
161 } else {
162 array->Set(index_map[elem->key], NanNew(elem->value));
163 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800164 index_map[elem->key] += 1;
165 }
166 return NanEscapeScope(metadata_object);
167}
168
murgatroid99ff43c092015-02-09 11:41:23 -0800169Handle<Value> Op::GetOpType() const {
170 NanEscapableScope();
murgatroid99016bb502015-02-09 15:55:10 -0800171 return NanEscapeScope(NanNew<String>(GetTypeString()));
murgatroid99ff43c092015-02-09 11:41:23 -0800172}
murgatroid99d4d67ad2015-02-09 10:43:21 -0800173
174class SendMetadataOp : public Op {
175 public:
murgatroid99016bb502015-02-09 15:55:10 -0800176 Handle<Value> GetNodeValue() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800177 NanEscapableScope();
178 return NanEscapeScope(NanTrue());
179 }
180 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800181 shared_ptr<Resources> resources) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800182 if (!value->IsObject()) {
183 return false;
184 }
185 grpc_metadata_array array;
murgatroid9917be5892015-02-13 10:19:10 -0800186 if (!CreateMetadataArray(value->ToObject(), &array, resources)) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800187 return false;
188 }
189 out->data.send_initial_metadata.count = array.count;
190 out->data.send_initial_metadata.metadata = array.metadata;
191 return true;
192 }
193 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800194 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800195 return "send metadata";
196 }
197};
198
199class SendMessageOp : public Op {
200 public:
murgatroid99016bb502015-02-09 15:55:10 -0800201 Handle<Value> GetNodeValue() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800202 NanEscapableScope();
203 return NanEscapeScope(NanTrue());
204 }
205 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800206 shared_ptr<Resources> resources) {
murgatroid995f875d22015-03-04 11:28:37 -0800207 if (!::node::Buffer::HasInstance(value)) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800208 return false;
209 }
murgatroid99016bb502015-02-09 15:55:10 -0800210 out->data.send_message = BufferToByteBuffer(value);
murgatroid99f28066b2015-03-04 14:42:31 -0800211 Persistent<Value> *handle = new Persistent<Value>();
212 NanAssignPersistent(*handle, value);
murgatroid9917be5892015-02-13 10:19:10 -0800213 resources->handles.push_back(unique_ptr<PersistentHolder>(
murgatroid99ff43c092015-02-09 11:41:23 -0800214 new PersistentHolder(handle)));
murgatroid99016bb502015-02-09 15:55:10 -0800215 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800216 }
217 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800218 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800219 return "send message";
220 }
221};
222
223class SendClientCloseOp : public Op {
224 public:
murgatroid99016bb502015-02-09 15:55:10 -0800225 Handle<Value> GetNodeValue() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800226 NanEscapableScope();
227 return NanEscapeScope(NanTrue());
228 }
229 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800230 shared_ptr<Resources> resources) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800231 return true;
232 }
233 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800234 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800235 return "client close";
236 }
237};
238
239class SendServerStatusOp : public Op {
240 public:
murgatroid99016bb502015-02-09 15:55:10 -0800241 Handle<Value> GetNodeValue() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800242 NanEscapableScope();
243 return NanEscapeScope(NanTrue());
244 }
245 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800246 shared_ptr<Resources> resources) {
murgatroid99cd0b9062015-02-10 09:16:49 -0800247 if (!value->IsObject()) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800248 return false;
249 }
250 Handle<Object> server_status = value->ToObject();
251 if (!server_status->Get(NanNew("metadata"))->IsObject()) {
252 return false;
253 }
254 if (!server_status->Get(NanNew("code"))->IsUint32()) {
255 return false;
256 }
257 if (!server_status->Get(NanNew("details"))->IsString()) {
258 return false;
259 }
260 grpc_metadata_array array;
261 if (!CreateMetadataArray(server_status->Get(NanNew("metadata"))->
262 ToObject(),
murgatroid9917be5892015-02-13 10:19:10 -0800263 &array, resources)) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800264 return false;
265 }
266 out->data.send_status_from_server.trailing_metadata_count = array.count;
267 out->data.send_status_from_server.trailing_metadata = array.metadata;
268 out->data.send_status_from_server.status =
269 static_cast<grpc_status_code>(
270 server_status->Get(NanNew("code"))->Uint32Value());
271 NanUtf8String *str = new NanUtf8String(
272 server_status->Get(NanNew("details")));
murgatroid9917be5892015-02-13 10:19:10 -0800273 resources->strings.push_back(unique_ptr<NanUtf8String>(str));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800274 out->data.send_status_from_server.status_details = **str;
275 return true;
276 }
277 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800278 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800279 return "send status";
280 }
murgatroid99016bb502015-02-09 15:55:10 -0800281};
murgatroid99d4d67ad2015-02-09 10:43:21 -0800282
283class GetMetadataOp : public Op {
284 public:
285 GetMetadataOp() {
286 grpc_metadata_array_init(&recv_metadata);
287 }
288
289 ~GetMetadataOp() {
290 grpc_metadata_array_destroy(&recv_metadata);
291 }
292
293 Handle<Value> GetNodeValue() const {
294 NanEscapableScope();
295 return NanEscapeScope(ParseMetadata(&recv_metadata));
296 }
297
298 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800299 shared_ptr<Resources> resources) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800300 out->data.recv_initial_metadata = &recv_metadata;
murgatroid99016bb502015-02-09 15:55:10 -0800301 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800302 }
303
304 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800305 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800306 return "metadata";
307 }
308
309 private:
310 grpc_metadata_array recv_metadata;
311};
312
313class ReadMessageOp : public Op {
314 public:
315 ReadMessageOp() {
316 recv_message = NULL;
317 }
318 ~ReadMessageOp() {
319 if (recv_message != NULL) {
320 gpr_free(recv_message);
321 }
322 }
323 Handle<Value> GetNodeValue() const {
324 NanEscapableScope();
murgatroid99ff43c092015-02-09 11:41:23 -0800325 return NanEscapeScope(ByteBufferToBuffer(recv_message));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800326 }
327
328 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800329 shared_ptr<Resources> resources) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800330 out->data.recv_message = &recv_message;
murgatroid99ff43c092015-02-09 11:41:23 -0800331 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800332 }
333
334 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800335 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800336 return "read";
337 }
338
339 private:
340 grpc_byte_buffer *recv_message;
341};
342
343class ClientStatusOp : public Op {
344 public:
345 ClientStatusOp() {
murgatroid99016bb502015-02-09 15:55:10 -0800346 grpc_metadata_array_init(&metadata_array);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800347 status_details = NULL;
murgatroid99016bb502015-02-09 15:55:10 -0800348 details_capacity = 0;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800349 }
350
351 ~ClientStatusOp() {
murgatroid99016bb502015-02-09 15:55:10 -0800352 grpc_metadata_array_destroy(&metadata_array);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800353 gpr_free(status_details);
354 }
355
356 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800357 shared_ptr<Resources> resources) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800358 out->data.recv_status_on_client.trailing_metadata = &metadata_array;
359 out->data.recv_status_on_client.status = &status;
360 out->data.recv_status_on_client.status_details = &status_details;
361 out->data.recv_status_on_client.status_details_capacity = &details_capacity;
murgatroid99ff43c092015-02-09 11:41:23 -0800362 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800363 }
364
365 Handle<Value> GetNodeValue() const {
366 NanEscapableScope();
367 Handle<Object> status_obj = NanNew<Object>();
368 status_obj->Set(NanNew("code"), NanNew<Number>(status));
murgatroid99016bb502015-02-09 15:55:10 -0800369 if (status_details != NULL) {
murgatroid995f875d22015-03-04 11:28:37 -0800370 status_obj->Set(NanNew("details"), NanNew(status_details));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800371 }
372 status_obj->Set(NanNew("metadata"), ParseMetadata(&metadata_array));
373 return NanEscapeScope(status_obj);
374 }
murgatroid99ff43c092015-02-09 11:41:23 -0800375 protected:
376 std::string GetTypeString() const {
377 return "status";
378 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800379 private:
380 grpc_metadata_array metadata_array;
381 grpc_status_code status;
382 char *status_details;
383 size_t details_capacity;
384};
385
386class ServerCloseResponseOp : public Op {
387 public:
388 Handle<Value> GetNodeValue() const {
389 NanEscapableScope();
murgatroid99016bb502015-02-09 15:55:10 -0800390 return NanEscapeScope(NanNew<Boolean>(cancelled));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800391 }
392
393 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800394 shared_ptr<Resources> resources) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800395 out->data.recv_close_on_server.cancelled = &cancelled;
murgatroid99ff43c092015-02-09 11:41:23 -0800396 return true;
397 }
398
399 protected:
400 std::string GetTypeString() const {
401 return "cancelled";
murgatroid99d4d67ad2015-02-09 10:43:21 -0800402 }
403
404 private:
405 int cancelled;
406};
407
murgatroid99e0123662015-02-13 11:14:03 -0800408tag::tag(NanCallback *callback, OpVec *ops,
murgatroid9917be5892015-02-13 10:19:10 -0800409 shared_ptr<Resources> resources) :
410 callback(callback), ops(ops), resources(resources){
murgatroid99016bb502015-02-09 15:55:10 -0800411}
murgatroid9917be5892015-02-13 10:19:10 -0800412
murgatroid99016bb502015-02-09 15:55:10 -0800413tag::~tag() {
414 delete callback;
415 delete ops;
murgatroid99016bb502015-02-09 15:55:10 -0800416}
417
418Handle<Value> GetTagNodeValue(void *tag) {
419 NanEscapableScope();
420 struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
421 Handle<Object> tag_obj = NanNew<Object>();
murgatroid99e0123662015-02-13 11:14:03 -0800422 for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
murgatroid99016bb502015-02-09 15:55:10 -0800423 it != tag_struct->ops->end(); ++it) {
424 Op *op_ptr = it->get();
425 tag_obj->Set(op_ptr->GetOpType(), op_ptr->GetNodeValue());
426 }
427 return NanEscapeScope(tag_obj);
428}
429
murgatroid991578c6a2015-02-11 16:19:55 -0800430NanCallback *GetTagCallback(void *tag) {
murgatroid99016bb502015-02-09 15:55:10 -0800431 struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
murgatroid991578c6a2015-02-11 16:19:55 -0800432 return tag_struct->callback;
murgatroid99016bb502015-02-09 15:55:10 -0800433}
434
435void DestroyTag(void *tag) {
436 struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
437 delete tag_struct;
438}
murgatroid99d4d67ad2015-02-09 10:43:21 -0800439
murgatroid9977659062015-02-11 09:26:25 -0800440Call::Call(grpc_call *call) : wrapped_call(call) {
murgatroid9977659062015-02-11 09:26:25 -0800441}
murgatroid99e5061512015-01-12 18:14:35 -0800442
murgatroid9977659062015-02-11 09:26:25 -0800443Call::~Call() {
murgatroid9977659062015-02-11 09:26:25 -0800444 grpc_call_destroy(wrapped_call);
445}
murgatroid99e5061512015-01-12 18:14:35 -0800446
447void Call::Init(Handle<Object> exports) {
448 NanScope();
murgatroid995f875d22015-03-04 11:28:37 -0800449 Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New);
murgatroid99e5061512015-01-12 18:14:35 -0800450 tpl->SetClassName(NanNew("Call"));
451 tpl->InstanceTemplate()->SetInternalFieldCount(1);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800452 NanSetPrototypeTemplate(tpl, "startBatch",
murgatroid995f875d22015-03-04 11:28:37 -0800453 NanNew<FunctionTemplate>(StartBatch)->GetFunction());
murgatroid99e5061512015-01-12 18:14:35 -0800454 NanSetPrototypeTemplate(tpl, "cancel",
murgatroid995f875d22015-03-04 11:28:37 -0800455 NanNew<FunctionTemplate>(Cancel)->GetFunction());
murgatroid99e5061512015-01-12 18:14:35 -0800456 NanAssignPersistent(fun_tpl, tpl);
murgatroid995f875d22015-03-04 11:28:37 -0800457 Handle<Function> ctr = tpl->GetFunction();
458 ctr->Set(NanNew("WRITE_BUFFER_HINT"),
459 NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
460 ctr->Set(NanNew("WRITE_NO_COMPRESS"),
461 NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
462 exports->Set(NanNew("Call"), ctr);
463 constructor = new NanCallback(ctr);
murgatroid99e5061512015-01-12 18:14:35 -0800464}
465
466bool Call::HasInstance(Handle<Value> val) {
467 NanScope();
468 return NanHasInstance(fun_tpl, val);
469}
470
471Handle<Value> Call::WrapStruct(grpc_call *call) {
472 NanEscapableScope();
473 if (call == NULL) {
474 return NanEscapeScope(NanNull());
475 }
476 const int argc = 1;
murgatroid995f875d22015-03-04 11:28:37 -0800477 Handle<Value> argv[argc] = {NanNew<External>(reinterpret_cast<void *>(call))};
478 return NanEscapeScope(constructor->GetFunction()->NewInstance(argc, argv));
murgatroid99e5061512015-01-12 18:14:35 -0800479}
480
481NAN_METHOD(Call::New) {
482 NanScope();
483
484 if (args.IsConstructCall()) {
485 Call *call;
486 if (args[0]->IsExternal()) {
murgatroid995f875d22015-03-04 11:28:37 -0800487 Handle<External> ext = args[0].As<External>();
murgatroid99e5061512015-01-12 18:14:35 -0800488 // This option is used for wrapping an existing call
Craig Tillere8e304e2015-01-13 14:41:29 -0800489 grpc_call *call_value =
murgatroid995f875d22015-03-04 11:28:37 -0800490 reinterpret_cast<grpc_call *>(ext->Value());
murgatroid99e5061512015-01-12 18:14:35 -0800491 call = new Call(call_value);
492 } else {
493 if (!Channel::HasInstance(args[0])) {
494 return NanThrowTypeError("Call's first argument must be a Channel");
495 }
496 if (!args[1]->IsString()) {
497 return NanThrowTypeError("Call's second argument must be a string");
498 }
499 if (!(args[2]->IsNumber() || args[2]->IsDate())) {
500 return NanThrowTypeError(
501 "Call's third argument must be a date or a number");
502 }
503 Handle<Object> channel_object = args[0]->ToObject();
504 Channel *channel = ObjectWrap::Unwrap<Channel>(channel_object);
505 if (channel->GetWrappedChannel() == NULL) {
506 return NanThrowError("Call cannot be created from a closed channel");
507 }
508 NanUtf8String method(args[1]);
509 double deadline = args[2]->NumberValue();
510 grpc_channel *wrapped_channel = channel->GetWrappedChannel();
murgatroid99a9b99c92015-02-05 17:42:01 -0800511 grpc_call *wrapped_call = grpc_channel_create_call(
512 wrapped_channel, CompletionQueueAsyncWorker::GetQueue(), *method,
513 channel->GetHost(), MillisecondsToTimespec(deadline));
murgatroid99e5061512015-01-12 18:14:35 -0800514 call = new Call(wrapped_call);
murgatroid995f875d22015-03-04 11:28:37 -0800515 args.This()->SetHiddenValue(NanNew("channel_"), channel_object);
murgatroid99e5061512015-01-12 18:14:35 -0800516 }
517 call->Wrap(args.This());
518 NanReturnValue(args.This());
519 } else {
520 const int argc = 4;
Craig Tillere8e304e2015-01-13 14:41:29 -0800521 Local<Value> argv[argc] = {args[0], args[1], args[2], args[3]};
murgatroid995f875d22015-03-04 11:28:37 -0800522 NanReturnValue(constructor->GetFunction()->NewInstance(argc, argv));
murgatroid99e5061512015-01-12 18:14:35 -0800523 }
524}
525
murgatroid99a9b99c92015-02-05 17:42:01 -0800526NAN_METHOD(Call::StartBatch) {
527 NanScope();
528 if (!HasInstance(args.This())) {
529 return NanThrowTypeError("startBatch can only be called on Call objects");
530 }
531 if (!args[0]->IsObject()) {
532 return NanThrowError("startBatch's first argument must be an object");
533 }
534 if (!args[1]->IsFunction()) {
535 return NanThrowError("startBatch's second argument must be a callback");
536 }
murgatroid9977659062015-02-11 09:26:25 -0800537 Handle<Function> callback_func = args[1].As<Function>();
murgatroid99d4d67ad2015-02-09 10:43:21 -0800538 Call *call = ObjectWrap::Unwrap<Call>(args.This());
murgatroid9917be5892015-02-13 10:19:10 -0800539 shared_ptr<Resources> resources(new Resources);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800540 Handle<Object> obj = args[0]->ToObject();
541 Handle<Array> keys = obj->GetOwnPropertyNames();
murgatroid99a9b99c92015-02-05 17:42:01 -0800542 size_t nops = keys->Length();
murgatroid99e0123662015-02-13 11:14:03 -0800543 vector<grpc_op> ops(nops);
544 unique_ptr<OpVec> op_vector(new OpVec());
murgatroid99a9b99c92015-02-05 17:42:01 -0800545 for (unsigned int i = 0; i < nops; i++) {
murgatroid9917be5892015-02-13 10:19:10 -0800546 unique_ptr<Op> op;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800547 if (!keys->Get(i)->IsUint32()) {
murgatroid99a9b99c92015-02-05 17:42:01 -0800548 return NanThrowError(
549 "startBatch's first argument's keys must be integers");
550 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800551 uint32_t type = keys->Get(i)->Uint32Value();
552 ops[i].op = static_cast<grpc_op_type>(type);
David Garcia Quintasba710e52015-06-15 13:31:15 -0700553 ops[i].flags = 0;
murgatroid99a9b99c92015-02-05 17:42:01 -0800554 switch (type) {
555 case GRPC_OP_SEND_INITIAL_METADATA:
murgatroid9917be5892015-02-13 10:19:10 -0800556 op.reset(new SendMetadataOp());
murgatroid99d4d67ad2015-02-09 10:43:21 -0800557 break;
murgatroid99a9b99c92015-02-05 17:42:01 -0800558 case GRPC_OP_SEND_MESSAGE:
murgatroid9917be5892015-02-13 10:19:10 -0800559 op.reset(new SendMessageOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800560 break;
561 case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
murgatroid9917be5892015-02-13 10:19:10 -0800562 op.reset(new SendClientCloseOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800563 break;
564 case GRPC_OP_SEND_STATUS_FROM_SERVER:
murgatroid9917be5892015-02-13 10:19:10 -0800565 op.reset(new SendServerStatusOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800566 break;
567 case GRPC_OP_RECV_INITIAL_METADATA:
murgatroid9917be5892015-02-13 10:19:10 -0800568 op.reset(new GetMetadataOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800569 break;
570 case GRPC_OP_RECV_MESSAGE:
murgatroid9917be5892015-02-13 10:19:10 -0800571 op.reset(new ReadMessageOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800572 break;
573 case GRPC_OP_RECV_STATUS_ON_CLIENT:
murgatroid9917be5892015-02-13 10:19:10 -0800574 op.reset(new ClientStatusOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800575 break;
576 case GRPC_OP_RECV_CLOSE_ON_SERVER:
murgatroid9917be5892015-02-13 10:19:10 -0800577 op.reset(new ServerCloseResponseOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800578 break;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800579 default:
580 return NanThrowError("Argument object had an unrecognized key");
murgatroid99a9b99c92015-02-05 17:42:01 -0800581 }
murgatroid9917be5892015-02-13 10:19:10 -0800582 if (!op->ParseOp(obj->Get(type), &ops[i], resources)) {
murgatroid99016bb502015-02-09 15:55:10 -0800583 return NanThrowTypeError("Incorrectly typed arguments to startBatch");
584 }
murgatroid9917be5892015-02-13 10:19:10 -0800585 op_vector->push_back(std::move(op));
murgatroid99a9b99c92015-02-05 17:42:01 -0800586 }
murgatroid9957dfd052015-02-13 10:41:25 -0800587 NanCallback *callback = new NanCallback(callback_func);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800588 grpc_call_error error = grpc_call_start_batch(
murgatroid99d66408b2015-02-13 10:40:07 -0800589 call->wrapped_call, &ops[0], nops, new struct tag(
murgatroid99e0123662015-02-13 11:14:03 -0800590 callback, op_vector.release(), resources));
murgatroid99e5061512015-01-12 18:14:35 -0800591 if (error != GRPC_CALL_OK) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800592 return NanThrowError("startBatch failed", error);
murgatroid99e5061512015-01-12 18:14:35 -0800593 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800594 CompletionQueueAsyncWorker::Next();
murgatroid99e5061512015-01-12 18:14:35 -0800595 NanReturnUndefined();
596}
597
598NAN_METHOD(Call::Cancel) {
599 NanScope();
600 if (!HasInstance(args.This())) {
murgatroid993548ed82015-01-15 15:38:45 -0800601 return NanThrowTypeError("cancel can only be called on Call objects");
murgatroid99e5061512015-01-12 18:14:35 -0800602 }
603 Call *call = ObjectWrap::Unwrap<Call>(args.This());
604 grpc_call_error error = grpc_call_cancel(call->wrapped_call);
605 if (error != GRPC_CALL_OK) {
606 return NanThrowError("cancel failed", error);
607 }
608 NanReturnUndefined();
609}
610
murgatroid99e5061512015-01-12 18:14:35 -0800611} // namespace node
612} // namespace grpc