murgatroid99 | 749666e | 2015-01-12 18:25:58 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Craig Tiller | 0605995 | 2015-02-18 08:34:56 -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> |
| 35 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 36 | #include "server.h" |
| 37 | |
| 38 | #include <node.h> |
| 39 | #include <nan.h> |
| 40 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 41 | #include <vector> |
| 42 | #include "grpc/grpc.h" |
| 43 | #include "grpc/grpc_security.h" |
murgatroid99 | 7765906 | 2015-02-11 09:26:25 -0800 | [diff] [blame] | 44 | #include "grpc/support/log.h" |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 45 | #include "call.h" |
| 46 | #include "completion_queue_async_worker.h" |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 47 | #include "server_credentials.h" |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 48 | #include "timeval.h" |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 49 | |
| 50 | namespace grpc { |
| 51 | namespace node { |
| 52 | |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 53 | using std::unique_ptr; |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 54 | using v8::Array; |
| 55 | using v8::Boolean; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 56 | using v8::Date; |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 57 | using v8::Exception; |
| 58 | using v8::Function; |
| 59 | using v8::FunctionTemplate; |
| 60 | using v8::Handle; |
| 61 | using v8::HandleScope; |
| 62 | using v8::Local; |
| 63 | using v8::Number; |
| 64 | using v8::Object; |
| 65 | using v8::Persistent; |
| 66 | using v8::String; |
| 67 | using v8::Value; |
| 68 | |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 69 | NanCallback *Server::constructor; |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 70 | Persistent<FunctionTemplate> Server::fun_tpl; |
| 71 | |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 72 | class NewCallOp : public Op { |
| 73 | public: |
| 74 | NewCallOp() { |
| 75 | call = NULL; |
| 76 | grpc_call_details_init(&details); |
| 77 | grpc_metadata_array_init(&request_metadata); |
| 78 | } |
| 79 | |
| 80 | ~NewCallOp() { |
| 81 | grpc_call_details_destroy(&details); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 82 | grpc_metadata_array_destroy(&request_metadata); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | Handle<Value> GetNodeValue() const { |
| 86 | NanEscapableScope(); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 87 | if (call == NULL) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 88 | return NanEscapeScope(NanNull()); |
| 89 | } |
| 90 | Handle<Object> obj = NanNew<Object>(); |
| 91 | obj->Set(NanNew("call"), Call::WrapStruct(call)); |
| 92 | obj->Set(NanNew("method"), NanNew(details.method)); |
| 93 | obj->Set(NanNew("host"), NanNew(details.host)); |
| 94 | obj->Set(NanNew("deadline"), |
| 95 | NanNew<Date>(TimespecToMilliseconds(details.deadline))); |
| 96 | obj->Set(NanNew("metadata"), ParseMetadata(&request_metadata)); |
| 97 | return NanEscapeScope(obj); |
| 98 | } |
| 99 | |
| 100 | bool ParseOp(Handle<Value> value, grpc_op *out, |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 101 | shared_ptr<Resources> resources) { |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 102 | return true; |
| 103 | } |
| 104 | |
| 105 | grpc_call *call; |
| 106 | grpc_call_details details; |
| 107 | grpc_metadata_array request_metadata; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 108 | |
| 109 | protected: |
| 110 | std::string GetTypeString() const { |
murgatroid99 | a627d89 | 2015-07-23 10:40:19 -0700 | [diff] [blame] | 111 | return "new_call"; |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 112 | } |
| 113 | }; |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 114 | |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 115 | Server::Server(grpc_server *server) : wrapped_server(server) { |
| 116 | shutdown_queue = grpc_completion_queue_create(); |
| 117 | grpc_server_register_completion_queue(server, shutdown_queue); |
| 118 | } |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 119 | |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 120 | Server::~Server() { |
| 121 | this->ShutdownServer(); |
| 122 | grpc_completion_queue_shutdown(this->shutdown_queue); |
| 123 | grpc_server_destroy(wrapped_server); |
| 124 | grpc_completion_queue_destroy(this->shutdown_queue); |
| 125 | } |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 126 | |
| 127 | void Server::Init(Handle<Object> exports) { |
| 128 | NanScope(); |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 129 | Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New); |
| 130 | tpl->SetClassName(NanNew("Server")); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 131 | tpl->InstanceTemplate()->SetInternalFieldCount(1); |
| 132 | NanSetPrototypeTemplate(tpl, "requestCall", |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 133 | NanNew<FunctionTemplate>(RequestCall)->GetFunction()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 134 | |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 135 | NanSetPrototypeTemplate( |
| 136 | tpl, "addHttp2Port", |
| 137 | NanNew<FunctionTemplate>(AddHttp2Port)->GetFunction()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 138 | |
Craig Tiller | e8e304e | 2015-01-13 14:41:29 -0800 | [diff] [blame] | 139 | NanSetPrototypeTemplate( |
| 140 | tpl, "addSecureHttp2Port", |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 141 | NanNew<FunctionTemplate>(AddSecureHttp2Port)->GetFunction()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 142 | |
| 143 | NanSetPrototypeTemplate(tpl, "start", |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 144 | NanNew<FunctionTemplate>(Start)->GetFunction()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 145 | |
| 146 | NanSetPrototypeTemplate(tpl, "shutdown", |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 147 | NanNew<FunctionTemplate>(Shutdown)->GetFunction()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 148 | |
| 149 | NanAssignPersistent(fun_tpl, tpl); |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 150 | Handle<Function> ctr = tpl->GetFunction(); |
| 151 | constructor = new NanCallback(ctr); |
| 152 | exports->Set(NanNew("Server"), ctr); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | bool Server::HasInstance(Handle<Value> val) { |
| 156 | return NanHasInstance(fun_tpl, val); |
| 157 | } |
| 158 | |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 159 | void Server::ShutdownServer() { |
| 160 | if (this->wrapped_server != NULL) { |
| 161 | grpc_server_shutdown_and_notify(this->wrapped_server, |
| 162 | this->shutdown_queue, |
| 163 | NULL); |
Craig Tiller | 354398f | 2015-07-13 09:16:03 -0700 | [diff] [blame] | 164 | grpc_completion_queue_pluck(this->shutdown_queue, NULL, |
| 165 | gpr_inf_future(GPR_CLOCK_REALTIME)); |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 166 | this->wrapped_server = NULL; |
| 167 | } |
| 168 | } |
| 169 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 170 | NAN_METHOD(Server::New) { |
| 171 | NanScope(); |
| 172 | |
| 173 | /* If this is not a constructor call, make a constructor call and return |
| 174 | the result */ |
| 175 | if (!args.IsConstructCall()) { |
| 176 | const int argc = 1; |
Craig Tiller | e8e304e | 2015-01-13 14:41:29 -0800 | [diff] [blame] | 177 | Local<Value> argv[argc] = {args[0]}; |
murgatroid99 | f28066b | 2015-03-04 14:42:31 -0800 | [diff] [blame] | 178 | NanReturnValue(constructor->GetFunction()->NewInstance(argc, argv)); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 179 | } |
| 180 | grpc_server *wrapped_server; |
| 181 | grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue(); |
| 182 | if (args[0]->IsUndefined()) { |
Craig Tiller | f508145 | 2015-05-06 12:42:47 -0700 | [diff] [blame] | 183 | wrapped_server = grpc_server_create(NULL); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 184 | } else if (args[0]->IsObject()) { |
murgatroid99 | da02a67 | 2015-03-02 17:28:02 -0800 | [diff] [blame] | 185 | Handle<Object> args_hash(args[0]->ToObject()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 186 | Handle<Array> keys(args_hash->GetOwnPropertyNames()); |
| 187 | grpc_channel_args channel_args; |
| 188 | channel_args.num_args = keys->Length(); |
Craig Tiller | e8e304e | 2015-01-13 14:41:29 -0800 | [diff] [blame] | 189 | channel_args.args = reinterpret_cast<grpc_arg *>( |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 190 | calloc(channel_args.num_args, sizeof(grpc_arg))); |
| 191 | /* These are used to keep all strings until then end of the block, then |
| 192 | destroy them */ |
Craig Tiller | e8e304e | 2015-01-13 14:41:29 -0800 | [diff] [blame] | 193 | std::vector<NanUtf8String *> key_strings(keys->Length()); |
| 194 | std::vector<NanUtf8String *> value_strings(keys->Length()); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 195 | for (unsigned int i = 0; i < channel_args.num_args; i++) { |
| 196 | Handle<String> current_key(keys->Get(i)->ToString()); |
| 197 | Handle<Value> current_value(args_hash->Get(current_key)); |
| 198 | key_strings[i] = new NanUtf8String(current_key); |
| 199 | channel_args.args[i].key = **key_strings[i]; |
| 200 | if (current_value->IsInt32()) { |
| 201 | channel_args.args[i].type = GRPC_ARG_INTEGER; |
| 202 | channel_args.args[i].value.integer = current_value->Int32Value(); |
| 203 | } else if (current_value->IsString()) { |
| 204 | channel_args.args[i].type = GRPC_ARG_STRING; |
| 205 | value_strings[i] = new NanUtf8String(current_value); |
| 206 | channel_args.args[i].value.string = **value_strings[i]; |
| 207 | } else { |
| 208 | free(channel_args.args); |
| 209 | return NanThrowTypeError("Arg values must be strings"); |
| 210 | } |
| 211 | } |
Craig Tiller | f508145 | 2015-05-06 12:42:47 -0700 | [diff] [blame] | 212 | wrapped_server = grpc_server_create(&channel_args); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 213 | free(channel_args.args); |
| 214 | } else { |
| 215 | return NanThrowTypeError("Server expects an object"); |
| 216 | } |
Craig Tiller | f508145 | 2015-05-06 12:42:47 -0700 | [diff] [blame] | 217 | grpc_server_register_completion_queue(wrapped_server, queue); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 218 | Server *server = new Server(wrapped_server); |
| 219 | server->Wrap(args.This()); |
| 220 | NanReturnValue(args.This()); |
| 221 | } |
| 222 | |
| 223 | NAN_METHOD(Server::RequestCall) { |
| 224 | NanScope(); |
| 225 | if (!HasInstance(args.This())) { |
| 226 | return NanThrowTypeError("requestCall can only be called on a Server"); |
| 227 | } |
| 228 | Server *server = ObjectWrap::Unwrap<Server>(args.This()); |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 229 | if (server->wrapped_server == NULL) { |
| 230 | return NanThrowError("requestCall cannot be called on a shut down Server"); |
| 231 | } |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 232 | NewCallOp *op = new NewCallOp(); |
murgatroid99 | d3f9f9f | 2015-02-13 12:21:59 -0800 | [diff] [blame] | 233 | unique_ptr<OpVec> ops(new OpVec()); |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 234 | ops->push_back(unique_ptr<Op>(op)); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 235 | grpc_call_error error = grpc_server_request_call( |
murgatroid99 | 016bb50 | 2015-02-09 15:55:10 -0800 | [diff] [blame] | 236 | server->wrapped_server, &op->call, &op->details, &op->request_metadata, |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 237 | CompletionQueueAsyncWorker::GetQueue(), |
Craig Tiller | f508145 | 2015-05-06 12:42:47 -0700 | [diff] [blame] | 238 | CompletionQueueAsyncWorker::GetQueue(), |
murgatroid99 | d3f9f9f | 2015-02-13 12:21:59 -0800 | [diff] [blame] | 239 | new struct tag(new NanCallback(args[0].As<Function>()), ops.release(), |
murgatroid99 | 17be589 | 2015-02-13 10:19:10 -0800 | [diff] [blame] | 240 | shared_ptr<Resources>(nullptr))); |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 241 | if (error != GRPC_CALL_OK) { |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 242 | return NanThrowError("requestCall failed", error); |
| 243 | } |
murgatroid99 | d4d67ad | 2015-02-09 10:43:21 -0800 | [diff] [blame] | 244 | CompletionQueueAsyncWorker::Next(); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 245 | NanReturnUndefined(); |
| 246 | } |
| 247 | |
| 248 | NAN_METHOD(Server::AddHttp2Port) { |
| 249 | NanScope(); |
| 250 | if (!HasInstance(args.This())) { |
| 251 | return NanThrowTypeError("addHttp2Port can only be called on a Server"); |
| 252 | } |
| 253 | if (!args[0]->IsString()) { |
| 254 | return NanThrowTypeError("addHttp2Port's argument must be a String"); |
| 255 | } |
| 256 | Server *server = ObjectWrap::Unwrap<Server>(args.This()); |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 257 | if (server->wrapped_server == NULL) { |
| 258 | return NanThrowError("addHttp2Port cannot be called on a shut down Server"); |
| 259 | } |
murgatroid99 | d2f20b2 | 2015-01-21 11:55:39 -0800 | [diff] [blame] | 260 | NanReturnValue(NanNew<Number>(grpc_server_add_http2_port( |
Craig Tiller | e8e304e | 2015-01-13 14:41:29 -0800 | [diff] [blame] | 261 | server->wrapped_server, *NanUtf8String(args[0])))); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 262 | } |
| 263 | |
| 264 | NAN_METHOD(Server::AddSecureHttp2Port) { |
| 265 | NanScope(); |
| 266 | if (!HasInstance(args.This())) { |
| 267 | return NanThrowTypeError( |
| 268 | "addSecureHttp2Port can only be called on a Server"); |
| 269 | } |
| 270 | if (!args[0]->IsString()) { |
murgatroid99 | da02a67 | 2015-03-02 17:28:02 -0800 | [diff] [blame] | 271 | return NanThrowTypeError( |
| 272 | "addSecureHttp2Port's first argument must be a String"); |
| 273 | } |
| 274 | if (!ServerCredentials::HasInstance(args[1])) { |
| 275 | return NanThrowTypeError( |
| 276 | "addSecureHttp2Port's second argument must be ServerCredentials"); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 277 | } |
| 278 | Server *server = ObjectWrap::Unwrap<Server>(args.This()); |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 279 | if (server->wrapped_server == NULL) { |
| 280 | return NanThrowError( |
| 281 | "addSecureHttp2Port cannot be called on a shut down Server"); |
| 282 | } |
murgatroid99 | da02a67 | 2015-03-02 17:28:02 -0800 | [diff] [blame] | 283 | ServerCredentials *creds = ObjectWrap::Unwrap<ServerCredentials>( |
| 284 | args[1]->ToObject()); |
murgatroid99 | d2f20b2 | 2015-01-21 11:55:39 -0800 | [diff] [blame] | 285 | NanReturnValue(NanNew<Number>(grpc_server_add_secure_http2_port( |
murgatroid99 | da02a67 | 2015-03-02 17:28:02 -0800 | [diff] [blame] | 286 | server->wrapped_server, *NanUtf8String(args[0]), |
| 287 | creds->GetWrappedServerCredentials()))); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 288 | } |
| 289 | |
| 290 | NAN_METHOD(Server::Start) { |
| 291 | NanScope(); |
| 292 | if (!HasInstance(args.This())) { |
| 293 | return NanThrowTypeError("start can only be called on a Server"); |
| 294 | } |
| 295 | Server *server = ObjectWrap::Unwrap<Server>(args.This()); |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 296 | if (server->wrapped_server == NULL) { |
| 297 | return NanThrowError("start cannot be called on a shut down Server"); |
| 298 | } |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 299 | grpc_server_start(server->wrapped_server); |
| 300 | NanReturnUndefined(); |
| 301 | } |
| 302 | |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 303 | NAN_METHOD(ShutdownCallback) { |
| 304 | NanReturnUndefined(); |
| 305 | } |
| 306 | |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 307 | NAN_METHOD(Server::Shutdown) { |
| 308 | NanScope(); |
| 309 | if (!HasInstance(args.This())) { |
| 310 | return NanThrowTypeError("shutdown can only be called on a Server"); |
| 311 | } |
| 312 | Server *server = ObjectWrap::Unwrap<Server>(args.This()); |
murgatroid99 | cd35c4c | 2015-05-28 13:39:25 -0700 | [diff] [blame] | 313 | server->ShutdownServer(); |
murgatroid99 | e506151 | 2015-01-12 18:14:35 -0800 | [diff] [blame] | 314 | NanReturnUndefined(); |
| 315 | } |
| 316 | |
| 317 | } // namespace node |
Craig Tiller | 190d360 | 2015-02-18 09:23:38 -0800 | [diff] [blame] | 318 | } // namespace grpc |