murgatroid99 | 749666e | 2015-01-12 18:25:58 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 3 | * Copyright 2015, Google Inc. |
murgatroid99 | 749666e | 2015-01-12 18:25:58 -0800 | [diff] [blame] | 4 | * 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 | |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 34 | #include <memory> |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 35 | #include <vector> |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 36 | #include <map> |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 37 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 38 | #include <node.h> |
| 39 | |
murgatroid99 | 7625db4 | 2015-01-28 15:36:27 -0800 | [diff] [blame] | 40 | #include "grpc/support/log.h" |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 41 | #include "grpc/grpc.h" |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 42 | #include "grpc/support/alloc.h" |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 43 | #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" |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 49 | |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 50 | using std::unique_ptr; |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 51 | using std::shared_ptr; |
murgatroid99 | e012366 | 2015-02-13 11:14:03 -0800 | [diff] [blame] | 52 | using std::vector; |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 53 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 54 | namespace grpc { |
| 55 | namespace node { |
| 56 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 57 | using v8::Array; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 58 | using v8::Boolean; |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 59 | using v8::Exception; |
| 60 | using v8::External; |
| 61 | using v8::Function; |
| 62 | using v8::FunctionTemplate; |
| 63 | using v8::Handle; |
| 64 | using v8::HandleScope; |
| 65 | using v8::Integer; |
| 66 | using v8::Local; |
| 67 | using v8::Number; |
| 68 | using v8::Object; |
| 69 | using v8::ObjectTemplate; |
| 70 | using v8::Persistent; |
| 71 | using v8::Uint32; |
| 72 | using v8::String; |
| 73 | using v8::Value; |
| 74 | |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 75 | NanCallback *Call::constructor; |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 76 | Persistent<FunctionTemplate> Call::fun_tpl; |
| 77 | |
murgatroid99 | da77151 | 2015-03-17 18:13:55 -0700 | [diff] [blame] | 78 | bool EndsWith(const char *str, const char *substr) { |
| 79 | return strcmp(str+strlen(str)-strlen(substr), substr) == 0; |
| 80 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 81 | |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 82 | bool CreateMetadataArray(Handle<Object> metadata, grpc_metadata_array *array, |
| 83 | shared_ptr<Resources> resources) { |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 84 | NanScope(); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 85 | grpc_metadata_array_init(array); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 86 | 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 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 94 | array->metadata = reinterpret_cast<grpc_metadata*>( |
| 95 | gpr_malloc(array->capacity * sizeof(grpc_metadata))); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 96 | 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); |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 99 | resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_key)); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 100 | 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); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 103 | grpc_metadata *current = &array->metadata[array->count]; |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 104 | current->key = **utf8_key; |
murgatroid99 | da77151 | 2015-03-17 18:13:55 -0700 | [diff] [blame] | 105 | // 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()) { |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 118 | Handle<String> string_value = value->ToString(); |
| 119 | NanUtf8String *utf8_value = new NanUtf8String(string_value); |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 120 | resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_value)); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 121 | 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 | |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 132 | Handle<Value> ParseMetadata(const grpc_metadata_array *metadata_array) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 133 | NanEscapableScope(); |
| 134 | grpc_metadata *metadata_elements = metadata_array->metadata; |
| 135 | size_t length = metadata_array->count; |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 136 | std::map<const char*, size_t> size_map; |
| 137 | std::map<const char*, size_t> index_map; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 138 | |
| 139 | for (unsigned int i = 0; i < length; i++) { |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 140 | const char *key = metadata_elements[i].key; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 141 | 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]; |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 149 | Handle<String> key_string = NanNew(elem->key); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 150 | 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 | } |
murgatroid99 | da77151 | 2015-03-17 18:13:55 -0700 | [diff] [blame] | 157 | 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 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 164 | index_map[elem->key] += 1; |
| 165 | } |
| 166 | return NanEscapeScope(metadata_object); |
| 167 | } |
| 168 | |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 169 | Handle<Value> Op::GetOpType() const { |
| 170 | NanEscapableScope(); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 171 | return NanEscapeScope(NanNew<String>(GetTypeString())); |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 172 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 173 | |
| 174 | class SendMetadataOp : public Op { |
| 175 | public: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 176 | Handle<Value> GetNodeValue() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 177 | NanEscapableScope(); |
| 178 | return NanEscapeScope(NanTrue()); |
| 179 | } |
| 180 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 181 | shared_ptr<Resources> resources) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 182 | if (!value->IsObject()) { |
| 183 | return false; |
| 184 | } |
| 185 | grpc_metadata_array array; |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 186 | if (!CreateMetadataArray(value->ToObject(), &array, resources)) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 187 | 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: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 194 | std::string GetTypeString() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 195 | return "send metadata"; |
| 196 | } |
| 197 | }; |
| 198 | |
| 199 | class SendMessageOp : public Op { |
| 200 | public: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 201 | Handle<Value> GetNodeValue() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 202 | NanEscapableScope(); |
| 203 | return NanEscapeScope(NanTrue()); |
| 204 | } |
| 205 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 206 | shared_ptr<Resources> resources) { |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 207 | if (!::node::Buffer::HasInstance(value)) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 208 | return false; |
| 209 | } |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 210 | out->data.send_message = BufferToByteBuffer(value); |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 211 | Persistent<Value> *handle = new Persistent<Value>(); |
| 212 | NanAssignPersistent(*handle, value); |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 213 | resources->handles.push_back(unique_ptr<PersistentHolder>( |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 214 | new PersistentHolder(handle))); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 215 | return true; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 216 | } |
| 217 | protected: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 218 | std::string GetTypeString() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 219 | return "send message"; |
| 220 | } |
| 221 | }; |
| 222 | |
| 223 | class SendClientCloseOp : public Op { |
| 224 | public: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 225 | Handle<Value> GetNodeValue() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 226 | NanEscapableScope(); |
| 227 | return NanEscapeScope(NanTrue()); |
| 228 | } |
| 229 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 230 | shared_ptr<Resources> resources) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 231 | return true; |
| 232 | } |
| 233 | protected: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 234 | std::string GetTypeString() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 235 | return "client close"; |
| 236 | } |
| 237 | }; |
| 238 | |
| 239 | class SendServerStatusOp : public Op { |
| 240 | public: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 241 | Handle<Value> GetNodeValue() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 242 | NanEscapableScope(); |
| 243 | return NanEscapeScope(NanTrue()); |
| 244 | } |
| 245 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 246 | shared_ptr<Resources> resources) { |
murgatroid99 | cd0b906 | 2015-02-10 09:16:49 -0800 | [diff] [blame] | 247 | if (!value->IsObject()) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 248 | 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(), |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 263 | &array, resources)) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 264 | 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"))); |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 273 | resources->strings.push_back(unique_ptr<NanUtf8String>(str)); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 274 | out->data.send_status_from_server.status_details = **str; |
| 275 | return true; |
| 276 | } |
| 277 | protected: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 278 | std::string GetTypeString() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 279 | return "send status"; |
| 280 | } |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 281 | }; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 282 | |
| 283 | class 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, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 299 | shared_ptr<Resources> resources) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 300 | out->data.recv_initial_metadata = &recv_metadata; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 301 | return true; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 302 | } |
| 303 | |
| 304 | protected: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 305 | std::string GetTypeString() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 306 | return "metadata"; |
| 307 | } |
| 308 | |
| 309 | private: |
| 310 | grpc_metadata_array recv_metadata; |
| 311 | }; |
| 312 | |
| 313 | class 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(); |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 325 | return NanEscapeScope(ByteBufferToBuffer(recv_message)); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 326 | } |
| 327 | |
| 328 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 329 | shared_ptr<Resources> resources) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 330 | out->data.recv_message = &recv_message; |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 331 | return true; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | protected: |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 335 | std::string GetTypeString() const { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 336 | return "read"; |
| 337 | } |
| 338 | |
| 339 | private: |
| 340 | grpc_byte_buffer *recv_message; |
| 341 | }; |
| 342 | |
| 343 | class ClientStatusOp : public Op { |
| 344 | public: |
| 345 | ClientStatusOp() { |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 346 | grpc_metadata_array_init(&metadata_array); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 347 | status_details = NULL; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 348 | details_capacity = 0; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 349 | } |
| 350 | |
| 351 | ~ClientStatusOp() { |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 352 | grpc_metadata_array_destroy(&metadata_array); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 353 | gpr_free(status_details); |
| 354 | } |
| 355 | |
| 356 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 357 | shared_ptr<Resources> resources) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 358 | 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; |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 362 | return true; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | Handle<Value> GetNodeValue() const { |
| 366 | NanEscapableScope(); |
| 367 | Handle<Object> status_obj = NanNew<Object>(); |
| 368 | status_obj->Set(NanNew("code"), NanNew<Number>(status)); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 369 | if (status_details != NULL) { |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 370 | status_obj->Set(NanNew("details"), NanNew(status_details)); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 371 | } |
| 372 | status_obj->Set(NanNew("metadata"), ParseMetadata(&metadata_array)); |
| 373 | return NanEscapeScope(status_obj); |
| 374 | } |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 375 | protected: |
| 376 | std::string GetTypeString() const { |
| 377 | return "status"; |
| 378 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 379 | private: |
| 380 | grpc_metadata_array metadata_array; |
| 381 | grpc_status_code status; |
| 382 | char *status_details; |
| 383 | size_t details_capacity; |
| 384 | }; |
| 385 | |
| 386 | class ServerCloseResponseOp : public Op { |
| 387 | public: |
| 388 | Handle<Value> GetNodeValue() const { |
| 389 | NanEscapableScope(); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 390 | return NanEscapeScope(NanNew<Boolean>(cancelled)); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 391 | } |
| 392 | |
| 393 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 394 | shared_ptr<Resources> resources) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 395 | out->data.recv_close_on_server.cancelled = &cancelled; |
murgatroid99 | ff43c09 | 2015-02-09 11:41:23 -0800 | [diff] [blame] | 396 | return true; |
| 397 | } |
| 398 | |
| 399 | protected: |
| 400 | std::string GetTypeString() const { |
| 401 | return "cancelled"; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | private: |
| 405 | int cancelled; |
| 406 | }; |
| 407 | |
murgatroid99 | e012366 | 2015-02-13 11:14:03 -0800 | [diff] [blame] | 408 | tag::tag(NanCallback *callback, OpVec *ops, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 409 | shared_ptr<Resources> resources) : |
| 410 | callback(callback), ops(ops), resources(resources){ |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 411 | } |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 412 | |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 413 | tag::~tag() { |
| 414 | delete callback; |
| 415 | delete ops; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 416 | } |
| 417 | |
| 418 | Handle<Value> GetTagNodeValue(void *tag) { |
| 419 | NanEscapableScope(); |
| 420 | struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
| 421 | Handle<Object> tag_obj = NanNew<Object>(); |
murgatroid99 | e012366 | 2015-02-13 11:14:03 -0800 | [diff] [blame] | 422 | for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin(); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 423 | 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 | |
murgatroid99 | 1578c6a | 2015-02-11 16:19:55 -0800 | [diff] [blame] | 430 | NanCallback *GetTagCallback(void *tag) { |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 431 | struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
murgatroid99 | 1578c6a | 2015-02-11 16:19:55 -0800 | [diff] [blame] | 432 | return tag_struct->callback; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | void DestroyTag(void *tag) { |
| 436 | struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
| 437 | delete tag_struct; |
| 438 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 439 | |
murgatroid99 | 7765906 | 2015-02-11 09:26:25 -0800 | [diff] [blame] | 440 | Call::Call(grpc_call *call) : wrapped_call(call) { |
murgatroid99 | 7765906 | 2015-02-11 09:26:25 -0800 | [diff] [blame] | 441 | } |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 442 | |
murgatroid99 | 7765906 | 2015-02-11 09:26:25 -0800 | [diff] [blame] | 443 | Call::~Call() { |
murgatroid99 | 7765906 | 2015-02-11 09:26:25 -0800 | [diff] [blame] | 444 | grpc_call_destroy(wrapped_call); |
| 445 | } |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 446 | |
| 447 | void Call::Init(Handle<Object> exports) { |
| 448 | NanScope(); |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 449 | Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 450 | tpl->SetClassName(NanNew("Call")); |
| 451 | tpl->InstanceTemplate()->SetInternalFieldCount(1); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 452 | NanSetPrototypeTemplate(tpl, "startBatch", |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 453 | NanNew<FunctionTemplate>(StartBatch)->GetFunction()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 454 | NanSetPrototypeTemplate(tpl, "cancel", |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 455 | NanNew<FunctionTemplate>(Cancel)->GetFunction()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 456 | NanAssignPersistent(fun_tpl, tpl); |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 457 | 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); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 464 | } |
| 465 | |
| 466 | bool Call::HasInstance(Handle<Value> val) { |
| 467 | NanScope(); |
| 468 | return NanHasInstance(fun_tpl, val); |
| 469 | } |
| 470 | |
| 471 | Handle<Value> Call::WrapStruct(grpc_call *call) { |
| 472 | NanEscapableScope(); |
| 473 | if (call == NULL) { |
| 474 | return NanEscapeScope(NanNull()); |
| 475 | } |
| 476 | const int argc = 1; |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 477 | Handle<Value> argv[argc] = {NanNew<External>(reinterpret_cast<void *>(call))}; |
| 478 | return NanEscapeScope(constructor->GetFunction()->NewInstance(argc, argv)); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 479 | } |
| 480 | |
| 481 | NAN_METHOD(Call::New) { |
| 482 | NanScope(); |
| 483 | |
| 484 | if (args.IsConstructCall()) { |
| 485 | Call *call; |
| 486 | if (args[0]->IsExternal()) { |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 487 | Handle<External> ext = args[0].As<External>(); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 488 | // This option is used for wrapping an existing call |
Craig Tiller | e8e304e | 2015-01-13 14:41:29 -0800 | [diff] [blame] | 489 | grpc_call *call_value = |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 490 | reinterpret_cast<grpc_call *>(ext->Value()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 491 | 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(); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 511 | grpc_call *wrapped_call = grpc_channel_create_call( |
| 512 | wrapped_channel, CompletionQueueAsyncWorker::GetQueue(), *method, |
| 513 | channel->GetHost(), MillisecondsToTimespec(deadline)); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 514 | call = new Call(wrapped_call); |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 515 | args.This()->SetHiddenValue(NanNew("channel_"), channel_object); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 516 | } |
| 517 | call->Wrap(args.This()); |
| 518 | NanReturnValue(args.This()); |
| 519 | } else { |
| 520 | const int argc = 4; |
Craig Tiller | e8e304e | 2015-01-13 14:41:29 -0800 | [diff] [blame] | 521 | Local<Value> argv[argc] = {args[0], args[1], args[2], args[3]}; |
murgatroid99 | 5f875d2 | 2015-03-04 11:28:37 -0800 | [diff] [blame] | 522 | NanReturnValue(constructor->GetFunction()->NewInstance(argc, argv)); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 523 | } |
| 524 | } |
| 525 | |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 526 | NAN_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 | } |
murgatroid99 | 7765906 | 2015-02-11 09:26:25 -0800 | [diff] [blame] | 537 | Handle<Function> callback_func = args[1].As<Function>(); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 538 | Call *call = ObjectWrap::Unwrap<Call>(args.This()); |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 539 | shared_ptr<Resources> resources(new Resources); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 540 | Handle<Object> obj = args[0]->ToObject(); |
| 541 | Handle<Array> keys = obj->GetOwnPropertyNames(); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 542 | size_t nops = keys->Length(); |
murgatroid99 | e012366 | 2015-02-13 11:14:03 -0800 | [diff] [blame] | 543 | vector<grpc_op> ops(nops); |
| 544 | unique_ptr<OpVec> op_vector(new OpVec()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 545 | for (unsigned int i = 0; i < nops; i++) { |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 546 | unique_ptr<Op> op; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 547 | if (!keys->Get(i)->IsUint32()) { |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 548 | return NanThrowError( |
| 549 | "startBatch's first argument's keys must be integers"); |
| 550 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 551 | uint32_t type = keys->Get(i)->Uint32Value(); |
| 552 | ops[i].op = static_cast<grpc_op_type>(type); |
David Garcia Quintas | ba710e5 | 2015-06-15 13:31:15 -0700 | [diff] [blame] | 553 | ops[i].flags = 0; |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 554 | switch (type) { |
| 555 | case GRPC_OP_SEND_INITIAL_METADATA: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 556 | op.reset(new SendMetadataOp()); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 557 | break; |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 558 | case GRPC_OP_SEND_MESSAGE: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 559 | op.reset(new SendMessageOp()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 560 | break; |
| 561 | case GRPC_OP_SEND_CLOSE_FROM_CLIENT: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 562 | op.reset(new SendClientCloseOp()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 563 | break; |
| 564 | case GRPC_OP_SEND_STATUS_FROM_SERVER: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 565 | op.reset(new SendServerStatusOp()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 566 | break; |
| 567 | case GRPC_OP_RECV_INITIAL_METADATA: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 568 | op.reset(new GetMetadataOp()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 569 | break; |
| 570 | case GRPC_OP_RECV_MESSAGE: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 571 | op.reset(new ReadMessageOp()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 572 | break; |
| 573 | case GRPC_OP_RECV_STATUS_ON_CLIENT: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 574 | op.reset(new ClientStatusOp()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 575 | break; |
| 576 | case GRPC_OP_RECV_CLOSE_ON_SERVER: |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 577 | op.reset(new ServerCloseResponseOp()); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 578 | break; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 579 | default: |
| 580 | return NanThrowError("Argument object had an unrecognized key"); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 581 | } |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 582 | if (!op->ParseOp(obj->Get(type), &ops[i], resources)) { |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 583 | return NanThrowTypeError("Incorrectly typed arguments to startBatch"); |
| 584 | } |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 585 | op_vector->push_back(std::move(op)); |
murgatroid99 | a9b99c9 | 2015-02-05 17:42:01 -0800 | [diff] [blame] | 586 | } |
murgatroid99 | 57dfd05 | 2015-02-13 10:41:25 -0800 | [diff] [blame] | 587 | NanCallback *callback = new NanCallback(callback_func); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 588 | grpc_call_error error = grpc_call_start_batch( |
murgatroid99 | d66408b | 2015-02-13 10:40:07 -0800 | [diff] [blame] | 589 | call->wrapped_call, &ops[0], nops, new struct tag( |
murgatroid99 | e012366 | 2015-02-13 11:14:03 -0800 | [diff] [blame] | 590 | callback, op_vector.release(), resources)); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 591 | if (error != GRPC_CALL_OK) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 592 | return NanThrowError("startBatch failed", error); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 593 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 594 | CompletionQueueAsyncWorker::Next(); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 595 | NanReturnUndefined(); |
| 596 | } |
| 597 | |
| 598 | NAN_METHOD(Call::Cancel) { |
| 599 | NanScope(); |
| 600 | if (!HasInstance(args.This())) { |
murgatroid99 | 3548ed8 | 2015-01-15 15:38:45 -0800 | [diff] [blame] | 601 | return NanThrowTypeError("cancel can only be called on Call objects"); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 602 | } |
| 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 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 611 | } // namespace node |
| 612 | } // namespace grpc |