src_server.js.html 26 KB

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