src_server.js.html 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: src/server.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: src/server.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>/*
  20. *
  21. * Copyright 2015, Google Inc.
  22. * All rights reserved.
  23. *
  24. * Redistribution and use in source and binary forms, with or without
  25. * modification, are permitted provided that the following conditions are
  26. * met:
  27. *
  28. * * Redistributions of source code must retain the above copyright
  29. * notice, this list of conditions and the following disclaimer.
  30. * * Redistributions in binary form must reproduce the above
  31. * copyright notice, this list of conditions and the following disclaimer
  32. * in the documentation and/or other materials provided with the
  33. * distribution.
  34. * * Neither the name of Google Inc. nor the names of its
  35. * contributors may be used to endorse or promote products derived from
  36. * this software without specific prior written permission.
  37. *
  38. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  39. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  40. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  41. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  42. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  43. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  44. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  45. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  46. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  47. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  48. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  49. *
  50. */
  51. /**
  52. * Server module
  53. *
  54. * This module contains all the server code for Node gRPC: both the Server
  55. * class itself and the method handler code for all types of methods.
  56. *
  57. * For example, to create a Server, add a service, and start it:
  58. *
  59. * var server = new server_module.Server();
  60. * server.addProtoService(protobuf_service_descriptor, service_implementation);
  61. * server.bind('address:port', server_credential);
  62. * server.start();
  63. *
  64. * @module
  65. */
  66. 'use strict';
  67. var _ = require('lodash');
  68. var grpc = require('bindings')('grpc_node');
  69. var common = require('./common');
  70. var Metadata = require('./metadata');
  71. var stream = require('stream');
  72. var Readable = stream.Readable;
  73. var Writable = stream.Writable;
  74. var Duplex = stream.Duplex;
  75. var util = require('util');
  76. var EventEmitter = require('events').EventEmitter;
  77. /**
  78. * Handle an error on a call by sending it as a status
  79. * @access private
  80. * @param {grpc.Call} call The call to send the error on
  81. * @param {Object} error The error object
  82. */
  83. function handleError(call, error) {
  84. var statusMetadata = new Metadata();
  85. var status = {
  86. code: grpc.status.UNKNOWN,
  87. details: 'Unknown Error'
  88. };
  89. if (error.hasOwnProperty('message')) {
  90. status.details = error.message;
  91. }
  92. if (error.hasOwnProperty('code')) {
  93. status.code = error.code;
  94. if (error.hasOwnProperty('details')) {
  95. status.details = error.details;
  96. }
  97. }
  98. if (error.hasOwnProperty('metadata')) {
  99. statusMetadata = error.metadata;
  100. }
  101. status.metadata = statusMetadata._getCoreRepresentation();
  102. var error_batch = {};
  103. if (!call.metadataSent) {
  104. error_batch[grpc.opType.SEND_INITIAL_METADATA] =
  105. (new Metadata())._getCoreRepresentation();
  106. }
  107. error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
  108. call.startBatch(error_batch, function(){});
  109. }
  110. /**
  111. * Send a response to a unary or client streaming call.
  112. * @access private
  113. * @param {grpc.Call} call The call to respond on
  114. * @param {*} value The value to respond with
  115. * @param {function(*):Buffer=} serialize Serialization function for the
  116. * response
  117. * @param {Metadata=} metadata Optional trailing metadata to send with status
  118. * @param {number=} flags Flags for modifying how the message is sent.
  119. * Defaults to 0.
  120. */
  121. function sendUnaryResponse(call, value, serialize, metadata, flags) {
  122. var end_batch = {};
  123. var statusMetadata = new Metadata();
  124. var status = {
  125. code: grpc.status.OK,
  126. details: 'OK'
  127. };
  128. if (metadata) {
  129. statusMetadata = metadata;
  130. }
  131. status.metadata = statusMetadata._getCoreRepresentation();
  132. if (!call.metadataSent) {
  133. end_batch[grpc.opType.SEND_INITIAL_METADATA] =
  134. (new Metadata())._getCoreRepresentation();
  135. call.metadataSent = true;
  136. }
  137. var message = serialize(value);
  138. message.grpcWriteFlags = flags;
  139. end_batch[grpc.opType.SEND_MESSAGE] = message;
  140. end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
  141. call.startBatch(end_batch, function (){});
  142. }
  143. /**
  144. * Initialize a writable stream. This is used for both the writable and duplex
  145. * stream constructors.
  146. * @access private
  147. * @param {Writable} stream The stream to set up
  148. * @param {function(*):Buffer=} Serialization function for responses
  149. */
  150. function setUpWritable(stream, serialize) {
  151. stream.finished = false;
  152. stream.status = {
  153. code : grpc.status.OK,
  154. details : 'OK',
  155. metadata : new Metadata()
  156. };
  157. stream.serialize = common.wrapIgnoreNull(serialize);
  158. function sendStatus() {
  159. var batch = {};
  160. if (!stream.call.metadataSent) {
  161. stream.call.metadataSent = true;
  162. batch[grpc.opType.SEND_INITIAL_METADATA] =
  163. (new Metadata())._getCoreRepresentation();
  164. }
  165. if (stream.status.metadata) {
  166. stream.status.metadata = stream.status.metadata._getCoreRepresentation();
  167. }
  168. batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status;
  169. stream.call.startBatch(batch, function(){});
  170. }
  171. stream.on('finish', sendStatus);
  172. /**
  173. * Set the pending status to a given error status. If the error does not have
  174. * code or details properties, the code will be set to grpc.status.UNKNOWN
  175. * and the details will be set to 'Unknown Error'.
  176. * @param {Error} err The error object
  177. */
  178. function setStatus(err) {
  179. var code = grpc.status.UNKNOWN;
  180. var details = 'Unknown Error';
  181. var metadata = new Metadata();
  182. if (err.hasOwnProperty('message')) {
  183. details = err.message;
  184. }
  185. if (err.hasOwnProperty('code')) {
  186. code = err.code;
  187. if (err.hasOwnProperty('details')) {
  188. details = err.details;
  189. }
  190. }
  191. if (err.hasOwnProperty('metadata')) {
  192. metadata = err.metadata;
  193. }
  194. stream.status = {code: code, details: details, metadata: metadata};
  195. }
  196. /**
  197. * Terminate the call. This includes indicating that reads are done, draining
  198. * all pending writes, and sending the given error as a status
  199. * @param {Error} err The error object
  200. * @this GrpcServerStream
  201. */
  202. function terminateCall(err) {
  203. // Drain readable data
  204. setStatus(err);
  205. stream.end();
  206. }
  207. stream.on('error', terminateCall);
  208. /**
  209. * Override of Writable#end method that allows for sending metadata with a
  210. * success status.
  211. * @param {Metadata=} metadata Metadata to send with the status
  212. */
  213. stream.end = function(metadata) {
  214. if (metadata) {
  215. stream.status.metadata = metadata;
  216. }
  217. Writable.prototype.end.call(this);
  218. };
  219. }
  220. /**
  221. * Initialize a readable stream. This is used for both the readable and duplex
  222. * stream constructors.
  223. * @access private
  224. * @param {Readable} stream The stream to initialize
  225. * @param {function(Buffer):*=} deserialize Deserialization function for
  226. * incoming data.
  227. */
  228. function setUpReadable(stream, deserialize) {
  229. stream.deserialize = common.wrapIgnoreNull(deserialize);
  230. stream.finished = false;
  231. stream.reading = false;
  232. stream.terminate = function() {
  233. stream.finished = true;
  234. stream.on('data', function() {});
  235. };
  236. stream.on('cancelled', function() {
  237. stream.terminate();
  238. });
  239. }
  240. util.inherits(ServerUnaryCall, EventEmitter);
  241. function ServerUnaryCall(call) {
  242. EventEmitter.call(this);
  243. this.call = call;
  244. }
  245. util.inherits(ServerWritableStream, Writable);
  246. /**
  247. * A stream that the server can write to. Used for calls that are streaming from
  248. * the server side.
  249. * @constructor
  250. * @param {grpc.Call} call The call object to send data with
  251. * @param {function(*):Buffer=} serialize Serialization function for writes
  252. */
  253. function ServerWritableStream(call, serialize) {
  254. Writable.call(this, {objectMode: true});
  255. this.call = call;
  256. this.finished = false;
  257. setUpWritable(this, serialize);
  258. }
  259. /**
  260. * Start writing a chunk of data. This is an implementation of a method required
  261. * for implementing stream.Writable.
  262. * @access private
  263. * @param {Buffer} chunk The chunk of data to write
  264. * @param {string} encoding Used to pass write flags
  265. * @param {function(Error=)} callback Callback to indicate that the write is
  266. * complete
  267. */
  268. function _write(chunk, encoding, callback) {
  269. /* jshint validthis: true */
  270. var batch = {};
  271. var self = this;
  272. if (!this.call.metadataSent) {
  273. batch[grpc.opType.SEND_INITIAL_METADATA] =
  274. (new Metadata())._getCoreRepresentation();
  275. this.call.metadataSent = true;
  276. }
  277. var message = this.serialize(chunk);
  278. if (_.isFinite(encoding)) {
  279. /* Attach the encoding if it is a finite number. This is the closest we
  280. * can get to checking that it is valid flags */
  281. message.grpcWriteFlags = encoding;
  282. }
  283. batch[grpc.opType.SEND_MESSAGE] = message;
  284. this.call.startBatch(batch, function(err, value) {
  285. if (err) {
  286. self.emit('error', err);
  287. return;
  288. }
  289. callback();
  290. });
  291. }
  292. ServerWritableStream.prototype._write = _write;
  293. util.inherits(ServerReadableStream, Readable);
  294. /**
  295. * A stream that the server can read from. Used for calls that are streaming
  296. * from the client side.
  297. * @constructor
  298. * @param {grpc.Call} call The call object to read data with
  299. * @param {function(Buffer):*=} deserialize Deserialization function for reads
  300. */
  301. function ServerReadableStream(call, deserialize) {
  302. Readable.call(this, {objectMode: true});
  303. this.call = call;
  304. setUpReadable(this, deserialize);
  305. }
  306. /**
  307. * Start reading from the gRPC data source. This is an implementation of a
  308. * method required for implementing stream.Readable
  309. * @access private
  310. * @param {number} size Ignored
  311. */
  312. function _read(size) {
  313. /* jshint validthis: true */
  314. var self = this;
  315. /**
  316. * Callback to be called when a READ event is received. Pushes the data onto
  317. * the read queue and starts reading again if applicable
  318. * @param {grpc.Event} event READ event object
  319. */
  320. function readCallback(err, event) {
  321. if (err) {
  322. self.terminate();
  323. return;
  324. }
  325. if (self.finished) {
  326. self.push(null);
  327. return;
  328. }
  329. var data = event.read;
  330. var deserialized;
  331. try {
  332. deserialized = self.deserialize(data);
  333. } catch (e) {
  334. e.code = grpc.status.INVALID_ARGUMENT;
  335. self.emit('error', e);
  336. return;
  337. }
  338. if (self.push(deserialized) &amp;&amp; data !== null) {
  339. var read_batch = {};
  340. read_batch[grpc.opType.RECV_MESSAGE] = true;
  341. self.call.startBatch(read_batch, readCallback);
  342. } else {
  343. self.reading = false;
  344. }
  345. }
  346. if (self.finished) {
  347. self.push(null);
  348. } else {
  349. if (!self.reading) {
  350. self.reading = true;
  351. var batch = {};
  352. batch[grpc.opType.RECV_MESSAGE] = true;
  353. self.call.startBatch(batch, readCallback);
  354. }
  355. }
  356. }
  357. ServerReadableStream.prototype._read = _read;
  358. util.inherits(ServerDuplexStream, Duplex);
  359. /**
  360. * A stream that the server can read from or write to. Used for calls with
  361. * duplex streaming.
  362. * @constructor
  363. * @param {grpc.Call} call Call object to proxy
  364. * @param {function(*):Buffer=} serialize Serialization function for requests
  365. * @param {function(Buffer):*=} deserialize Deserialization function for
  366. * responses
  367. */
  368. function ServerDuplexStream(call, serialize, deserialize) {
  369. Duplex.call(this, {objectMode: true});
  370. this.call = call;
  371. setUpWritable(this, serialize);
  372. setUpReadable(this, deserialize);
  373. }
  374. ServerDuplexStream.prototype._read = _read;
  375. ServerDuplexStream.prototype._write = _write;
  376. /**
  377. * Send the initial metadata for a writable stream.
  378. * @param {Metadata} responseMetadata Metadata to send
  379. */
  380. function sendMetadata(responseMetadata) {
  381. /* jshint validthis: true */
  382. var self = this;
  383. if (!this.call.metadataSent) {
  384. this.call.metadataSent = true;
  385. var batch = {};
  386. batch[grpc.opType.SEND_INITIAL_METADATA] =
  387. responseMetadata._getCoreRepresentation();
  388. this.call.startBatch(batch, function(err) {
  389. if (err) {
  390. self.emit('error', err);
  391. return;
  392. }
  393. });
  394. }
  395. }
  396. ServerUnaryCall.prototype.sendMetadata = sendMetadata;
  397. ServerWritableStream.prototype.sendMetadata = sendMetadata;
  398. ServerReadableStream.prototype.sendMetadata = sendMetadata;
  399. ServerDuplexStream.prototype.sendMetadata = sendMetadata;
  400. /**
  401. * Get the endpoint this call/stream is connected to.
  402. * @return {string} The URI of the endpoint
  403. */
  404. function getPeer() {
  405. /* jshint validthis: true */
  406. return this.call.getPeer();
  407. }
  408. ServerUnaryCall.prototype.getPeer = getPeer;
  409. ServerReadableStream.prototype.getPeer = getPeer;
  410. ServerWritableStream.prototype.getPeer = getPeer;
  411. ServerDuplexStream.prototype.getPeer = getPeer;
  412. /**
  413. * Wait for the client to close, then emit a cancelled event if the client
  414. * cancelled.
  415. */
  416. function waitForCancel() {
  417. /* jshint validthis: true */
  418. var self = this;
  419. var cancel_batch = {};
  420. cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
  421. self.call.startBatch(cancel_batch, function(err, result) {
  422. if (err) {
  423. self.emit('error', err);
  424. }
  425. if (result.cancelled) {
  426. self.cancelled = true;
  427. self.emit('cancelled');
  428. }
  429. });
  430. }
  431. ServerUnaryCall.prototype.waitForCancel = waitForCancel;
  432. ServerReadableStream.prototype.waitForCancel = waitForCancel;
  433. ServerWritableStream.prototype.waitForCancel = waitForCancel;
  434. ServerDuplexStream.prototype.waitForCancel = waitForCancel;
  435. /**
  436. * Fully handle a unary call
  437. * @access private
  438. * @param {grpc.Call} call The call to handle
  439. * @param {Object} handler Request handler object for the method that was called
  440. * @param {Metadata} metadata Metadata from the client
  441. */
  442. function handleUnary(call, handler, metadata) {
  443. var emitter = new ServerUnaryCall(call);
  444. emitter.on('error', function(error) {
  445. handleError(call, error);
  446. });
  447. emitter.metadata = metadata;
  448. emitter.waitForCancel();
  449. var batch = {};
  450. batch[grpc.opType.RECV_MESSAGE] = true;
  451. call.startBatch(batch, function(err, result) {
  452. if (err) {
  453. handleError(call, err);
  454. return;
  455. }
  456. try {
  457. emitter.request = handler.deserialize(result.read);
  458. } catch (e) {
  459. e.code = grpc.status.INVALID_ARGUMENT;
  460. handleError(call, e);
  461. return;
  462. }
  463. if (emitter.cancelled) {
  464. return;
  465. }
  466. handler.func(emitter, function sendUnaryData(err, value, trailer, flags) {
  467. if (err) {
  468. if (trailer) {
  469. err.metadata = trailer;
  470. }
  471. handleError(call, err);
  472. } else {
  473. sendUnaryResponse(call, value, handler.serialize, trailer, flags);
  474. }
  475. });
  476. });
  477. }
  478. /**
  479. * Fully handle a server streaming call
  480. * @access private
  481. * @param {grpc.Call} call The call to handle
  482. * @param {Object} handler Request handler object for the method that was called
  483. * @param {Metadata} metadata Metadata from the client
  484. */
  485. function handleServerStreaming(call, handler, metadata) {
  486. var stream = new ServerWritableStream(call, handler.serialize);
  487. stream.waitForCancel();
  488. stream.metadata = metadata;
  489. var batch = {};
  490. batch[grpc.opType.RECV_MESSAGE] = true;
  491. call.startBatch(batch, function(err, result) {
  492. if (err) {
  493. stream.emit('error', err);
  494. return;
  495. }
  496. try {
  497. stream.request = handler.deserialize(result.read);
  498. } catch (e) {
  499. e.code = grpc.status.INVALID_ARGUMENT;
  500. stream.emit('error', e);
  501. return;
  502. }
  503. handler.func(stream);
  504. });
  505. }
  506. /**
  507. * Fully handle a client streaming call
  508. * @access private
  509. * @param {grpc.Call} call The call to handle
  510. * @param {Object} handler Request handler object for the method that was called
  511. * @param {Metadata} metadata Metadata from the client
  512. */
  513. function handleClientStreaming(call, handler, metadata) {
  514. var stream = new ServerReadableStream(call, handler.deserialize);
  515. stream.on('error', function(error) {
  516. handleError(call, error);
  517. });
  518. stream.waitForCancel();
  519. stream.metadata = metadata;
  520. handler.func(stream, function(err, value, trailer, flags) {
  521. stream.terminate();
  522. if (err) {
  523. if (trailer) {
  524. err.metadata = trailer;
  525. }
  526. handleError(call, err);
  527. } else {
  528. sendUnaryResponse(call, value, handler.serialize, trailer, flags);
  529. }
  530. });
  531. }
  532. /**
  533. * Fully handle a bidirectional streaming call
  534. * @access private
  535. * @param {grpc.Call} call The call to handle
  536. * @param {Object} handler Request handler object for the method that was called
  537. * @param {Metadata} metadata Metadata from the client
  538. */
  539. function handleBidiStreaming(call, handler, metadata) {
  540. var stream = new ServerDuplexStream(call, handler.serialize,
  541. handler.deserialize);
  542. stream.waitForCancel();
  543. stream.metadata = metadata;
  544. handler.func(stream);
  545. }
  546. var streamHandlers = {
  547. unary: handleUnary,
  548. server_stream: handleServerStreaming,
  549. client_stream: handleClientStreaming,
  550. bidi: handleBidiStreaming
  551. };
  552. /**
  553. * Constructs a server object that stores request handlers and delegates
  554. * incoming requests to those handlers
  555. * @constructor
  556. * @param {Object=} options Options that should be passed to the internal server
  557. * implementation
  558. */
  559. function Server(options) {
  560. this.handlers = {};
  561. var handlers = this.handlers;
  562. var server = new grpc.Server(options);
  563. this._server = server;
  564. this.started = false;
  565. /**
  566. * Start the server and begin handling requests
  567. * @this Server
  568. */
  569. this.start = function() {
  570. if (this.started) {
  571. throw new Error('Server is already running');
  572. }
  573. this.started = true;
  574. server.start();
  575. /**
  576. * Handles the SERVER_RPC_NEW event. If there is a handler associated with
  577. * the requested method, use that handler to respond to the request. Then
  578. * wait for the next request
  579. * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW
  580. */
  581. function handleNewCall(err, event) {
  582. if (err) {
  583. return;
  584. }
  585. var details = event.new_call;
  586. var call = details.call;
  587. var method = details.method;
  588. var metadata = Metadata._fromCoreRepresentation(details.metadata);
  589. if (method === null) {
  590. return;
  591. }
  592. server.requestCall(handleNewCall);
  593. var handler;
  594. if (handlers.hasOwnProperty(method)) {
  595. handler = handlers[method];
  596. } else {
  597. var batch = {};
  598. batch[grpc.opType.SEND_INITIAL_METADATA] =
  599. (new Metadata())._getCoreRepresentation();
  600. batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
  601. code: grpc.status.UNIMPLEMENTED,
  602. details: '',
  603. metadata: {}
  604. };
  605. batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
  606. call.startBatch(batch, function() {});
  607. return;
  608. }
  609. streamHandlers[handler.type](call, handler, metadata);
  610. }
  611. server.requestCall(handleNewCall);
  612. };
  613. /**
  614. * Gracefully shuts down the server. The server will stop receiving new calls,
  615. * and any pending calls will complete. The callback will be called when all
  616. * pending calls have completed and the server is fully shut down. This method
  617. * is idempotent with itself and forceShutdown.
  618. * @param {function()} callback The shutdown complete callback
  619. */
  620. this.tryShutdown = function(callback) {
  621. server.tryShutdown(callback);
  622. };
  623. /**
  624. * Forcibly shuts down the server. The server will stop receiving new calls
  625. * and cancel all pending calls. When it returns, the server has shut down.
  626. * This method is idempotent with itself and tryShutdown, and it will trigger
  627. * any outstanding tryShutdown callbacks.
  628. */
  629. this.forceShutdown = function() {
  630. server.forceShutdown();
  631. };
  632. }
  633. /**
  634. * Registers a handler to handle the named method. Fails if there already is
  635. * a handler for the given method. Returns true on success
  636. * @param {string} name The name of the method that the provided function should
  637. * handle/respond to.
  638. * @param {function} handler Function that takes a stream of request values and
  639. * returns a stream of response values
  640. * @param {function(*):Buffer} serialize Serialization function for responses
  641. * @param {function(Buffer):*} deserialize Deserialization function for requests
  642. * @param {string} type The streaming type of method that this handles
  643. * @return {boolean} True if the handler was set. False if a handler was already
  644. * set for that name.
  645. */
  646. Server.prototype.register = function(name, handler, serialize, deserialize,
  647. type) {
  648. if (this.handlers.hasOwnProperty(name)) {
  649. return false;
  650. }
  651. this.handlers[name] = {
  652. func: handler,
  653. serialize: serialize,
  654. deserialize: deserialize,
  655. type: type
  656. };
  657. return true;
  658. };
  659. /**
  660. * Add a service to the server, with a corresponding implementation. If you are
  661. * generating this from a proto file, you should instead use
  662. * addProtoService.
  663. * @param {Object&lt;String, *>} service The service descriptor, as
  664. * {@link module:src/common.getProtobufServiceAttrs} returns
  665. * @param {Object&lt;String, function>} implementation Map of method names to
  666. * method implementation for the provided service.
  667. */
  668. Server.prototype.addService = function(service, implementation) {
  669. if (this.started) {
  670. throw new Error('Can\'t add a service to a started server.');
  671. }
  672. var self = this;
  673. _.each(service, function(attrs, name) {
  674. var method_type;
  675. if (attrs.requestStream) {
  676. if (attrs.responseStream) {
  677. method_type = 'bidi';
  678. } else {
  679. method_type = 'client_stream';
  680. }
  681. } else {
  682. if (attrs.responseStream) {
  683. method_type = 'server_stream';
  684. } else {
  685. method_type = 'unary';
  686. }
  687. }
  688. if (implementation[name] === undefined) {
  689. throw new Error('Method handler for ' + attrs.path +
  690. ' not provided.');
  691. }
  692. var serialize = attrs.responseSerialize;
  693. var deserialize = attrs.requestDeserialize;
  694. var register_success = self.register(attrs.path,
  695. _.bind(implementation[name],
  696. implementation),
  697. serialize, deserialize, method_type);
  698. if (!register_success) {
  699. throw new Error('Method handler for ' + attrs.path +
  700. ' already provided.');
  701. }
  702. });
  703. };
  704. /**
  705. * Add a proto service to the server, with a corresponding implementation
  706. * @param {Protobuf.Reflect.Service} service The proto service descriptor
  707. * @param {Object&lt;String, function>} implementation Map of method names to
  708. * method implementation for the provided service.
  709. */
  710. Server.prototype.addProtoService = function(service, implementation) {
  711. this.addService(common.getProtobufServiceAttrs(service), implementation);
  712. };
  713. /**
  714. * Binds the server to the given port, with SSL enabled if creds is given
  715. * @param {string} port The port that the server should bind on, in the format
  716. * "address:port"
  717. * @param {ServerCredentials=} creds Server credential object to be used for
  718. * SSL. Pass an insecure credentials object for an insecure port.
  719. */
  720. Server.prototype.bind = function(port, creds) {
  721. if (this.started) {
  722. throw new Error('Can\'t bind an already running server to an address');
  723. }
  724. return this._server.addHttp2Port(port, creds);
  725. };
  726. /**
  727. * @see module:src/server~Server
  728. */
  729. exports.Server = Server;
  730. </code></pre>
  731. </article>
  732. </section>
  733. </div>
  734. <nav>
  735. <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-src_client.html">src/client</a></li><li><a href="module-src_common.html">src/common</a></li><li><a href="module-src_credentials.html">src/credentials</a></li><li><a href="module-src_metadata.html">src/metadata</a></li><li><a href="module-src_server.html">src/server</a></li></ul><h3>Classes</h3><ul><li><a href="module-src_client.makeClientConstructor-Client.html">Client</a></li><li><a href="module-src_client-ClientDuplexStream.html">ClientDuplexStream</a></li><li><a href="module-src_client-ClientReadableStream.html">ClientReadableStream</a></li><li><a href="module-src_client-ClientWritableStream.html">ClientWritableStream</a></li><li><a href="module-src_metadata-Metadata.html">Metadata</a></li><li><a href="module-src_server-Server.html">Server</a></li><li><a href="module-src_server-ServerDuplexStream.html">ServerDuplexStream</a></li><li><a href="module-src_server-ServerReadableStream.html">ServerReadableStream</a></li><li><a href="module-src_server-ServerWritableStream.html">ServerWritableStream</a></li></ul><h3>Global</h3><ul><li><a href="global.html#callError">callError</a></li><li><a href="global.html#credentials">credentials</a></li><li><a href="global.html#getClientChannel">getClientChannel</a></li><li><a href="global.html#load">load</a></li><li><a href="global.html#loadObject">loadObject</a></li><li><a href="global.html#makeGenericClientConstructor">makeGenericClientConstructor</a></li><li><a href="global.html#Metadata">Metadata</a></li><li><a href="global.html#propagate">propagate</a></li><li><a href="global.html#Server">Server</a></li><li><a href="global.html#ServerCredentials">ServerCredentials</a></li><li><a href="global.html#status">status</a></li><li><a href="global.html#waitForClientReady">waitForClientReady</a></li><li><a href="global.html#writeFlags">writeFlags</a></li></ul>
  736. </nav>
  737. <br class="clear">
  738. <footer>
  739. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Thu Jan 14 2016 16:17:15 GMT-0800 (PST)
  740. </footer>
  741. <script> prettyPrint(); </script>
  742. <script src="scripts/linenumber.js"> </script>
  743. </body>
  744. </html>