src_server.js.html 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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. var self = this;
  277. if (!this.call.metadataSent) {
  278. batch[grpc.opType.SEND_INITIAL_METADATA] =
  279. (new Metadata())._getCoreRepresentation();
  280. this.call.metadataSent = true;
  281. }
  282. var message = this.serialize(chunk);
  283. if (_.isFinite(encoding)) {
  284. /* Attach the encoding if it is a finite number. This is the closest we
  285. * can get to checking that it is valid flags */
  286. message.grpcWriteFlags = encoding;
  287. }
  288. batch[grpc.opType.SEND_MESSAGE] = message;
  289. this.call.startBatch(batch, function(err, value) {
  290. if (err) {
  291. self.emit('error', err);
  292. return;
  293. }
  294. callback();
  295. });
  296. }
  297. ServerWritableStream.prototype._write = _write;
  298. /**
  299. * Send the initial metadata for a writable stream.
  300. * @param {Metadata} responseMetadata Metadata to send
  301. */
  302. function sendMetadata(responseMetadata) {
  303. /* jshint validthis: true */
  304. var self = this;
  305. if (!this.call.metadataSent) {
  306. this.call.metadataSent = true;
  307. var batch = [];
  308. batch[grpc.opType.SEND_INITIAL_METADATA] =
  309. responseMetadata._getCoreRepresentation();
  310. this.call.startBatch(batch, function(err) {
  311. if (err) {
  312. self.emit('error', err);
  313. return;
  314. }
  315. });
  316. }
  317. }
  318. /**
  319. * @inheritdoc
  320. * @alias module:src/server~ServerWritableStream#sendMetadata
  321. */
  322. ServerWritableStream.prototype.sendMetadata = sendMetadata;
  323. util.inherits(ServerReadableStream, Readable);
  324. /**
  325. * A stream that the server can read from. Used for calls that are streaming
  326. * from the client side.
  327. * @constructor
  328. * @param {grpc.Call} call The call object to read data with
  329. * @param {function(Buffer):*=} deserialize Deserialization function for reads
  330. */
  331. function ServerReadableStream(call, deserialize) {
  332. Readable.call(this, {objectMode: true});
  333. this.call = call;
  334. setUpReadable(this, deserialize);
  335. }
  336. /**
  337. * Start reading from the gRPC data source. This is an implementation of a
  338. * method required for implementing stream.Readable
  339. * @access private
  340. * @param {number} size Ignored
  341. */
  342. function _read(size) {
  343. /* jshint validthis: true */
  344. var self = this;
  345. /**
  346. * Callback to be called when a READ event is received. Pushes the data onto
  347. * the read queue and starts reading again if applicable
  348. * @param {grpc.Event} event READ event object
  349. */
  350. function readCallback(err, event) {
  351. if (err) {
  352. self.terminate();
  353. return;
  354. }
  355. if (self.finished) {
  356. self.push(null);
  357. return;
  358. }
  359. var data = event.read;
  360. var deserialized;
  361. try {
  362. deserialized = self.deserialize(data);
  363. } catch (e) {
  364. e.code = grpc.status.INVALID_ARGUMENT;
  365. self.emit('error', e);
  366. return;
  367. }
  368. if (self.push(deserialized) &amp;&amp; data !== null) {
  369. var read_batch = {};
  370. read_batch[grpc.opType.RECV_MESSAGE] = true;
  371. self.call.startBatch(read_batch, readCallback);
  372. } else {
  373. self.reading = false;
  374. }
  375. }
  376. if (self.finished) {
  377. self.push(null);
  378. } else {
  379. if (!self.reading) {
  380. self.reading = true;
  381. var batch = {};
  382. batch[grpc.opType.RECV_MESSAGE] = true;
  383. self.call.startBatch(batch, readCallback);
  384. }
  385. }
  386. }
  387. ServerReadableStream.prototype._read = _read;
  388. util.inherits(ServerDuplexStream, Duplex);
  389. /**
  390. * A stream that the server can read from or write to. Used for calls with
  391. * duplex streaming.
  392. * @constructor
  393. * @param {grpc.Call} call Call object to proxy
  394. * @param {function(*):Buffer=} serialize Serialization function for requests
  395. * @param {function(Buffer):*=} deserialize Deserialization function for
  396. * responses
  397. */
  398. function ServerDuplexStream(call, serialize, deserialize) {
  399. Duplex.call(this, {objectMode: true});
  400. this.call = call;
  401. setUpWritable(this, serialize);
  402. setUpReadable(this, deserialize);
  403. }
  404. ServerDuplexStream.prototype._read = _read;
  405. ServerDuplexStream.prototype._write = _write;
  406. ServerDuplexStream.prototype.sendMetadata = sendMetadata;
  407. /**
  408. * Get the endpoint this call/stream is connected to.
  409. * @return {string} The URI of the endpoint
  410. */
  411. function getPeer() {
  412. /* jshint validthis: true */
  413. return this.call.getPeer();
  414. }
  415. ServerReadableStream.prototype.getPeer = getPeer;
  416. ServerWritableStream.prototype.getPeer = getPeer;
  417. ServerDuplexStream.prototype.getPeer = getPeer;
  418. /**
  419. * Fully handle a unary call
  420. * @access private
  421. * @param {grpc.Call} call The call to handle
  422. * @param {Object} handler Request handler object for the method that was called
  423. * @param {Metadata} metadata Metadata from the client
  424. */
  425. function handleUnary(call, handler, metadata) {
  426. var emitter = new EventEmitter();
  427. emitter.sendMetadata = function(responseMetadata) {
  428. if (!call.metadataSent) {
  429. call.metadataSent = true;
  430. var batch = {};
  431. batch[grpc.opType.SEND_INITIAL_METADATA] =
  432. responseMetadata._getCoreRepresentation();
  433. call.startBatch(batch, function() {});
  434. }
  435. };
  436. emitter.getPeer = function() {
  437. return call.getPeer();
  438. };
  439. emitter.on('error', function(error) {
  440. handleError(call, error);
  441. });
  442. emitter.metadata = metadata;
  443. waitForCancel(call, emitter);
  444. emitter.call = call;
  445. var batch = {};
  446. batch[grpc.opType.RECV_MESSAGE] = true;
  447. call.startBatch(batch, function(err, result) {
  448. if (err) {
  449. handleError(call, err);
  450. return;
  451. }
  452. try {
  453. emitter.request = handler.deserialize(result.read);
  454. } catch (e) {
  455. e.code = grpc.status.INVALID_ARGUMENT;
  456. handleError(call, e);
  457. return;
  458. }
  459. if (emitter.cancelled) {
  460. return;
  461. }
  462. handler.func(emitter, function sendUnaryData(err, value, trailer, flags) {
  463. if (err) {
  464. if (trailer) {
  465. err.metadata = trailer;
  466. }
  467. handleError(call, err);
  468. } else {
  469. sendUnaryResponse(call, value, handler.serialize, trailer, flags);
  470. }
  471. });
  472. });
  473. }
  474. /**
  475. * Fully handle a server streaming call
  476. * @access private
  477. * @param {grpc.Call} call The call to handle
  478. * @param {Object} handler Request handler object for the method that was called
  479. * @param {Metadata} metadata Metadata from the client
  480. */
  481. function handleServerStreaming(call, handler, metadata) {
  482. var stream = new ServerWritableStream(call, handler.serialize);
  483. waitForCancel(call, stream);
  484. stream.metadata = metadata;
  485. var batch = {};
  486. batch[grpc.opType.RECV_MESSAGE] = true;
  487. call.startBatch(batch, function(err, result) {
  488. if (err) {
  489. stream.emit('error', err);
  490. return;
  491. }
  492. try {
  493. stream.request = handler.deserialize(result.read);
  494. } catch (e) {
  495. e.code = grpc.status.INVALID_ARGUMENT;
  496. stream.emit('error', e);
  497. return;
  498. }
  499. handler.func(stream);
  500. });
  501. }
  502. /**
  503. * Fully handle a client streaming call
  504. * @access private
  505. * @param {grpc.Call} call The call to handle
  506. * @param {Object} handler Request handler object for the method that was called
  507. * @param {Metadata} metadata Metadata from the client
  508. */
  509. function handleClientStreaming(call, handler, metadata) {
  510. var stream = new ServerReadableStream(call, handler.deserialize);
  511. stream.sendMetadata = function(responseMetadata) {
  512. if (!call.metadataSent) {
  513. call.metadataSent = true;
  514. var batch = {};
  515. batch[grpc.opType.SEND_INITIAL_METADATA] =
  516. responseMetadata._getCoreRepresentation();
  517. call.startBatch(batch, function() {});
  518. }
  519. };
  520. stream.on('error', function(error) {
  521. handleError(call, error);
  522. });
  523. waitForCancel(call, stream);
  524. stream.metadata = metadata;
  525. handler.func(stream, function(err, value, trailer, flags) {
  526. stream.terminate();
  527. if (err) {
  528. if (trailer) {
  529. err.metadata = trailer;
  530. }
  531. handleError(call, err);
  532. } else {
  533. sendUnaryResponse(call, value, handler.serialize, trailer, flags);
  534. }
  535. });
  536. }
  537. /**
  538. * Fully handle a bidirectional streaming call
  539. * @access private
  540. * @param {grpc.Call} call The call to handle
  541. * @param {Object} handler Request handler object for the method that was called
  542. * @param {Metadata} metadata Metadata from the client
  543. */
  544. function handleBidiStreaming(call, handler, metadata) {
  545. var stream = new ServerDuplexStream(call, handler.serialize,
  546. handler.deserialize);
  547. waitForCancel(call, stream);
  548. stream.metadata = metadata;
  549. handler.func(stream);
  550. }
  551. var streamHandlers = {
  552. unary: handleUnary,
  553. server_stream: handleServerStreaming,
  554. client_stream: handleClientStreaming,
  555. bidi: handleBidiStreaming
  556. };
  557. /**
  558. * Constructs a server object that stores request handlers and delegates
  559. * incoming requests to those handlers
  560. * @constructor
  561. * @param {Object=} options Options that should be passed to the internal server
  562. * implementation
  563. */
  564. function Server(options) {
  565. this.handlers = {};
  566. var handlers = this.handlers;
  567. var server = new grpc.Server(options);
  568. this._server = server;
  569. this.started = false;
  570. /**
  571. * Start the server and begin handling requests
  572. * @this Server
  573. */
  574. this.start = function() {
  575. if (this.started) {
  576. throw new Error('Server is already running');
  577. }
  578. this.started = true;
  579. console.log('Server starting');
  580. _.each(handlers, function(handler, handler_name) {
  581. console.log('Serving', handler_name);
  582. });
  583. server.start();
  584. /**
  585. * Handles the SERVER_RPC_NEW event. If there is a handler associated with
  586. * the requested method, use that handler to respond to the request. Then
  587. * wait for the next request
  588. * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW
  589. */
  590. function handleNewCall(err, event) {
  591. if (err) {
  592. return;
  593. }
  594. var details = event.new_call;
  595. var call = details.call;
  596. var method = details.method;
  597. var metadata = Metadata._fromCoreRepresentation(details.metadata);
  598. if (method === null) {
  599. return;
  600. }
  601. server.requestCall(handleNewCall);
  602. var handler;
  603. if (handlers.hasOwnProperty(method)) {
  604. handler = handlers[method];
  605. } else {
  606. var batch = {};
  607. batch[grpc.opType.SEND_INITIAL_METADATA] =
  608. (new Metadata())._getCoreRepresentation();
  609. batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
  610. code: grpc.status.UNIMPLEMENTED,
  611. details: 'This method is not available on this server.',
  612. metadata: {}
  613. };
  614. batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
  615. call.startBatch(batch, function() {});
  616. return;
  617. }
  618. streamHandlers[handler.type](call, handler, metadata);
  619. }
  620. server.requestCall(handleNewCall);
  621. };
  622. /**
  623. * Gracefully shuts down the server. The server will stop receiving new calls,
  624. * and any pending calls will complete. The callback will be called when all
  625. * pending calls have completed and the server is fully shut down. This method
  626. * is idempotent with itself and forceShutdown.
  627. * @param {function()} callback The shutdown complete callback
  628. */
  629. this.tryShutdown = function(callback) {
  630. server.tryShutdown(callback);
  631. };
  632. /**
  633. * Forcibly shuts down the server. The server will stop receiving new calls
  634. * and cancel all pending calls. When it returns, the server has shut down.
  635. * This method is idempotent with itself and tryShutdown, and it will trigger
  636. * any outstanding tryShutdown callbacks.
  637. */
  638. this.forceShutdown = function() {
  639. server.forceShutdown();
  640. };
  641. }
  642. /**
  643. * Registers a handler to handle the named method. Fails if there already is
  644. * a handler for the given method. Returns true on success
  645. * @param {string} name The name of the method that the provided function should
  646. * handle/respond to.
  647. * @param {function} handler Function that takes a stream of request values and
  648. * returns a stream of response values
  649. * @param {function(*):Buffer} serialize Serialization function for responses
  650. * @param {function(Buffer):*} deserialize Deserialization function for requests
  651. * @param {string} type The streaming type of method that this handles
  652. * @return {boolean} True if the handler was set. False if a handler was already
  653. * set for that name.
  654. */
  655. Server.prototype.register = function(name, handler, serialize, deserialize,
  656. type) {
  657. if (this.handlers.hasOwnProperty(name)) {
  658. return false;
  659. }
  660. this.handlers[name] = {
  661. func: handler,
  662. serialize: serialize,
  663. deserialize: deserialize,
  664. type: type
  665. };
  666. return true;
  667. };
  668. /**
  669. * Add a service to the server, with a corresponding implementation. If you are
  670. * generating this from a proto file, you should instead use
  671. * addProtoService.
  672. * @param {Object&lt;String, *>} service The service descriptor, as
  673. * {@link module:src/common.getProtobufServiceAttrs} returns
  674. * @param {Object&lt;String, function>} implementation Map of method names to
  675. * method implementation for the provided service.
  676. */
  677. Server.prototype.addService = function(service, implementation) {
  678. if (this.started) {
  679. throw new Error('Can\'t add a service to a started server.');
  680. }
  681. var self = this;
  682. _.each(service, function(attrs, name) {
  683. var method_type;
  684. if (attrs.requestStream) {
  685. if (attrs.responseStream) {
  686. method_type = 'bidi';
  687. } else {
  688. method_type = 'client_stream';
  689. }
  690. } else {
  691. if (attrs.responseStream) {
  692. method_type = 'server_stream';
  693. } else {
  694. method_type = 'unary';
  695. }
  696. }
  697. if (implementation[name] === undefined) {
  698. throw new Error('Method handler for ' + attrs.path +
  699. ' not provided.');
  700. }
  701. var serialize = attrs.responseSerialize;
  702. var deserialize = attrs.requestDeserialize;
  703. var register_success = self.register(attrs.path,
  704. _.bind(implementation[name],
  705. implementation),
  706. serialize, deserialize, method_type);
  707. if (!register_success) {
  708. throw new Error('Method handler for ' + attrs.path +
  709. ' already provided.');
  710. }
  711. });
  712. };
  713. /**
  714. * Add a proto service to the server, with a corresponding implementation
  715. * @param {Protobuf.Reflect.Service} service The proto service descriptor
  716. * @param {Object&lt;String, function>} implementation Map of method names to
  717. * method implementation for the provided service.
  718. */
  719. Server.prototype.addProtoService = function(service, implementation) {
  720. this.addService(common.getProtobufServiceAttrs(service), implementation);
  721. };
  722. /**
  723. * Binds the server to the given port, with SSL enabled if creds is given
  724. * @param {string} port The port that the server should bind on, in the format
  725. * "address:port"
  726. * @param {boolean=} creds Server credential object to be used for SSL. Pass
  727. * nothing for an insecure port
  728. */
  729. Server.prototype.bind = function(port, creds) {
  730. if (this.started) {
  731. throw new Error('Can\'t bind an already running server to an address');
  732. }
  733. return this._server.addHttp2Port(port, creds);
  734. };
  735. /**
  736. * @see module:src/server~Server
  737. */
  738. exports.Server = Server;
  739. </code></pre>
  740. </article>
  741. </section>
  742. </div>
  743. <nav>
  744. <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>
  745. </nav>
  746. <br class="clear">
  747. <footer>
  748. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.3</a> on Thu Oct 29 2015 13:07:25 GMT-0700 (PDT)
  749. </footer>
  750. <script> prettyPrint(); </script>
  751. <script src="scripts/linenumber.js"> </script>
  752. </body>
  753. </html>