blob: ff6b153c5303a5c3c32f65e2ff8695990d14bad4 [file] [log] [blame]
murgatroid99749666e2015-01-12 18:25:58 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * 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"
murgatroid99153b09d2015-09-25 16:04:03 -070042#include "grpc/grpc_security.h"
murgatroid99d4d67ad2015-02-09 10:43:21 -080043#include "grpc/support/alloc.h"
murgatroid99e5061512015-01-12 18:14:35 -080044#include "grpc/support/time.h"
45#include "byte_buffer.h"
46#include "call.h"
47#include "channel.h"
murgatroid999030c812016-09-16 13:25:08 -070048#include "completion_queue.h"
murgatroid99e5061512015-01-12 18:14:35 -080049#include "completion_queue_async_worker.h"
murgatroid995f709ca2015-09-30 14:22:54 -070050#include "call_credentials.h"
Craig Tiller7c70b6c2017-01-23 07:48:42 -080051#include "slice.h"
murgatroid99e5061512015-01-12 18:14:35 -080052#include "timeval.h"
murgatroid99e5061512015-01-12 18:14:35 -080053
murgatroid99ff43c092015-02-09 11:41:23 -080054using std::unique_ptr;
murgatroid9917be5892015-02-13 10:19:10 -080055using std::shared_ptr;
murgatroid99e0123662015-02-13 11:14:03 -080056using std::vector;
murgatroid99ff43c092015-02-09 11:41:23 -080057
murgatroid99e5061512015-01-12 18:14:35 -080058namespace grpc {
59namespace node {
60
murgatroid992b097832015-09-17 13:56:25 -070061using Nan::Callback;
62using Nan::EscapableHandleScope;
63using Nan::HandleScope;
64using Nan::Maybe;
65using Nan::MaybeLocal;
66using Nan::ObjectWrap;
67using Nan::Persistent;
68using Nan::Utf8String;
69
murgatroid99e5061512015-01-12 18:14:35 -080070using v8::Array;
murgatroid99016bb502015-02-09 15:55:10 -080071using v8::Boolean;
murgatroid99e5061512015-01-12 18:14:35 -080072using v8::Exception;
73using v8::External;
74using v8::Function;
75using v8::FunctionTemplate;
murgatroid99e5061512015-01-12 18:14:35 -080076using v8::Integer;
77using v8::Local;
78using v8::Number;
79using v8::Object;
80using v8::ObjectTemplate;
murgatroid99e5061512015-01-12 18:14:35 -080081using v8::Uint32;
82using v8::String;
83using v8::Value;
84
murgatroid992b097832015-09-17 13:56:25 -070085Callback *Call::constructor;
murgatroid99e5061512015-01-12 18:14:35 -080086Persistent<FunctionTemplate> Call::fun_tpl;
87
murgatroid9975a2bba2015-10-12 16:12:04 -070088/**
89 * Helper function for throwing errors with a grpc_call_error value.
90 * Modified from the answer by Gus Goose to
91 * http://stackoverflow.com/questions/31794200.
92 */
93Local<Value> nanErrorWithCode(const char *msg, grpc_call_error code) {
94 EscapableHandleScope scope;
95 Local<Object> err = Nan::Error(msg).As<Object>();
96 Nan::Set(err, Nan::New("code").ToLocalChecked(), Nan::New<Uint32>(code));
97 return scope.Escape(err);
98}
99
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800100bool CreateMetadataArray(Local<Object> metadata, grpc_metadata_array *array) {
murgatroid992b097832015-09-17 13:56:25 -0700101 HandleScope scope;
murgatroid99016bb502015-02-09 15:55:10 -0800102 grpc_metadata_array_init(array);
murgatroid992b097832015-09-17 13:56:25 -0700103 Local<Array> keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked();
murgatroid99a9b99c92015-02-05 17:42:01 -0800104 for (unsigned int i = 0; i < keys->Length(); i++) {
murgatroid992b097832015-09-17 13:56:25 -0700105 Local<String> current_key = Nan::To<String>(
106 Nan::Get(keys, i).ToLocalChecked()).ToLocalChecked();
107 Local<Value> value_array = Nan::Get(metadata, current_key).ToLocalChecked();
108 if (!value_array->IsArray()) {
murgatroid99a9b99c92015-02-05 17:42:01 -0800109 return false;
110 }
murgatroid992b097832015-09-17 13:56:25 -0700111 array->capacity += Local<Array>::Cast(value_array)->Length();
murgatroid99a9b99c92015-02-05 17:42:01 -0800112 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800113 array->metadata = reinterpret_cast<grpc_metadata*>(
114 gpr_malloc(array->capacity * sizeof(grpc_metadata)));
murgatroid99a9b99c92015-02-05 17:42:01 -0800115 for (unsigned int i = 0; i < keys->Length(); i++) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800116 Local<String> current_key(Nan::To<String>(keys->Get(i)).ToLocalChecked());
murgatroid992b097832015-09-17 13:56:25 -0700117 Local<Array> values = Local<Array>::Cast(
118 Nan::Get(metadata, current_key).ToLocalChecked());
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800119 grpc_slice key_slice = grpc_slice_intern(CreateSliceFromString(current_key));
murgatroid99a9b99c92015-02-05 17:42:01 -0800120 for (unsigned int j = 0; j < values->Length(); j++) {
murgatroid992b097832015-09-17 13:56:25 -0700121 Local<Value> value = Nan::Get(values, j).ToLocalChecked();
murgatroid99d4d67ad2015-02-09 10:43:21 -0800122 grpc_metadata *current = &array->metadata[array->count];
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800123 current->key = key_slice;
murgatroid99da771512015-03-17 18:13:55 -0700124 // Only allow binary headers for "-bin" keys
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800125 if (grpc_is_binary_header(key_slice)) {
murgatroid99da771512015-03-17 18:13:55 -0700126 if (::node::Buffer::HasInstance(value)) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800127 current->value = CreateSliceFromBuffer(value);
murgatroid994ad40032015-08-27 10:02:24 -0700128 } else {
129 return false;
murgatroid99da771512015-03-17 18:13:55 -0700130 }
murgatroid99a9b99c92015-02-05 17:42:01 -0800131 } else {
murgatroid994ad40032015-08-27 10:02:24 -0700132 if (value->IsString()) {
murgatroid992b097832015-09-17 13:56:25 -0700133 Local<String> string_value = Nan::To<String>(value).ToLocalChecked();
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800134 current->value = CreateSliceFromString(string_value);
murgatroid994ad40032015-08-27 10:02:24 -0700135 } else {
136 return false;
137 }
murgatroid99a9b99c92015-02-05 17:42:01 -0800138 }
139 array->count += 1;
140 }
141 }
142 return true;
143}
144
murgatroid992b097832015-09-17 13:56:25 -0700145Local<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
146 EscapableHandleScope scope;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800147 grpc_metadata *metadata_elements = metadata_array->metadata;
148 size_t length = metadata_array->count;
murgatroid992b097832015-09-17 13:56:25 -0700149 Local<Object> metadata_object = Nan::New<Object>();
murgatroid99d4d67ad2015-02-09 10:43:21 -0800150 for (unsigned int i = 0; i < length; i++) {
151 grpc_metadata* elem = &metadata_elements[i];
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800152 // TODO(murgatroid99): Use zero-copy string construction instead
153 Local<String> key_string = CopyStringFromSlice(elem->key);
murgatroid992b097832015-09-17 13:56:25 -0700154 Local<Array> array;
155 MaybeLocal<Value> maybe_array = Nan::Get(metadata_object, key_string);
156 if (maybe_array.IsEmpty() || !maybe_array.ToLocalChecked()->IsArray()) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800157 array = Nan::New<Array>(0);
murgatroid992b097832015-09-17 13:56:25 -0700158 Nan::Set(metadata_object, key_string, array);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800159 } else {
murgatroid992b097832015-09-17 13:56:25 -0700160 array = Local<Array>::Cast(maybe_array.ToLocalChecked());
murgatroid99d4d67ad2015-02-09 10:43:21 -0800161 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800162 if (grpc_is_binary_header(elem->key)) {
163 Nan::Set(array, array->Length(), CreateBufferFromSlice(elem->value));
murgatroid99da771512015-03-17 18:13:55 -0700164 } else {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800165 // TODO(murgatroid99): Use zero-copy string construction instead
166 Nan::Set(array, array->Length(), CopyStringFromSlice(elem->value));
murgatroid99da771512015-03-17 18:13:55 -0700167 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800168 }
murgatroid992b097832015-09-17 13:56:25 -0700169 return scope.Escape(metadata_object);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800170}
171
murgatroid992b097832015-09-17 13:56:25 -0700172Local<Value> Op::GetOpType() const {
173 EscapableHandleScope scope;
174 return scope.Escape(Nan::New(GetTypeString()).ToLocalChecked());
murgatroid99ff43c092015-02-09 11:41:23 -0800175}
murgatroid99d4d67ad2015-02-09 10:43:21 -0800176
murgatroid99474f53b2015-09-14 13:53:07 -0700177Op::~Op() {
178}
179
murgatroid99d4d67ad2015-02-09 10:43:21 -0800180class SendMetadataOp : public Op {
181 public:
murgatroid992b097832015-09-17 13:56:25 -0700182 Local<Value> GetNodeValue() const {
183 EscapableHandleScope scope;
184 return scope.Escape(Nan::True());
murgatroid99d4d67ad2015-02-09 10:43:21 -0800185 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800186 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800187 if (!value->IsObject()) {
188 return false;
189 }
190 grpc_metadata_array array;
murgatroid992b097832015-09-17 13:56:25 -0700191 MaybeLocal<Object> maybe_metadata = Nan::To<Object>(value);
192 if (maybe_metadata.IsEmpty()) {
193 return false;
194 }
195 if (!CreateMetadataArray(maybe_metadata.ToLocalChecked(),
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800196 &array)) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800197 return false;
198 }
199 out->data.send_initial_metadata.count = array.count;
200 out->data.send_initial_metadata.metadata = array.metadata;
201 return true;
202 }
murgatroid999030c812016-09-16 13:25:08 -0700203 bool IsFinalOp() {
204 return false;
205 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800206 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800207 std::string GetTypeString() const {
murgatroid99a627d892015-07-23 10:40:19 -0700208 return "send_metadata";
murgatroid99d4d67ad2015-02-09 10:43:21 -0800209 }
210};
211
212class SendMessageOp : public Op {
213 public:
Seongjin Chob531f762015-11-30 05:15:58 +0900214 SendMessageOp() {
215 send_message = NULL;
216 }
217 ~SendMessageOp() {
218 if (send_message != NULL) {
219 grpc_byte_buffer_destroy(send_message);
220 }
221 }
murgatroid992b097832015-09-17 13:56:25 -0700222 Local<Value> GetNodeValue() const {
223 EscapableHandleScope scope;
224 return scope.Escape(Nan::True());
murgatroid99d4d67ad2015-02-09 10:43:21 -0800225 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800226 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid995f875d22015-03-04 11:28:37 -0800227 if (!::node::Buffer::HasInstance(value)) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800228 return false;
229 }
murgatroid992b097832015-09-17 13:56:25 -0700230 Local<Object> object_value = Nan::To<Object>(value).ToLocalChecked();
231 MaybeLocal<Value> maybe_flag_value = Nan::Get(
232 object_value, Nan::New("grpcWriteFlags").ToLocalChecked());
233 if (!maybe_flag_value.IsEmpty()) {
234 Local<Value> flag_value = maybe_flag_value.ToLocalChecked();
murgatroid991d8e3df2015-07-22 15:02:51 -0700235 if (flag_value->IsUint32()) {
murgatroid992b097832015-09-17 13:56:25 -0700236 Maybe<uint32_t> maybe_flag = Nan::To<uint32_t>(flag_value);
237 out->flags = maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK;
murgatroid991d8e3df2015-07-22 15:02:51 -0700238 }
239 }
Seongjin Chob531f762015-11-30 05:15:58 +0900240 send_message = BufferToByteBuffer(value);
Mark D. Roth448c1f02017-01-25 10:44:30 -0800241 out->data.send_message.send_message = send_message;
murgatroid99016bb502015-02-09 15:55:10 -0800242 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800243 }
murgatroid999030c812016-09-16 13:25:08 -0700244 bool IsFinalOp() {
245 return false;
246 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800247 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800248 std::string GetTypeString() const {
murgatroid99a627d892015-07-23 10:40:19 -0700249 return "send_message";
murgatroid99d4d67ad2015-02-09 10:43:21 -0800250 }
Seongjin Chob531f762015-11-30 05:15:58 +0900251 private:
252 grpc_byte_buffer *send_message;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800253};
254
255class SendClientCloseOp : public Op {
256 public:
murgatroid992b097832015-09-17 13:56:25 -0700257 Local<Value> GetNodeValue() const {
258 EscapableHandleScope scope;
259 return scope.Escape(Nan::True());
murgatroid99d4d67ad2015-02-09 10:43:21 -0800260 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800261 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800262 return true;
263 }
murgatroid999030c812016-09-16 13:25:08 -0700264 bool IsFinalOp() {
265 return false;
266 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800267 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800268 std::string GetTypeString() const {
murgatroid99a627d892015-07-23 10:40:19 -0700269 return "client_close";
murgatroid99d4d67ad2015-02-09 10:43:21 -0800270 }
271};
272
273class SendServerStatusOp : public Op {
274 public:
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800275 ~SendServerStatusOp() {
276 grpc_slice_unref(details);
277 }
murgatroid992b097832015-09-17 13:56:25 -0700278 Local<Value> GetNodeValue() const {
279 EscapableHandleScope scope;
280 return scope.Escape(Nan::True());
murgatroid99d4d67ad2015-02-09 10:43:21 -0800281 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800282 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid99cd0b9062015-02-10 09:16:49 -0800283 if (!value->IsObject()) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800284 return false;
285 }
murgatroid992b097832015-09-17 13:56:25 -0700286 Local<Object> server_status = Nan::To<Object>(value).ToLocalChecked();
287 MaybeLocal<Value> maybe_metadata = Nan::Get(
288 server_status, Nan::New("metadata").ToLocalChecked());
289 if (maybe_metadata.IsEmpty()) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800290 return false;
291 }
murgatroid992b097832015-09-17 13:56:25 -0700292 if (!maybe_metadata.ToLocalChecked()->IsObject()) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800293 return false;
294 }
murgatroid992b097832015-09-17 13:56:25 -0700295 Local<Object> metadata = Nan::To<Object>(
296 maybe_metadata.ToLocalChecked()).ToLocalChecked();
297 MaybeLocal<Value> maybe_code = Nan::Get(server_status,
298 Nan::New("code").ToLocalChecked());
299 if (maybe_code.IsEmpty()) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800300 return false;
301 }
murgatroid992b097832015-09-17 13:56:25 -0700302 if (!maybe_code.ToLocalChecked()->IsUint32()) {
303 return false;
304 }
305 uint32_t code = Nan::To<uint32_t>(maybe_code.ToLocalChecked()).FromJust();
306 MaybeLocal<Value> maybe_details = Nan::Get(
307 server_status, Nan::New("details").ToLocalChecked());
308 if (maybe_details.IsEmpty()) {
309 return false;
310 }
311 if (!maybe_details.ToLocalChecked()->IsString()) {
312 return false;
313 }
314 Local<String> details = Nan::To<String>(
315 maybe_details.ToLocalChecked()).ToLocalChecked();
murgatroid99d4d67ad2015-02-09 10:43:21 -0800316 grpc_metadata_array array;
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800317 if (!CreateMetadataArray(metadata, &array)) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800318 return false;
319 }
320 out->data.send_status_from_server.trailing_metadata_count = array.count;
321 out->data.send_status_from_server.trailing_metadata = array.metadata;
322 out->data.send_status_from_server.status =
murgatroid992b097832015-09-17 13:56:25 -0700323 static_cast<grpc_status_code>(code);
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800324 this->details = CreateSliceFromString(details);
325 out->data.send_status_from_server.status_details = &this->details;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800326 return true;
327 }
murgatroid999030c812016-09-16 13:25:08 -0700328 bool IsFinalOp() {
329 return true;
330 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800331 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800332 std::string GetTypeString() const {
murgatroid99a627d892015-07-23 10:40:19 -0700333 return "send_status";
murgatroid99d4d67ad2015-02-09 10:43:21 -0800334 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800335
336 private:
337 grpc_slice details;
murgatroid99016bb502015-02-09 15:55:10 -0800338};
murgatroid99d4d67ad2015-02-09 10:43:21 -0800339
340class GetMetadataOp : public Op {
341 public:
342 GetMetadataOp() {
343 grpc_metadata_array_init(&recv_metadata);
344 }
345
346 ~GetMetadataOp() {
347 grpc_metadata_array_destroy(&recv_metadata);
348 }
349
murgatroid992b097832015-09-17 13:56:25 -0700350 Local<Value> GetNodeValue() const {
351 EscapableHandleScope scope;
352 return scope.Escape(ParseMetadata(&recv_metadata));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800353 }
354
Craig Tillerafceb2e2017-01-26 12:21:28 -0800355<<<<<<< HEAD
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800356 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800357 out->data.recv_initial_metadata = &recv_metadata;
Craig Tillerafceb2e2017-01-26 12:21:28 -0800358=======
murgatroid99d4d67ad2015-02-09 10:43:21 -0800359 bool ParseOp(Local<Value> value, grpc_op *out,
360 shared_ptr<Resources> resources) {
Mark D. Roth448c1f02017-01-25 10:44:30 -0800361 out->data.recv_initial_metadata.recv_initial_metadata = &recv_metadata;
Craig Tillerafceb2e2017-01-26 12:21:28 -0800362>>>>>>> 4ffcb2058df96c1fa0a319cd3e5d4aa9358e5bae
murgatroid99016bb502015-02-09 15:55:10 -0800363 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800364 }
murgatroid999030c812016-09-16 13:25:08 -0700365 bool IsFinalOp() {
366 return false;
367 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800368
369 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800370 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800371 return "metadata";
372 }
373
374 private:
375 grpc_metadata_array recv_metadata;
376};
377
378class ReadMessageOp : public Op {
379 public:
380 ReadMessageOp() {
381 recv_message = NULL;
382 }
383 ~ReadMessageOp() {
384 if (recv_message != NULL) {
murgatroid99474f53b2015-09-14 13:53:07 -0700385 grpc_byte_buffer_destroy(recv_message);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800386 }
387 }
murgatroid992b097832015-09-17 13:56:25 -0700388 Local<Value> GetNodeValue() const {
389 EscapableHandleScope scope;
390 return scope.Escape(ByteBufferToBuffer(recv_message));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800391 }
392
Craig Tillerafceb2e2017-01-26 12:21:28 -0800393<<<<<<< HEAD
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800394 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800395 out->data.recv_message = &recv_message;
Craig Tillerafceb2e2017-01-26 12:21:28 -0800396=======
murgatroid99d4d67ad2015-02-09 10:43:21 -0800397 bool ParseOp(Local<Value> value, grpc_op *out,
398 shared_ptr<Resources> resources) {
Mark D. Roth448c1f02017-01-25 10:44:30 -0800399 out->data.recv_message.recv_message = &recv_message;
Craig Tillerafceb2e2017-01-26 12:21:28 -0800400>>>>>>> 4ffcb2058df96c1fa0a319cd3e5d4aa9358e5bae
murgatroid99ff43c092015-02-09 11:41:23 -0800401 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800402 }
murgatroid999030c812016-09-16 13:25:08 -0700403 bool IsFinalOp() {
404 return false;
405 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800406
407 protected:
murgatroid99016bb502015-02-09 15:55:10 -0800408 std::string GetTypeString() const {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800409 return "read";
410 }
411
412 private:
413 grpc_byte_buffer *recv_message;
414};
415
416class ClientStatusOp : public Op {
417 public:
418 ClientStatusOp() {
murgatroid99016bb502015-02-09 15:55:10 -0800419 grpc_metadata_array_init(&metadata_array);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800420 }
421
422 ~ClientStatusOp() {
murgatroid99016bb502015-02-09 15:55:10 -0800423 grpc_metadata_array_destroy(&metadata_array);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800424 }
425
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800426 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800427 out->data.recv_status_on_client.trailing_metadata = &metadata_array;
428 out->data.recv_status_on_client.status = &status;
429 out->data.recv_status_on_client.status_details = &status_details;
murgatroid99ff43c092015-02-09 11:41:23 -0800430 return true;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800431 }
432
murgatroid992b097832015-09-17 13:56:25 -0700433 Local<Value> GetNodeValue() const {
434 EscapableHandleScope scope;
435 Local<Object> status_obj = Nan::New<Object>();
436 Nan::Set(status_obj, Nan::New("code").ToLocalChecked(),
437 Nan::New<Number>(status));
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800438 Nan::Set(status_obj, Nan::New("details").ToLocalChecked(),
439 CopyStringFromSlice(status_details));
murgatroid992b097832015-09-17 13:56:25 -0700440 Nan::Set(status_obj, Nan::New("metadata").ToLocalChecked(),
441 ParseMetadata(&metadata_array));
442 return scope.Escape(status_obj);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800443 }
murgatroid999030c812016-09-16 13:25:08 -0700444 bool IsFinalOp() {
445 return true;
446 }
murgatroid99ff43c092015-02-09 11:41:23 -0800447 protected:
448 std::string GetTypeString() const {
449 return "status";
450 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800451 private:
452 grpc_metadata_array metadata_array;
453 grpc_status_code status;
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800454 grpc_slice status_details;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800455};
456
457class ServerCloseResponseOp : public Op {
458 public:
murgatroid992b097832015-09-17 13:56:25 -0700459 Local<Value> GetNodeValue() const {
460 EscapableHandleScope scope;
461 return scope.Escape(Nan::New<Boolean>(cancelled));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800462 }
463
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800464 bool ParseOp(Local<Value> value, grpc_op *out) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800465 out->data.recv_close_on_server.cancelled = &cancelled;
murgatroid99ff43c092015-02-09 11:41:23 -0800466 return true;
467 }
murgatroid999030c812016-09-16 13:25:08 -0700468 bool IsFinalOp() {
469 return false;
470 }
murgatroid99ff43c092015-02-09 11:41:23 -0800471
472 protected:
473 std::string GetTypeString() const {
474 return "cancelled";
murgatroid99d4d67ad2015-02-09 10:43:21 -0800475 }
476
477 private:
478 int cancelled;
479};
480
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800481tag::tag(Callback *callback, OpVec *ops, Call *call) :
482 callback(callback), ops(ops), call(call){
murgatroid99016bb502015-02-09 15:55:10 -0800483}
murgatroid9917be5892015-02-13 10:19:10 -0800484
murgatroid99016bb502015-02-09 15:55:10 -0800485tag::~tag() {
486 delete callback;
487 delete ops;
murgatroid99016bb502015-02-09 15:55:10 -0800488}
489
murgatroid992b097832015-09-17 13:56:25 -0700490Local<Value> GetTagNodeValue(void *tag) {
491 EscapableHandleScope scope;
murgatroid99016bb502015-02-09 15:55:10 -0800492 struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
murgatroid992b097832015-09-17 13:56:25 -0700493 Local<Object> tag_obj = Nan::New<Object>();
murgatroid99e0123662015-02-13 11:14:03 -0800494 for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
murgatroid99016bb502015-02-09 15:55:10 -0800495 it != tag_struct->ops->end(); ++it) {
496 Op *op_ptr = it->get();
murgatroid992b097832015-09-17 13:56:25 -0700497 Nan::Set(tag_obj, op_ptr->GetOpType(), op_ptr->GetNodeValue());
murgatroid99016bb502015-02-09 15:55:10 -0800498 }
murgatroid992b097832015-09-17 13:56:25 -0700499 return scope.Escape(tag_obj);
murgatroid99016bb502015-02-09 15:55:10 -0800500}
501
murgatroid992b097832015-09-17 13:56:25 -0700502Callback *GetTagCallback(void *tag) {
murgatroid99016bb502015-02-09 15:55:10 -0800503 struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
murgatroid991578c6a2015-02-11 16:19:55 -0800504 return tag_struct->callback;
murgatroid99016bb502015-02-09 15:55:10 -0800505}
506
murgatroid999030c812016-09-16 13:25:08 -0700507void CompleteTag(void *tag) {
508 struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
509 bool is_final_op = false;
510 if (tag_struct->call == NULL) {
511 return;
512 }
513 for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
514 it != tag_struct->ops->end(); ++it) {
515 Op *op_ptr = it->get();
516 if (op_ptr->IsFinalOp()) {
517 is_final_op = true;
518 }
519 }
520 tag_struct->call->CompleteBatch(is_final_op);
521}
522
murgatroid99016bb502015-02-09 15:55:10 -0800523void DestroyTag(void *tag) {
524 struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
525 delete tag_struct;
526}
murgatroid99d4d67ad2015-02-09 10:43:21 -0800527
murgatroid999030c812016-09-16 13:25:08 -0700528Call::Call(grpc_call *call) : wrapped_call(call),
529 pending_batches(0),
530 has_final_op_completed(false) {
murgatroid9977659062015-02-11 09:26:25 -0800531}
murgatroid99e5061512015-01-12 18:14:35 -0800532
murgatroid9977659062015-02-11 09:26:25 -0800533Call::~Call() {
murgatroid999030c812016-09-16 13:25:08 -0700534 if (wrapped_call != NULL) {
535 grpc_call_destroy(wrapped_call);
536 }
murgatroid9977659062015-02-11 09:26:25 -0800537}
murgatroid99e5061512015-01-12 18:14:35 -0800538
murgatroid992b097832015-09-17 13:56:25 -0700539void Call::Init(Local<Object> exports) {
540 HandleScope scope;
541 Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
542 tpl->SetClassName(Nan::New("Call").ToLocalChecked());
murgatroid99e5061512015-01-12 18:14:35 -0800543 tpl->InstanceTemplate()->SetInternalFieldCount(1);
murgatroid992b097832015-09-17 13:56:25 -0700544 Nan::SetPrototypeMethod(tpl, "startBatch", StartBatch);
545 Nan::SetPrototypeMethod(tpl, "cancel", Cancel);
546 Nan::SetPrototypeMethod(tpl, "cancelWithStatus", CancelWithStatus);
547 Nan::SetPrototypeMethod(tpl, "getPeer", GetPeer);
murgatroid99153b09d2015-09-25 16:04:03 -0700548 Nan::SetPrototypeMethod(tpl, "setCredentials", SetCredentials);
murgatroid992b097832015-09-17 13:56:25 -0700549 fun_tpl.Reset(tpl);
550 Local<Function> ctr = Nan::GetFunction(tpl).ToLocalChecked();
551 Nan::Set(exports, Nan::New("Call").ToLocalChecked(), ctr);
552 constructor = new Callback(ctr);
murgatroid99e5061512015-01-12 18:14:35 -0800553}
554
murgatroid992b097832015-09-17 13:56:25 -0700555bool Call::HasInstance(Local<Value> val) {
556 HandleScope scope;
557 return Nan::New(fun_tpl)->HasInstance(val);
murgatroid99e5061512015-01-12 18:14:35 -0800558}
559
murgatroid992b097832015-09-17 13:56:25 -0700560Local<Value> Call::WrapStruct(grpc_call *call) {
561 EscapableHandleScope scope;
murgatroid99e5061512015-01-12 18:14:35 -0800562 if (call == NULL) {
murgatroid992b097832015-09-17 13:56:25 -0700563 return scope.Escape(Nan::Null());
murgatroid99e5061512015-01-12 18:14:35 -0800564 }
565 const int argc = 1;
murgatroid992b097832015-09-17 13:56:25 -0700566 Local<Value> argv[argc] = {Nan::New<External>(
567 reinterpret_cast<void *>(call))};
568 MaybeLocal<Object> maybe_instance = Nan::NewInstance(
569 constructor->GetFunction(), argc, argv);
570 if (maybe_instance.IsEmpty()) {
571 return scope.Escape(Nan::Null());
572 } else {
573 return scope.Escape(maybe_instance.ToLocalChecked());
574 }
murgatroid99e5061512015-01-12 18:14:35 -0800575}
576
murgatroid999030c812016-09-16 13:25:08 -0700577void Call::CompleteBatch(bool is_final_op) {
578 if (is_final_op) {
579 this->has_final_op_completed = true;
580 }
581 this->pending_batches--;
582 if (this->has_final_op_completed && this->pending_batches == 0) {
583 grpc_call_destroy(this->wrapped_call);
584 this->wrapped_call = NULL;
585 }
586}
587
murgatroid99e5061512015-01-12 18:14:35 -0800588NAN_METHOD(Call::New) {
murgatroid992b097832015-09-17 13:56:25 -0700589 if (info.IsConstructCall()) {
murgatroid99e5061512015-01-12 18:14:35 -0800590 Call *call;
murgatroid992b097832015-09-17 13:56:25 -0700591 if (info[0]->IsExternal()) {
592 Local<External> ext = info[0].As<External>();
murgatroid99e5061512015-01-12 18:14:35 -0800593 // This option is used for wrapping an existing call
Craig Tillere8e304e2015-01-13 14:41:29 -0800594 grpc_call *call_value =
murgatroid995f875d22015-03-04 11:28:37 -0800595 reinterpret_cast<grpc_call *>(ext->Value());
murgatroid99e5061512015-01-12 18:14:35 -0800596 call = new Call(call_value);
597 } else {
murgatroid992b097832015-09-17 13:56:25 -0700598 if (!Channel::HasInstance(info[0])) {
599 return Nan::ThrowTypeError("Call's first argument must be a Channel");
murgatroid99e5061512015-01-12 18:14:35 -0800600 }
murgatroid992b097832015-09-17 13:56:25 -0700601 if (!info[1]->IsString()) {
602 return Nan::ThrowTypeError("Call's second argument must be a string");
murgatroid99e5061512015-01-12 18:14:35 -0800603 }
murgatroid992b097832015-09-17 13:56:25 -0700604 if (!(info[2]->IsNumber() || info[2]->IsDate())) {
605 return Nan::ThrowTypeError(
murgatroid99e5061512015-01-12 18:14:35 -0800606 "Call's third argument must be a date or a number");
607 }
murgatroid9999e21042015-08-14 10:35:43 -0700608 // These arguments are at the end because they are optional
609 grpc_call *parent_call = NULL;
murgatroid992b097832015-09-17 13:56:25 -0700610 if (Call::HasInstance(info[4])) {
611 Call *parent_obj = ObjectWrap::Unwrap<Call>(
612 Nan::To<Object>(info[4]).ToLocalChecked());
murgatroid9999e21042015-08-14 10:35:43 -0700613 parent_call = parent_obj->wrapped_call;
murgatroid992b097832015-09-17 13:56:25 -0700614 } else if (!(info[4]->IsUndefined() || info[4]->IsNull())) {
615 return Nan::ThrowTypeError(
murgatroid9999e21042015-08-14 10:35:43 -0700616 "Call's fifth argument must be another call, if provided");
617 }
Craig Tiller7536af02015-12-22 13:49:30 -0800618 uint32_t propagate_flags = GRPC_PROPAGATE_DEFAULTS;
murgatroid992b097832015-09-17 13:56:25 -0700619 if (info[5]->IsUint32()) {
620 propagate_flags = Nan::To<uint32_t>(info[5]).FromJust();
621 } else if (!(info[5]->IsUndefined() || info[5]->IsNull())) {
622 return Nan::ThrowTypeError(
murgatroid992cc1ed92015-08-14 12:57:00 -0700623 "Call's sixth argument must be propagate flags, if provided");
murgatroid9999e21042015-08-14 10:35:43 -0700624 }
murgatroid992b097832015-09-17 13:56:25 -0700625 Local<Object> channel_object = Nan::To<Object>(info[0]).ToLocalChecked();
murgatroid99e5061512015-01-12 18:14:35 -0800626 Channel *channel = ObjectWrap::Unwrap<Channel>(channel_object);
627 if (channel->GetWrappedChannel() == NULL) {
murgatroid992b097832015-09-17 13:56:25 -0700628 return Nan::ThrowError("Call cannot be created from a closed channel");
murgatroid99e5061512015-01-12 18:14:35 -0800629 }
murgatroid992b097832015-09-17 13:56:25 -0700630 double deadline = Nan::To<double>(info[2]).FromJust();
murgatroid99e5061512015-01-12 18:14:35 -0800631 grpc_channel *wrapped_channel = channel->GetWrappedChannel();
murgatroid993f507d02015-08-03 15:17:53 -0700632 grpc_call *wrapped_call;
murgatroid992b097832015-09-17 13:56:25 -0700633 if (info[3]->IsString()) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800634 grpc_slice *host = new grpc_slice;
635 *host = CreateSliceFromString(
636 Nan::To<String>(info[3]).ToLocalChecked());
murgatroid993f507d02015-08-03 15:17:53 -0700637 wrapped_call = grpc_channel_create_call(
murgatroid9999e21042015-08-14 10:35:43 -0700638 wrapped_channel, parent_call, propagate_flags,
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800639 GetCompletionQueue(), CreateSliceFromString(
640 Nan::To<String>(info[1]).ToLocalChecked()),
641 host, MillisecondsToTimespec(deadline), NULL);
642 delete host;
murgatroid992b097832015-09-17 13:56:25 -0700643 } else if (info[3]->IsUndefined() || info[3]->IsNull()) {
murgatroid993f507d02015-08-03 15:17:53 -0700644 wrapped_call = grpc_channel_create_call(
murgatroid9999e21042015-08-14 10:35:43 -0700645 wrapped_channel, parent_call, propagate_flags,
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800646 GetCompletionQueue(), CreateSliceFromString(
647 Nan::To<String>(info[1]).ToLocalChecked()),
Nicolas "Pixel" Noble9b6248f2015-08-12 19:53:03 +0200648 NULL, MillisecondsToTimespec(deadline), NULL);
murgatroid993f507d02015-08-03 15:17:53 -0700649 } else {
murgatroid992b097832015-09-17 13:56:25 -0700650 return Nan::ThrowTypeError("Call's fourth argument must be a string");
murgatroid993f507d02015-08-03 15:17:53 -0700651 }
murgatroid99e5061512015-01-12 18:14:35 -0800652 call = new Call(wrapped_call);
murgatroid99c0a64cd2016-08-15 13:14:16 -0700653 Nan::Set(info.This(), Nan::New("channel_").ToLocalChecked(),
654 channel_object);
murgatroid99e5061512015-01-12 18:14:35 -0800655 }
murgatroid992b097832015-09-17 13:56:25 -0700656 call->Wrap(info.This());
657 info.GetReturnValue().Set(info.This());
murgatroid99e5061512015-01-12 18:14:35 -0800658 } else {
659 const int argc = 4;
murgatroid992b097832015-09-17 13:56:25 -0700660 Local<Value> argv[argc] = {info[0], info[1], info[2], info[3]};
murgatroid99c0a64cd2016-08-15 13:14:16 -0700661 MaybeLocal<Object> maybe_instance = Nan::NewInstance(
662 constructor->GetFunction(), argc, argv);
murgatroid992b097832015-09-17 13:56:25 -0700663 if (maybe_instance.IsEmpty()) {
664 // There's probably a pending exception
665 return;
666 } else {
667 info.GetReturnValue().Set(maybe_instance.ToLocalChecked());
668 }
murgatroid99e5061512015-01-12 18:14:35 -0800669 }
670}
671
murgatroid99a9b99c92015-02-05 17:42:01 -0800672NAN_METHOD(Call::StartBatch) {
murgatroid992b097832015-09-17 13:56:25 -0700673 if (!Call::HasInstance(info.This())) {
674 return Nan::ThrowTypeError("startBatch can only be called on Call objects");
murgatroid99a9b99c92015-02-05 17:42:01 -0800675 }
murgatroid992b097832015-09-17 13:56:25 -0700676 if (!info[0]->IsObject()) {
677 return Nan::ThrowError("startBatch's first argument must be an object");
murgatroid99a9b99c92015-02-05 17:42:01 -0800678 }
murgatroid992b097832015-09-17 13:56:25 -0700679 if (!info[1]->IsFunction()) {
680 return Nan::ThrowError("startBatch's second argument must be a callback");
murgatroid99a9b99c92015-02-05 17:42:01 -0800681 }
murgatroid992b097832015-09-17 13:56:25 -0700682 Local<Function> callback_func = info[1].As<Function>();
683 Call *call = ObjectWrap::Unwrap<Call>(info.This());
murgatroid992b097832015-09-17 13:56:25 -0700684 Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
685 Local<Array> keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked();
murgatroid99a9b99c92015-02-05 17:42:01 -0800686 size_t nops = keys->Length();
murgatroid99e0123662015-02-13 11:14:03 -0800687 vector<grpc_op> ops(nops);
688 unique_ptr<OpVec> op_vector(new OpVec());
murgatroid99a9b99c92015-02-05 17:42:01 -0800689 for (unsigned int i = 0; i < nops; i++) {
murgatroid9917be5892015-02-13 10:19:10 -0800690 unique_ptr<Op> op;
murgatroid992b097832015-09-17 13:56:25 -0700691 MaybeLocal<Value> maybe_key = Nan::Get(keys, i);
692 if (maybe_key.IsEmpty() || (!maybe_key.ToLocalChecked()->IsUint32())) {
693 return Nan::ThrowError(
murgatroid99a9b99c92015-02-05 17:42:01 -0800694 "startBatch's first argument's keys must be integers");
695 }
murgatroid992b097832015-09-17 13:56:25 -0700696 uint32_t type = Nan::To<uint32_t>(maybe_key.ToLocalChecked()).FromJust();
murgatroid99d4d67ad2015-02-09 10:43:21 -0800697 ops[i].op = static_cast<grpc_op_type>(type);
David Garcia Quintasba710e52015-06-15 13:31:15 -0700698 ops[i].flags = 0;
Craig Tillerb815fb22015-08-19 08:02:38 -0700699 ops[i].reserved = NULL;
murgatroid99a9b99c92015-02-05 17:42:01 -0800700 switch (type) {
701 case GRPC_OP_SEND_INITIAL_METADATA:
murgatroid9917be5892015-02-13 10:19:10 -0800702 op.reset(new SendMetadataOp());
murgatroid99d4d67ad2015-02-09 10:43:21 -0800703 break;
murgatroid99a9b99c92015-02-05 17:42:01 -0800704 case GRPC_OP_SEND_MESSAGE:
murgatroid9917be5892015-02-13 10:19:10 -0800705 op.reset(new SendMessageOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800706 break;
707 case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
murgatroid9917be5892015-02-13 10:19:10 -0800708 op.reset(new SendClientCloseOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800709 break;
710 case GRPC_OP_SEND_STATUS_FROM_SERVER:
murgatroid9917be5892015-02-13 10:19:10 -0800711 op.reset(new SendServerStatusOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800712 break;
713 case GRPC_OP_RECV_INITIAL_METADATA:
murgatroid9917be5892015-02-13 10:19:10 -0800714 op.reset(new GetMetadataOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800715 break;
716 case GRPC_OP_RECV_MESSAGE:
murgatroid9917be5892015-02-13 10:19:10 -0800717 op.reset(new ReadMessageOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800718 break;
719 case GRPC_OP_RECV_STATUS_ON_CLIENT:
murgatroid9917be5892015-02-13 10:19:10 -0800720 op.reset(new ClientStatusOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800721 break;
722 case GRPC_OP_RECV_CLOSE_ON_SERVER:
murgatroid9917be5892015-02-13 10:19:10 -0800723 op.reset(new ServerCloseResponseOp());
murgatroid99a9b99c92015-02-05 17:42:01 -0800724 break;
murgatroid99d4d67ad2015-02-09 10:43:21 -0800725 default:
murgatroid992b097832015-09-17 13:56:25 -0700726 return Nan::ThrowError("Argument object had an unrecognized key");
murgatroid99a9b99c92015-02-05 17:42:01 -0800727 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800728 if (!op->ParseOp(obj->Get(type), &ops[i])) {
murgatroid992b097832015-09-17 13:56:25 -0700729 return Nan::ThrowTypeError("Incorrectly typed arguments to startBatch");
murgatroid99016bb502015-02-09 15:55:10 -0800730 }
murgatroid9917be5892015-02-13 10:19:10 -0800731 op_vector->push_back(std::move(op));
murgatroid99a9b99c92015-02-05 17:42:01 -0800732 }
murgatroid992b097832015-09-17 13:56:25 -0700733 Callback *callback = new Callback(callback_func);
murgatroid99d4d67ad2015-02-09 10:43:21 -0800734 grpc_call_error error = grpc_call_start_batch(
murgatroid99d66408b2015-02-13 10:40:07 -0800735 call->wrapped_call, &ops[0], nops, new struct tag(
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800736 callback, op_vector.release(), call), NULL);
murgatroid99e5061512015-01-12 18:14:35 -0800737 if (error != GRPC_CALL_OK) {
murgatroid992b097832015-09-17 13:56:25 -0700738 return Nan::ThrowError(nanErrorWithCode("startBatch failed", error));
murgatroid99e5061512015-01-12 18:14:35 -0800739 }
murgatroid999030c812016-09-16 13:25:08 -0700740 call->pending_batches++;
741 CompletionQueueNext();
murgatroid99e5061512015-01-12 18:14:35 -0800742}
743
744NAN_METHOD(Call::Cancel) {
murgatroid992b097832015-09-17 13:56:25 -0700745 if (!Call::HasInstance(info.This())) {
746 return Nan::ThrowTypeError("cancel can only be called on Call objects");
murgatroid99e5061512015-01-12 18:14:35 -0800747 }
murgatroid992b097832015-09-17 13:56:25 -0700748 Call *call = ObjectWrap::Unwrap<Call>(info.This());
Nicolas "Pixel" Noble8e6bab52015-08-07 01:40:49 +0200749 grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL);
murgatroid99e5061512015-01-12 18:14:35 -0800750 if (error != GRPC_CALL_OK) {
murgatroid992b097832015-09-17 13:56:25 -0700751 return Nan::ThrowError(nanErrorWithCode("cancel failed", error));
murgatroid99e5061512015-01-12 18:14:35 -0800752 }
murgatroid99e5061512015-01-12 18:14:35 -0800753}
754
murgatroid997d58aba2015-08-27 16:11:08 -0700755NAN_METHOD(Call::CancelWithStatus) {
murgatroid992b097832015-09-17 13:56:25 -0700756 Nan::HandleScope scope;
757 if (!HasInstance(info.This())) {
758 return Nan::ThrowTypeError("cancel can only be called on Call objects");
murgatroid997d58aba2015-08-27 16:11:08 -0700759 }
murgatroid992b097832015-09-17 13:56:25 -0700760 if (!info[0]->IsUint32()) {
761 return Nan::ThrowTypeError(
murgatroid997d58aba2015-08-27 16:11:08 -0700762 "cancelWithStatus's first argument must be a status code");
763 }
murgatroid992b097832015-09-17 13:56:25 -0700764 if (!info[1]->IsString()) {
765 return Nan::ThrowTypeError(
murgatroid997d58aba2015-08-27 16:11:08 -0700766 "cancelWithStatus's second argument must be a string");
767 }
murgatroid992b097832015-09-17 13:56:25 -0700768 Call *call = ObjectWrap::Unwrap<Call>(info.This());
769 grpc_status_code code = static_cast<grpc_status_code>(
770 Nan::To<uint32_t>(info[0]).FromJust());
murgatroid996fe015e2015-10-12 13:18:06 -0700771 if (code == GRPC_STATUS_OK) {
772 return Nan::ThrowRangeError(
773 "cancelWithStatus cannot be called with OK status");
774 }
775 Utf8String details(info[1]);
murgatroid997d58aba2015-08-27 16:11:08 -0700776 grpc_call_cancel_with_status(call->wrapped_call, code, *details, NULL);
murgatroid997d58aba2015-08-27 16:11:08 -0700777}
778
murgatroid99ea12b972015-07-24 10:43:27 -0700779NAN_METHOD(Call::GetPeer) {
murgatroid992b097832015-09-17 13:56:25 -0700780 Nan::HandleScope scope;
781 if (!HasInstance(info.This())) {
782 return Nan::ThrowTypeError("getPeer can only be called on Call objects");
murgatroid99ea12b972015-07-24 10:43:27 -0700783 }
murgatroid992b097832015-09-17 13:56:25 -0700784 Call *call = ObjectWrap::Unwrap<Call>(info.This());
murgatroid99ea12b972015-07-24 10:43:27 -0700785 char *peer = grpc_call_get_peer(call->wrapped_call);
murgatroid992b097832015-09-17 13:56:25 -0700786 Local<Value> peer_value = Nan::New(peer).ToLocalChecked();
murgatroid99ea12b972015-07-24 10:43:27 -0700787 gpr_free(peer);
murgatroid992b097832015-09-17 13:56:25 -0700788 info.GetReturnValue().Set(peer_value);
murgatroid99ea12b972015-07-24 10:43:27 -0700789}
790
murgatroid99153b09d2015-09-25 16:04:03 -0700791NAN_METHOD(Call::SetCredentials) {
792 Nan::HandleScope scope;
murgatroid999c43b002015-09-28 16:31:16 -0700793 if (!HasInstance(info.This())) {
794 return Nan::ThrowTypeError(
795 "setCredentials can only be called on Call objects");
796 }
murgatroid995f709ca2015-09-30 14:22:54 -0700797 if (!CallCredentials::HasInstance(info[0])) {
murgatroid99153b09d2015-09-25 16:04:03 -0700798 return Nan::ThrowTypeError(
murgatroid995f709ca2015-09-30 14:22:54 -0700799 "setCredentials' first argument must be a CallCredentials");
murgatroid99153b09d2015-09-25 16:04:03 -0700800 }
801 Call *call = ObjectWrap::Unwrap<Call>(info.This());
murgatroid995f709ca2015-09-30 14:22:54 -0700802 CallCredentials *creds_object = ObjectWrap::Unwrap<CallCredentials>(
murgatroid999c43b002015-09-28 16:31:16 -0700803 Nan::To<Object>(info[0]).ToLocalChecked());
murgatroid997c0dbf82015-10-20 16:10:20 -0700804 grpc_call_credentials *creds = creds_object->GetWrappedCredentials();
murgatroid99153b09d2015-09-25 16:04:03 -0700805 grpc_call_error error = GRPC_CALL_ERROR;
806 if (creds) {
807 error = grpc_call_set_credentials(call->wrapped_call, creds);
808 }
809 info.GetReturnValue().Set(Nan::New<Uint32>(error));
810}
811
murgatroid99e5061512015-01-12 18:14:35 -0800812} // namespace node
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800813} // namespace grpc