Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / ext / server.cc
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #include <memory>
20
21 #include "server.h"
22
23 #include <nan.h>
24 #include <node.h>
25
26 #include <vector>
27 #include "call.h"
28 #include "completion_queue.h"
29 #include "grpc/grpc.h"
30 #include "grpc/grpc_security.h"
31 #include "grpc/support/log.h"
32 #include "server_credentials.h"
33 #include "slice.h"
34 #include "timeval.h"
35
36 namespace grpc {
37 namespace node {
38
39 using Nan::Callback;
40 using Nan::EscapableHandleScope;
41 using Nan::HandleScope;
42 using Nan::Maybe;
43 using Nan::MaybeLocal;
44 using Nan::ObjectWrap;
45 using Nan::Persistent;
46 using Nan::Utf8String;
47
48 using std::unique_ptr;
49 using v8::Array;
50 using v8::Boolean;
51 using v8::Date;
52 using v8::Exception;
53 using v8::External;
54 using v8::Function;
55 using v8::FunctionTemplate;
56 using v8::Local;
57 using v8::Number;
58 using v8::Object;
59 using v8::String;
60 using v8::Value;
61
62 Nan::Callback *Server::constructor;
63 Persistent<FunctionTemplate> Server::fun_tpl;
64
65 static Persistent<Function> shutdown_cb;
66
67 class ServerShutdownOp : public Op {
68  public:
69   ServerShutdownOp(Server *server) : server(server) {}
70
71   ~ServerShutdownOp() {}
72
73   Local<Value> GetNodeValue() const {
74     EscapableHandleScope scope;
75     return scope.Escape(server->handle());
76   }
77
78   bool ParseOp(Local<Value> value, grpc_op *out) { return true; }
79   bool IsFinalOp() { return false; }
80   void OnComplete(bool success) {
81     if (success) {
82       server->FinishShutdown();
83     }
84   }
85
86   Server *server;
87
88  protected:
89   std::string GetTypeString() const { return "try_shutdown"; }
90 };
91
92 class NewCallOp : public Op {
93  public:
94   NewCallOp() {
95     call = NULL;
96     grpc_call_details_init(&details);
97     grpc_metadata_array_init(&request_metadata);
98   }
99
100   ~NewCallOp() {
101     grpc_call_details_destroy(&details);
102     grpc_metadata_array_destroy(&request_metadata);
103   }
104
105   Local<Value> GetNodeValue() const {
106     Nan::EscapableHandleScope scope;
107     if (call == NULL) {
108       return scope.Escape(Nan::Null());
109     }
110     Local<Object> obj = Nan::New<Object>();
111     Nan::Set(obj, Nan::New("call").ToLocalChecked(), Call::WrapStruct(call));
112     // TODO(murgatroid99): Use zero-copy string construction instead
113     Nan::Set(obj, Nan::New("method").ToLocalChecked(),
114              CopyStringFromSlice(details.method));
115     Nan::Set(obj, Nan::New("host").ToLocalChecked(),
116              CopyStringFromSlice(details.host));
117     Nan::Set(obj, Nan::New("deadline").ToLocalChecked(),
118              Nan::New<Date>(TimespecToMilliseconds(details.deadline))
119                  .ToLocalChecked());
120     Nan::Set(obj, Nan::New("metadata").ToLocalChecked(),
121              ParseMetadata(&request_metadata));
122     return scope.Escape(obj);
123   }
124
125   bool ParseOp(Local<Value> value, grpc_op *out) { return true; }
126   bool IsFinalOp() { return false; }
127   void OnComplete(bool success) {}
128
129   grpc_call *call;
130   grpc_call_details details;
131   grpc_metadata_array request_metadata;
132
133  protected:
134   std::string GetTypeString() const { return "new_call"; }
135 };
136
137 NAN_METHOD(ShutdownCallback) {
138   HandleScope scope;
139   if (!info[0]->IsNull()) {
140     return Nan::ThrowError("forceShutdown failed somehow");
141   }
142 }
143
144 Server::Server(grpc_server *server) :
145     wrapped_server(server), is_shutdown(false) {}
146
147 Server::~Server() { grpc_server_destroy(this->wrapped_server); }
148
149 void Server::Init(Local<Object> exports) {
150   HandleScope scope;
151   Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
152   tpl->SetClassName(Nan::New("Server").ToLocalChecked());
153   tpl->InstanceTemplate()->SetInternalFieldCount(1);
154   Nan::SetPrototypeMethod(tpl, "requestCall", RequestCall);
155   Nan::SetPrototypeMethod(tpl, "addHttp2Port", AddHttp2Port);
156   Nan::SetPrototypeMethod(tpl, "start", Start);
157   Nan::SetPrototypeMethod(tpl, "tryShutdown", TryShutdown);
158   Nan::SetPrototypeMethod(tpl, "forceShutdown", ForceShutdown);
159   fun_tpl.Reset(tpl);
160   Local<Function> ctr = Nan::GetFunction(tpl).ToLocalChecked();
161   Nan::Set(exports, Nan::New("Server").ToLocalChecked(), ctr);
162   constructor = new Callback(ctr);
163   Local<FunctionTemplate> shutdown_tpl =
164       Nan::New<FunctionTemplate>(ShutdownCallback);
165   shutdown_cb.Reset(Nan::GetFunction(shutdown_tpl).ToLocalChecked());
166 }
167
168 bool Server::HasInstance(Local<Value> val) {
169   HandleScope scope;
170   return Nan::New(fun_tpl)->HasInstance(val);
171 }
172
173 void Server::FinishShutdown() {
174   is_shutdown = true;
175   running_self_ref.Reset();
176 }
177
178 void Server::ShutdownServer() {
179   Nan::HandleScope scope;
180   if (!this->is_shutdown) {
181     Callback *shutdown_callback =
182         new Callback(Nan::New(shutdown_cb));
183     ServerShutdownOp *op = new ServerShutdownOp(this);
184     unique_ptr<OpVec> ops(new OpVec());
185     ops->push_back(unique_ptr<Op>(op));
186
187     grpc_server_shutdown_and_notify(
188         this->wrapped_server, GetCompletionQueue(),
189         new struct tag(shutdown_callback, ops.release(), NULL, Nan::Null()));
190     grpc_server_cancel_all_calls(this->wrapped_server);
191     CompletionQueueNext();
192   }
193 }
194
195 NAN_METHOD(Server::New) {
196   /* If this is not a constructor call, make a constructor call and return
197      the result */
198   if (!info.IsConstructCall()) {
199     const int argc = 1;
200     Local<Value> argv[argc] = {info[0]};
201     MaybeLocal<Object> maybe_instance =
202         Nan::NewInstance(constructor->GetFunction(), argc, argv);
203     if (maybe_instance.IsEmpty()) {
204       // There's probably a pending exception
205       return;
206     } else {
207       info.GetReturnValue().Set(maybe_instance.ToLocalChecked());
208       return;
209     }
210   }
211   grpc_server *wrapped_server;
212   grpc_completion_queue *queue = GetCompletionQueue();
213   grpc_channel_args *channel_args;
214   if (!ParseChannelArgs(info[0], &channel_args)) {
215     DeallocateChannelArgs(channel_args);
216     return Nan::ThrowTypeError(
217         "Server options must be an object with "
218         "string keys and integer or string values");
219   }
220   wrapped_server = grpc_server_create(channel_args, NULL);
221   DeallocateChannelArgs(channel_args);
222   grpc_server_register_completion_queue(wrapped_server, queue, NULL);
223   Server *server = new Server(wrapped_server);
224   server->Wrap(info.This());
225   info.GetReturnValue().Set(info.This());
226 }
227
228 NAN_METHOD(Server::RequestCall) {
229   if (!HasInstance(info.This())) {
230     return Nan::ThrowTypeError("requestCall can only be called on a Server");
231   }
232   Server *server = ObjectWrap::Unwrap<Server>(info.This());
233   NewCallOp *op = new NewCallOp();
234   unique_ptr<OpVec> ops(new OpVec());
235   ops->push_back(unique_ptr<Op>(op));
236   grpc_call_error error = grpc_server_request_call(
237       server->wrapped_server, &op->call, &op->details, &op->request_metadata,
238       GetCompletionQueue(), GetCompletionQueue(),
239       new struct tag(new Callback(info[0].As<Function>()), ops.release(), NULL,
240                      Nan::Null()));
241   if (error != GRPC_CALL_OK) {
242     return Nan::ThrowError(nanErrorWithCode("requestCall failed", error));
243   }
244   CompletionQueueNext();
245 }
246
247 NAN_METHOD(Server::AddHttp2Port) {
248   if (!HasInstance(info.This())) {
249     return Nan::ThrowTypeError("addHttp2Port can only be called on a Server");
250   }
251   if (!info[0]->IsString()) {
252     return Nan::ThrowTypeError(
253         "addHttp2Port's first argument must be a String");
254   }
255   if (!ServerCredentials::HasInstance(info[1])) {
256     return Nan::ThrowTypeError(
257         "addHttp2Port's second argument must be ServerCredentials");
258   }
259   Server *server = ObjectWrap::Unwrap<Server>(info.This());
260   ServerCredentials *creds_object = ObjectWrap::Unwrap<ServerCredentials>(
261       Nan::To<Object>(info[1]).ToLocalChecked());
262   grpc_server_credentials *creds = creds_object->GetWrappedServerCredentials();
263   int port;
264   if (creds == NULL) {
265     port = grpc_server_add_insecure_http2_port(server->wrapped_server,
266                                                *Utf8String(info[0]));
267   } else {
268     port = grpc_server_add_secure_http2_port(server->wrapped_server,
269                                              *Utf8String(info[0]), creds);
270   }
271   info.GetReturnValue().Set(Nan::New<Number>(port));
272 }
273
274 NAN_METHOD(Server::Start) {
275   Nan::HandleScope scope;
276   if (!HasInstance(info.This())) {
277     return Nan::ThrowTypeError("start can only be called on a Server");
278   }
279   Server *server = ObjectWrap::Unwrap<Server>(info.This());
280   server->running_self_ref.Reset(info.This());
281   grpc_server_start(server->wrapped_server);
282 }
283
284 NAN_METHOD(Server::TryShutdown) {
285   Nan::HandleScope scope;
286   if (!HasInstance(info.This())) {
287     return Nan::ThrowTypeError("tryShutdown can only be called on a Server");
288   }
289   if (!info[0]->IsFunction()) {
290     return Nan::ThrowError("tryShutdown's argument must be a callback");
291   }
292   Server *server = ObjectWrap::Unwrap<Server>(info.This());
293   ServerShutdownOp *op = new ServerShutdownOp(server);
294   unique_ptr<OpVec> ops(new OpVec());
295   ops->push_back(unique_ptr<Op>(op));
296   grpc_server_shutdown_and_notify(
297       server->wrapped_server, GetCompletionQueue(),
298       new struct tag(new Nan::Callback(info[0].As<Function>()), ops.release(),
299                      NULL, Nan::Null()));
300   CompletionQueueNext();
301 }
302
303 NAN_METHOD(Server::ForceShutdown) {
304   Nan::HandleScope scope;
305   if (!HasInstance(info.This())) {
306     return Nan::ThrowTypeError("forceShutdown can only be called on a Server");
307   }
308   Server *server = ObjectWrap::Unwrap<Server>(info.This());
309   server->ShutdownServer();
310 }
311
312 }  // namespace node
313 }  // namespace grpc