src_server.js.html 24 KB

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