src_client.js.html 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: src/client.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/client.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>/**
  20. * @license
  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. * Client module
  53. *
  54. * This module contains the factory method for creating Client classes, and the
  55. * method calling code for all types of methods.
  56. *
  57. * @example &lt;caption>Create a client and call a method on it&lt;/caption>
  58. *
  59. * var proto_obj = grpc.load(proto_file_path);
  60. * var Client = proto_obj.package.subpackage.ServiceName;
  61. * var client = new Client(server_address, client_credentials);
  62. * var call = client.unaryMethod(arguments, callback);
  63. */
  64. 'use strict';
  65. var _ = require('lodash');
  66. var arguejs = require('arguejs');
  67. var grpc = require('./grpc_extension');
  68. var common = require('./common');
  69. var Metadata = require('./metadata');
  70. var constants = require('./constants');
  71. var EventEmitter = require('events').EventEmitter;
  72. var stream = require('stream');
  73. var Readable = stream.Readable;
  74. var Writable = stream.Writable;
  75. var Duplex = stream.Duplex;
  76. var util = require('util');
  77. var version = require('../../../package.json').version;
  78. /**
  79. * Initial response metadata sent by the server when it starts processing the
  80. * call
  81. * @event grpc~ClientUnaryCall#metadata
  82. * @type {grpc.Metadata}
  83. */
  84. /**
  85. * Status of the call when it has completed.
  86. * @event grpc~ClientUnaryCall#status
  87. * @type grpc~StatusObject
  88. */
  89. util.inherits(ClientUnaryCall, EventEmitter);
  90. /**
  91. * An EventEmitter. Used for unary calls.
  92. * @constructor grpc~ClientUnaryCall
  93. * @extends external:EventEmitter
  94. * @param {grpc.internal~Call} call The call object associated with the request
  95. */
  96. function ClientUnaryCall(call) {
  97. EventEmitter.call(this);
  98. this.call = call;
  99. }
  100. util.inherits(ClientWritableStream, Writable);
  101. /**
  102. * A stream that the client can write to. Used for calls that are streaming from
  103. * the client side.
  104. * @constructor grpc~ClientWritableStream
  105. * @extends external:Writable
  106. * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientWritableStream#cancel
  107. * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientWritableStream#getPeer
  108. * @borrows grpc~ClientUnaryCall#event:metadata as
  109. * grpc~ClientWritableStream#metadata
  110. * @borrows grpc~ClientUnaryCall#event:status as
  111. * grpc~ClientWritableStream#status
  112. * @param {grpc.internal~Call} call The call object to send data with
  113. * @param {grpc~serialize=} [serialize=identity] Serialization
  114. * function for writes.
  115. */
  116. function ClientWritableStream(call, serialize) {
  117. Writable.call(this, {objectMode: true});
  118. this.call = call;
  119. this.serialize = common.wrapIgnoreNull(serialize);
  120. this.on('finish', function() {
  121. var batch = {};
  122. batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
  123. call.startBatch(batch, function() {});
  124. });
  125. }
  126. /**
  127. * Write a message to the request stream. If serializing the argument fails,
  128. * the call will be cancelled and the stream will end with an error.
  129. * @name grpc~ClientWritableStream#write
  130. * @kind function
  131. * @override
  132. * @param {*} message The message to write. Must be a valid argument to the
  133. * serialize function of the corresponding method
  134. * @param {grpc.writeFlags} flags Flags to modify how the message is written
  135. * @param {Function} callback Callback for when this chunk of data is flushed
  136. * @return {boolean} As defined for [Writable]{@link external:Writable}
  137. */
  138. /**
  139. * Attempt to write the given chunk. Calls the callback when done. This is an
  140. * implementation of a method needed for implementing stream.Writable.
  141. * @private
  142. * @param {*} chunk The chunk to write
  143. * @param {grpc.writeFlags} encoding Used to pass write flags
  144. * @param {function(Error=)} callback Called when the write is complete
  145. */
  146. function _write(chunk, encoding, callback) {
  147. /* jshint validthis: true */
  148. var batch = {};
  149. var message;
  150. var self = this;
  151. if (this.writeFailed) {
  152. /* Once a write fails, just call the callback immediately to let the caller
  153. flush any pending writes. */
  154. setImmediate(callback);
  155. return;
  156. }
  157. try {
  158. message = this.serialize(chunk);
  159. } catch (e) {
  160. /* Sending this error to the server and emitting it immediately on the
  161. client may put the call in a slightly weird state on the client side,
  162. but passing an object that causes a serialization failure is a misuse
  163. of the API anyway, so that's OK. The primary purpose here is to give the
  164. programmer a useful error and to stop the stream properly */
  165. this.call.cancelWithStatus(constants.status.INTERNAL,
  166. 'Serialization failure');
  167. callback(e);
  168. return;
  169. }
  170. if (_.isFinite(encoding)) {
  171. /* Attach the encoding if it is a finite number. This is the closest we
  172. * can get to checking that it is valid flags */
  173. message.grpcWriteFlags = encoding;
  174. }
  175. batch[grpc.opType.SEND_MESSAGE] = message;
  176. this.call.startBatch(batch, function(err, event) {
  177. if (err) {
  178. /* Assume that the call is complete and that writing failed because a
  179. status was received. In that case, set a flag to discard all future
  180. writes */
  181. self.writeFailed = true;
  182. }
  183. callback();
  184. });
  185. }
  186. ClientWritableStream.prototype._write = _write;
  187. util.inherits(ClientReadableStream, Readable);
  188. /**
  189. * A stream that the client can read from. Used for calls that are streaming
  190. * from the server side.
  191. * @constructor grpc~ClientReadableStream
  192. * @extends external:Readable
  193. * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientReadableStream#cancel
  194. * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientReadableStream#getPeer
  195. * @borrows grpc~ClientUnaryCall#event:metadata as
  196. * grpc~ClientReadableStream#metadata
  197. * @borrows grpc~ClientUnaryCall#event:status as
  198. * grpc~ClientReadableStream#status
  199. * @param {grpc.internal~Call} call The call object to read data with
  200. * @param {grpc~deserialize=} [deserialize=identity]
  201. * Deserialization function for reads
  202. */
  203. function ClientReadableStream(call, deserialize) {
  204. Readable.call(this, {objectMode: true});
  205. this.call = call;
  206. this.finished = false;
  207. this.reading = false;
  208. this.deserialize = common.wrapIgnoreNull(deserialize);
  209. /* Status generated from reading messages from the server. Overrides the
  210. * status from the server if not OK */
  211. this.read_status = null;
  212. /* Status received from the server. */
  213. this.received_status = null;
  214. }
  215. /**
  216. * Called when all messages from the server have been processed. The status
  217. * parameter indicates that the call should end with that status. status
  218. * defaults to OK if not provided.
  219. * @param {Object!} status The status that the call should end with
  220. * @private
  221. */
  222. function _readsDone(status) {
  223. /* jshint validthis: true */
  224. if (!status) {
  225. status = {code: constants.status.OK, details: 'OK'};
  226. }
  227. if (status.code !== constants.status.OK) {
  228. this.call.cancelWithStatus(status.code, status.details);
  229. }
  230. this.finished = true;
  231. this.read_status = status;
  232. this._emitStatusIfDone();
  233. }
  234. ClientReadableStream.prototype._readsDone = _readsDone;
  235. /**
  236. * Called to indicate that we have received a status from the server.
  237. * @private
  238. */
  239. function _receiveStatus(status) {
  240. /* jshint validthis: true */
  241. this.received_status = status;
  242. this._emitStatusIfDone();
  243. }
  244. ClientReadableStream.prototype._receiveStatus = _receiveStatus;
  245. /**
  246. * If we have both processed all incoming messages and received the status from
  247. * the server, emit the status. Otherwise, do nothing.
  248. * @private
  249. */
  250. function _emitStatusIfDone() {
  251. /* jshint validthis: true */
  252. var status;
  253. if (this.read_status &amp;&amp; this.received_status) {
  254. if (this.read_status.code !== constants.status.OK) {
  255. status = this.read_status;
  256. } else {
  257. status = this.received_status;
  258. }
  259. if (status.code === constants.status.OK) {
  260. this.push(null);
  261. } else {
  262. var error = new Error(status.details);
  263. error.code = status.code;
  264. error.metadata = status.metadata;
  265. this.emit('error', error);
  266. }
  267. this.emit('status', status);
  268. }
  269. }
  270. ClientReadableStream.prototype._emitStatusIfDone = _emitStatusIfDone;
  271. /**
  272. * Read the next object from the stream.
  273. * @private
  274. * @param {*} size Ignored because we use objectMode=true
  275. */
  276. function _read(size) {
  277. /* jshint validthis: true */
  278. var self = this;
  279. /**
  280. * Callback to be called when a READ event is received. Pushes the data onto
  281. * the read queue and starts reading again if applicable
  282. * @param {grpc.Event} event READ event object
  283. */
  284. function readCallback(err, event) {
  285. if (err) {
  286. // Something has gone wrong. Stop reading and wait for status
  287. self.finished = true;
  288. self._readsDone();
  289. return;
  290. }
  291. var data = event.read;
  292. var deserialized;
  293. try {
  294. deserialized = self.deserialize(data);
  295. } catch (e) {
  296. self._readsDone({code: constants.status.INTERNAL,
  297. details: 'Failed to parse server response'});
  298. return;
  299. }
  300. if (data === null) {
  301. self._readsDone();
  302. return;
  303. }
  304. if (self.push(deserialized) &amp;&amp; data !== null) {
  305. var read_batch = {};
  306. read_batch[grpc.opType.RECV_MESSAGE] = true;
  307. self.call.startBatch(read_batch, readCallback);
  308. } else {
  309. self.reading = false;
  310. }
  311. }
  312. if (self.finished) {
  313. self.push(null);
  314. } else {
  315. if (!self.reading) {
  316. self.reading = true;
  317. var read_batch = {};
  318. read_batch[grpc.opType.RECV_MESSAGE] = true;
  319. self.call.startBatch(read_batch, readCallback);
  320. }
  321. }
  322. }
  323. ClientReadableStream.prototype._read = _read;
  324. util.inherits(ClientDuplexStream, Duplex);
  325. /**
  326. * A stream that the client can read from or write to. Used for calls with
  327. * duplex streaming.
  328. * @constructor grpc~ClientDuplexStream
  329. * @extends external:Duplex
  330. * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientDuplexStream#cancel
  331. * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientDuplexStream#getPeer
  332. * @borrows grpc~ClientWritableStream#write as grpc~ClientDuplexStream#write
  333. * @borrows grpc~ClientUnaryCall#event:metadata as
  334. * grpc~ClientDuplexStream#metadata
  335. * @borrows grpc~ClientUnaryCall#event:status as
  336. * grpc~ClientDuplexStream#status
  337. * @param {grpc.internal~Call} call Call object to proxy
  338. * @param {grpc~serialize=} [serialize=identity] Serialization
  339. * function for requests
  340. * @param {grpc~deserialize=} [deserialize=identity]
  341. * Deserialization function for responses
  342. */
  343. function ClientDuplexStream(call, serialize, deserialize) {
  344. Duplex.call(this, {objectMode: true});
  345. this.serialize = common.wrapIgnoreNull(serialize);
  346. this.deserialize = common.wrapIgnoreNull(deserialize);
  347. this.call = call;
  348. /* Status generated from reading messages from the server. Overrides the
  349. * status from the server if not OK */
  350. this.read_status = null;
  351. /* Status received from the server. */
  352. this.received_status = null;
  353. this.on('finish', function() {
  354. var batch = {};
  355. batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
  356. call.startBatch(batch, function() {});
  357. });
  358. }
  359. ClientDuplexStream.prototype._readsDone = _readsDone;
  360. ClientDuplexStream.prototype._receiveStatus = _receiveStatus;
  361. ClientDuplexStream.prototype._emitStatusIfDone = _emitStatusIfDone;
  362. ClientDuplexStream.prototype._read = _read;
  363. ClientDuplexStream.prototype._write = _write;
  364. /**
  365. * Cancel the ongoing call. Results in the call ending with a CANCELLED status,
  366. * unless it has already ended with some other status.
  367. * @alias grpc~ClientUnaryCall#cancel
  368. */
  369. function cancel() {
  370. /* jshint validthis: true */
  371. this.call.cancel();
  372. }
  373. ClientUnaryCall.prototype.cancel = cancel;
  374. ClientReadableStream.prototype.cancel = cancel;
  375. ClientWritableStream.prototype.cancel = cancel;
  376. ClientDuplexStream.prototype.cancel = cancel;
  377. /**
  378. * Get the endpoint this call/stream is connected to.
  379. * @return {string} The URI of the endpoint
  380. * @alias grpc~ClientUnaryCall#getPeer
  381. */
  382. function getPeer() {
  383. /* jshint validthis: true */
  384. return this.call.getPeer();
  385. }
  386. ClientUnaryCall.prototype.getPeer = getPeer;
  387. ClientReadableStream.prototype.getPeer = getPeer;
  388. ClientWritableStream.prototype.getPeer = getPeer;
  389. ClientDuplexStream.prototype.getPeer = getPeer;
  390. /**
  391. * Any client call type
  392. * @typedef {(ClientUnaryCall|ClientReadableStream|
  393. * ClientWritableStream|ClientDuplexStream)}
  394. * grpc.Client~Call
  395. */
  396. /**
  397. * Options that can be set on a call.
  398. * @typedef {Object} grpc.Client~CallOptions
  399. * @property {grpc~Deadline} deadline The deadline for the entire call to
  400. * complete.
  401. * @property {string} host Server hostname to set on the call. Only meaningful
  402. * if different from the server address used to construct the client.
  403. * @property {grpc.Client~Call} parent Parent call. Used in servers when
  404. * making a call as part of the process of handling a call. Used to
  405. * propagate some information automatically, as specified by
  406. * propagate_flags.
  407. * @property {number} propagate_flags Indicates which properties of a parent
  408. * call should propagate to this call. Bitwise combination of flags in
  409. * {@link grpc.propagate}.
  410. * @property {grpc.credentials~CallCredentials} credentials The credentials that
  411. * should be used to make this particular call.
  412. */
  413. /**
  414. * Get a call object built with the provided options.
  415. * @access private
  416. * @param {grpc.Client~CallOptions=} options Options object.
  417. */
  418. function getCall(channel, method, options) {
  419. var deadline;
  420. var host;
  421. var parent;
  422. var propagate_flags;
  423. var credentials;
  424. if (options) {
  425. deadline = options.deadline;
  426. host = options.host;
  427. parent = _.get(options, 'parent.call');
  428. propagate_flags = options.propagate_flags;
  429. credentials = options.credentials;
  430. }
  431. if (deadline === undefined) {
  432. deadline = Infinity;
  433. }
  434. var call = new grpc.Call(channel, method, deadline, host,
  435. parent, propagate_flags);
  436. if (credentials) {
  437. call.setCredentials(credentials);
  438. }
  439. return call;
  440. }
  441. /**
  442. * A generic gRPC client. Primarily useful as a base class for generated clients
  443. * @memberof grpc
  444. * @constructor
  445. * @param {string} address Server address to connect to
  446. * @param {grpc~ChannelCredentials} credentials Credentials to use to connect to
  447. * the server
  448. * @param {Object} options Options to apply to channel creation
  449. */
  450. function Client(address, credentials, options) {
  451. if (!options) {
  452. options = {};
  453. }
  454. /* Append the grpc-node user agent string after the application user agent
  455. * string, and put the combination at the beginning of the user agent string
  456. */
  457. if (options['grpc.primary_user_agent']) {
  458. options['grpc.primary_user_agent'] += ' ';
  459. } else {
  460. options['grpc.primary_user_agent'] = '';
  461. }
  462. options['grpc.primary_user_agent'] += 'grpc-node/' + version;
  463. /* Private fields use $ as a prefix instead of _ because it is an invalid
  464. * prefix of a method name */
  465. this.$channel = new grpc.Channel(address, credentials, options);
  466. }
  467. exports.Client = Client;
  468. /**
  469. * @callback grpc.Client~requestCallback
  470. * @param {?grpc~ServiceError} error The error, if the call
  471. * failed
  472. * @param {*} value The response value, if the call succeeded
  473. */
  474. /**
  475. * Make a unary request to the given method, using the given serialize
  476. * and deserialize functions, with the given argument.
  477. * @param {string} method The name of the method to request
  478. * @param {grpc~serialize} serialize The serialization function for
  479. * inputs
  480. * @param {grpc~deserialize} deserialize The deserialization
  481. * function for outputs
  482. * @param {*} argument The argument to the call. Should be serializable with
  483. * serialize
  484. * @param {grpc.Metadata=} metadata Metadata to add to the call
  485. * @param {grpc.Client~CallOptions=} options Options map
  486. * @param {grpc.Client~requestCallback} callback The callback to
  487. * for when the response is received
  488. * @return {grpc~ClientUnaryCall} An event emitter for stream related events
  489. */
  490. Client.prototype.makeUnaryRequest = function(method, serialize, deserialize,
  491. argument, metadata, options,
  492. callback) {
  493. /* While the arguments are listed in the function signature, those variables
  494. * are not used directly. Instead, ArgueJS processes the arguments
  495. * object. This allows for simple handling of optional arguments in the
  496. * middle of the argument list, and also provides type checking. */
  497. var args = arguejs({method: String, serialize: Function,
  498. deserialize: Function,
  499. argument: null, metadata: [Metadata, new Metadata()],
  500. options: [Object], callback: Function}, arguments);
  501. var call = getCall(this.$channel, method, args.options);
  502. var emitter = new ClientUnaryCall(call);
  503. metadata = args.metadata.clone();
  504. var client_batch = {};
  505. var message = serialize(args.argument);
  506. if (args.options) {
  507. message.grpcWriteFlags = args.options.flags;
  508. }
  509. client_batch[grpc.opType.SEND_INITIAL_METADATA] =
  510. metadata._getCoreRepresentation();
  511. client_batch[grpc.opType.SEND_MESSAGE] = message;
  512. client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
  513. client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
  514. client_batch[grpc.opType.RECV_MESSAGE] = true;
  515. client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
  516. call.startBatch(client_batch, function(err, response) {
  517. response.status.metadata = Metadata._fromCoreRepresentation(
  518. response.status.metadata);
  519. var status = response.status;
  520. var error;
  521. var deserialized;
  522. emitter.emit('metadata', Metadata._fromCoreRepresentation(
  523. response.metadata));
  524. if (status.code === constants.status.OK) {
  525. if (err) {
  526. // Got a batch error, but OK status. Something went wrong
  527. args.callback(err);
  528. return;
  529. } else {
  530. try {
  531. deserialized = deserialize(response.read);
  532. } catch (e) {
  533. /* Change status to indicate bad server response. This will result
  534. * in passing an error to the callback */
  535. status = {
  536. code: constants.status.INTERNAL,
  537. details: 'Failed to parse server response'
  538. };
  539. }
  540. }
  541. }
  542. if (status.code !== constants.status.OK) {
  543. error = new Error(status.details);
  544. error.code = status.code;
  545. error.metadata = status.metadata;
  546. args.callback(error);
  547. } else {
  548. args.callback(null, deserialized);
  549. }
  550. emitter.emit('status', status);
  551. });
  552. return emitter;
  553. };
  554. /**
  555. * Make a client stream request to the given method, using the given serialize
  556. * and deserialize functions, with the given argument.
  557. * @param {string} method The name of the method to request
  558. * @param {grpc~serialize} serialize The serialization function for
  559. * inputs
  560. * @param {grpc~deserialize} deserialize The deserialization
  561. * function for outputs
  562. * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to
  563. * the call
  564. * @param {grpc.Client~CallOptions=} options Options map
  565. * @param {grpc.Client~requestCallback} callback The callback to for when the
  566. * response is received
  567. * @return {grpc~ClientWritableStream} An event emitter for stream related
  568. * events
  569. */
  570. Client.prototype.makeClientStreamRequest = function(method, serialize,
  571. deserialize, metadata,
  572. options, callback) {
  573. /* While the arguments are listed in the function signature, those variables
  574. * are not used directly. Instead, ArgueJS processes the arguments
  575. * object. This allows for simple handling of optional arguments in the
  576. * middle of the argument list, and also provides type checking. */
  577. var args = arguejs({method:String, serialize: Function,
  578. deserialize: Function,
  579. metadata: [Metadata, new Metadata()],
  580. options: [Object], callback: Function}, arguments);
  581. var call = getCall(this.$channel, method, args.options);
  582. metadata = args.metadata.clone();
  583. var stream = new ClientWritableStream(call, serialize);
  584. var metadata_batch = {};
  585. metadata_batch[grpc.opType.SEND_INITIAL_METADATA] =
  586. metadata._getCoreRepresentation();
  587. metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
  588. call.startBatch(metadata_batch, function(err, response) {
  589. if (err) {
  590. // The call has stopped for some reason. A non-OK status will arrive
  591. // in the other batch.
  592. return;
  593. }
  594. stream.emit('metadata', Metadata._fromCoreRepresentation(
  595. response.metadata));
  596. });
  597. var client_batch = {};
  598. client_batch[grpc.opType.RECV_MESSAGE] = true;
  599. client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
  600. call.startBatch(client_batch, function(err, response) {
  601. response.status.metadata = Metadata._fromCoreRepresentation(
  602. response.status.metadata);
  603. var status = response.status;
  604. var error;
  605. var deserialized;
  606. if (status.code === constants.status.OK) {
  607. if (err) {
  608. // Got a batch error, but OK status. Something went wrong
  609. args.callback(err);
  610. return;
  611. } else {
  612. try {
  613. deserialized = deserialize(response.read);
  614. } catch (e) {
  615. /* Change status to indicate bad server response. This will result
  616. * in passing an error to the callback */
  617. status = {
  618. code: constants.status.INTERNAL,
  619. details: 'Failed to parse server response'
  620. };
  621. }
  622. }
  623. }
  624. if (status.code !== constants.status.OK) {
  625. error = new Error(response.status.details);
  626. error.code = status.code;
  627. error.metadata = status.metadata;
  628. args.callback(error);
  629. } else {
  630. args.callback(null, deserialized);
  631. }
  632. stream.emit('status', status);
  633. });
  634. return stream;
  635. };
  636. /**
  637. * Make a server stream request to the given method, with the given serialize
  638. * and deserialize function, using the given argument
  639. * @param {string} method The name of the method to request
  640. * @param {grpc~serialize} serialize The serialization function for inputs
  641. * @param {grpc~deserialize} deserialize The deserialization
  642. * function for outputs
  643. * @param {*} argument The argument to the call. Should be serializable with
  644. * serialize
  645. * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to
  646. * the call
  647. * @param {grpc.Client~CallOptions=} options Options map
  648. * @return {grpc~ClientReadableStream} An event emitter for stream related
  649. * events
  650. */
  651. Client.prototype.makeServerStreamRequest = function(method, serialize,
  652. deserialize, argument,
  653. metadata, options) {
  654. /* While the arguments are listed in the function signature, those variables
  655. * are not used directly. Instead, ArgueJS processes the arguments
  656. * object. */
  657. var args = arguejs({method:String, serialize: Function,
  658. deserialize: Function,
  659. argument: null, metadata: [Metadata, new Metadata()],
  660. options: [Object]}, arguments);
  661. var call = getCall(this.$channel, method, args.options);
  662. metadata = args.metadata.clone();
  663. var stream = new ClientReadableStream(call, deserialize);
  664. var start_batch = {};
  665. var message = serialize(args.argument);
  666. if (args.options) {
  667. message.grpcWriteFlags = args.options.flags;
  668. }
  669. start_batch[grpc.opType.SEND_INITIAL_METADATA] =
  670. metadata._getCoreRepresentation();
  671. start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
  672. start_batch[grpc.opType.SEND_MESSAGE] = message;
  673. start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
  674. call.startBatch(start_batch, function(err, response) {
  675. if (err) {
  676. // The call has stopped for some reason. A non-OK status will arrive
  677. // in the other batch.
  678. return;
  679. }
  680. stream.emit('metadata', Metadata._fromCoreRepresentation(
  681. response.metadata));
  682. });
  683. var status_batch = {};
  684. status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
  685. call.startBatch(status_batch, function(err, response) {
  686. if (err) {
  687. stream.emit('error', err);
  688. return;
  689. }
  690. response.status.metadata = Metadata._fromCoreRepresentation(
  691. response.status.metadata);
  692. stream._receiveStatus(response.status);
  693. });
  694. return stream;
  695. };
  696. /**
  697. * Make a bidirectional stream request with this method on the given channel.
  698. * @param {string} method The name of the method to request
  699. * @param {grpc~serialize} serialize The serialization function for inputs
  700. * @param {grpc~deserialize} deserialize The deserialization
  701. * function for outputs
  702. * @param {grpc.Metadata=} metadata Array of metadata key/value
  703. * pairs to add to the call
  704. * @param {grpc.Client~CallOptions=} options Options map
  705. * @return {grpc~ClientDuplexStream} An event emitter for stream related events
  706. */
  707. Client.prototype.makeBidiStreamRequest = function(method, serialize,
  708. deserialize, metadata,
  709. options) {
  710. /* While the arguments are listed in the function signature, those variables
  711. * are not used directly. Instead, ArgueJS processes the arguments
  712. * object. */
  713. var args = arguejs({method:String, serialize: Function,
  714. deserialize: Function,
  715. metadata: [Metadata, new Metadata()],
  716. options: [Object]}, arguments);
  717. var call = getCall(this.$channel, method, args.options);
  718. metadata = args.metadata.clone();
  719. var stream = new ClientDuplexStream(call, serialize, deserialize);
  720. var start_batch = {};
  721. start_batch[grpc.opType.SEND_INITIAL_METADATA] =
  722. metadata._getCoreRepresentation();
  723. start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
  724. call.startBatch(start_batch, function(err, response) {
  725. if (err) {
  726. // The call has stopped for some reason. A non-OK status will arrive
  727. // in the other batch.
  728. return;
  729. }
  730. stream.emit('metadata', Metadata._fromCoreRepresentation(
  731. response.metadata));
  732. });
  733. var status_batch = {};
  734. status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
  735. call.startBatch(status_batch, function(err, response) {
  736. if (err) {
  737. stream.emit('error', err);
  738. return;
  739. }
  740. response.status.metadata = Metadata._fromCoreRepresentation(
  741. response.status.metadata);
  742. stream._receiveStatus(response.status);
  743. });
  744. return stream;
  745. };
  746. /**
  747. * Close this client.
  748. */
  749. Client.prototype.close = function() {
  750. this.$channel.close();
  751. };
  752. /**
  753. * Return the underlying channel object for the specified client
  754. * @return {Channel} The channel
  755. */
  756. Client.prototype.getChannel = function() {
  757. return this.$channel;
  758. };
  759. /**
  760. * Wait for the client to be ready. The callback will be called when the
  761. * client has successfully connected to the server, and it will be called
  762. * with an error if the attempt to connect to the server has unrecoverablly
  763. * failed or if the deadline expires. This function will make the channel
  764. * start connecting if it has not already done so.
  765. * @param {grpc~Deadline} deadline When to stop waiting for a connection.
  766. * @param {function(Error)} callback The callback to call when done attempting
  767. * to connect.
  768. */
  769. Client.prototype.waitForReady = function(deadline, callback) {
  770. var self = this;
  771. var checkState = function(err) {
  772. if (err) {
  773. callback(new Error('Failed to connect before the deadline'));
  774. return;
  775. }
  776. var new_state = self.$channel.getConnectivityState(true);
  777. if (new_state === grpc.connectivityState.READY) {
  778. callback();
  779. } else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
  780. callback(new Error('Failed to connect to server'));
  781. } else {
  782. self.$channel.watchConnectivityState(new_state, deadline, checkState);
  783. }
  784. };
  785. checkState();
  786. };
  787. /**
  788. * Map with short names for each of the requester maker functions. Used in
  789. * makeClientConstructor
  790. * @private
  791. */
  792. var requester_funcs = {
  793. unary: Client.prototype.makeUnaryRequest,
  794. server_stream: Client.prototype.makeServerStreamRequest,
  795. client_stream: Client.prototype.makeClientStreamRequest,
  796. bidi: Client.prototype.makeBidiStreamRequest
  797. };
  798. function getDefaultValues(metadata, options) {
  799. var res = {};
  800. res.metadata = metadata || new Metadata();
  801. res.options = options || {};
  802. return res;
  803. }
  804. /**
  805. * Map with wrappers for each type of requester function to make it use the old
  806. * argument order with optional arguments after the callback.
  807. * @access private
  808. */
  809. var deprecated_request_wrap = {
  810. unary: function(makeUnaryRequest) {
  811. return function makeWrappedUnaryRequest(argument, callback,
  812. metadata, options) {
  813. /* jshint validthis: true */
  814. var opt_args = getDefaultValues(metadata, metadata);
  815. return makeUnaryRequest.call(this, argument, opt_args.metadata,
  816. opt_args.options, callback);
  817. };
  818. },
  819. client_stream: function(makeServerStreamRequest) {
  820. return function makeWrappedClientStreamRequest(callback, metadata,
  821. options) {
  822. /* jshint validthis: true */
  823. var opt_args = getDefaultValues(metadata, options);
  824. return makeServerStreamRequest.call(this, opt_args.metadata,
  825. opt_args.options, callback);
  826. };
  827. },
  828. server_stream: _.identity,
  829. bidi: _.identity
  830. };
  831. /**
  832. * Creates a constructor for a client with the given methods, as specified in
  833. * the methods argument. The resulting class will have an instance method for
  834. * each method in the service, which is a partial application of one of the
  835. * [Client]{@link grpc.Client} request methods, depending on `requestSerialize`
  836. * and `responseSerialize`, with the `method`, `serialize`, and `deserialize`
  837. * arguments predefined.
  838. * @memberof grpc
  839. * @alias grpc~makeGenericClientConstructor
  840. * @param {grpc~ServiceDefinition} methods An object mapping method names to
  841. * method attributes
  842. * @param {string} serviceName The fully qualified name of the service
  843. * @param {Object} class_options An options object.
  844. * @param {boolean=} [class_options.deprecatedArgumentOrder=false] Indicates
  845. * that the old argument order should be used for methods, with optional
  846. * arguments at the end instead of the callback at the end. This option
  847. * is only a temporary stopgap measure to smooth an API breakage.
  848. * It is deprecated, and new code should not use it.
  849. * @return {function} New client constructor, which is a subclass of
  850. * {@link grpc.Client}, and has the same arguments as that constructor.
  851. */
  852. exports.makeClientConstructor = function(methods, serviceName,
  853. class_options) {
  854. if (!class_options) {
  855. class_options = {};
  856. }
  857. function ServiceClient(address, credentials, options) {
  858. Client.call(this, address, credentials, options);
  859. }
  860. util.inherits(ServiceClient, Client);
  861. _.each(methods, function(attrs, name) {
  862. var method_type;
  863. if (_.startsWith(name, '$')) {
  864. throw new Error('Method names cannot start with $');
  865. }
  866. if (attrs.requestStream) {
  867. if (attrs.responseStream) {
  868. method_type = 'bidi';
  869. } else {
  870. method_type = 'client_stream';
  871. }
  872. } else {
  873. if (attrs.responseStream) {
  874. method_type = 'server_stream';
  875. } else {
  876. method_type = 'unary';
  877. }
  878. }
  879. var serialize = attrs.requestSerialize;
  880. var deserialize = attrs.responseDeserialize;
  881. var method_func = _.partial(requester_funcs[method_type], attrs.path,
  882. serialize, deserialize);
  883. if (class_options.deprecatedArgumentOrder) {
  884. ServiceClient.prototype[name] = deprecated_request_wrap(method_func);
  885. } else {
  886. ServiceClient.prototype[name] = method_func;
  887. }
  888. // Associate all provided attributes with the method
  889. _.assign(ServiceClient.prototype[name], attrs);
  890. });
  891. ServiceClient.service = methods;
  892. return ServiceClient;
  893. };
  894. /**
  895. * Return the underlying channel object for the specified client
  896. * @memberof grpc
  897. * @alias grpc~getClientChannel
  898. * @param {Client} client
  899. * @return {Channel} The channel
  900. * @see grpc.Client#getChannel
  901. */
  902. exports.getClientChannel = function(client) {
  903. return Client.prototype.getChannel.call(client);
  904. };
  905. /**
  906. * Wait for the client to be ready. The callback will be called when the
  907. * client has successfully connected to the server, and it will be called
  908. * with an error if the attempt to connect to the server has unrecoverablly
  909. * failed or if the deadline expires. This function will make the channel
  910. * start connecting if it has not already done so.
  911. * @memberof grpc
  912. * @alias grpc~waitForClientReady
  913. * @param {Client} client The client to wait on
  914. * @param {grpc~Deadline} deadline When to stop waiting for a connection. Pass
  915. * Infinity to wait forever.
  916. * @param {function(Error)} callback The callback to call when done attempting
  917. * to connect.
  918. * @see grpc.Client#waitForReady
  919. */
  920. exports.waitForClientReady = function(client, deadline, callback) {
  921. Client.prototype.waitForReady.call(client, deadline, callback);
  922. };
  923. </code></pre>
  924. </article>
  925. </section>
  926. </div>
  927. <nav>
  928. <h2><a href="index.html">Home</a></h2><h3>Externals</h3><ul><li><a href="external-Duplex.html">Duplex</a></li><li><a href="external-EventEmitter.html">EventEmitter</a></li><li><a href="external-GoogleCredential.html">GoogleCredential</a></li><li><a href="external-Readable.html">Readable</a></li><li><a href="external-Writable.html">Writable</a></li></ul><h3>Classes</h3><ul><li><a href="grpc.Client.html">Client</a></li><li><a href="grpc.credentials-CallCredentials.html">CallCredentials</a></li><li><a href="grpc.credentials-ChannelCredentials.html">ChannelCredentials</a></li><li><a href="grpc.Metadata.html">Metadata</a></li><li><a href="grpc.Server.html">Server</a></li><li><a href="grpc.ServerCredentials.html">ServerCredentials</a></li><li><a href="grpc-ClientDuplexStream.html">ClientDuplexStream</a></li><li><a href="grpc-ClientReadableStream.html">ClientReadableStream</a></li><li><a href="grpc-ClientUnaryCall.html">ClientUnaryCall</a></li><li><a href="grpc-ClientWritableStream.html">ClientWritableStream</a></li><li><a href="grpc-ServerDuplexStream.html">ServerDuplexStream</a></li><li><a href="grpc-ServerReadableStream.html">ServerReadableStream</a></li><li><a href="grpc-ServerUnaryCall.html">ServerUnaryCall</a></li><li><a href="grpc-ServerWritableStream.html">ServerWritableStream</a></li></ul><h3>Events</h3><ul><li><a href="grpc-ClientDuplexStream.html#event:metadata">metadata</a></li><li><a href="grpc-ClientDuplexStream.html#event:status">status</a></li><li><a href="grpc-ClientReadableStream.html#event:metadata">metadata</a></li><li><a href="grpc-ClientReadableStream.html#event:status">status</a></li><li><a href="grpc-ClientUnaryCall.html#event:metadata">metadata</a></li><li><a href="grpc-ClientUnaryCall.html#event:status">status</a></li><li><a href="grpc-ClientWritableStream.html#event:metadata">metadata</a></li><li><a href="grpc-ClientWritableStream.html#event:status">status</a></li><li><a href="grpc-ServerDuplexStream.html#~event:cancelled">cancelled</a></li><li><a href="grpc-ServerReadableStream.html#~event:cancelled">cancelled</a></li><li><a href="grpc-ServerUnaryCall.html#~event:cancelled">cancelled</a></li><li><a href="grpc-ServerWritableStream.html#~event:cancelled">cancelled</a></li></ul><h3>Namespaces</h3><ul><li><a href="grpc.html">grpc</a></li><li><a href="grpc.credentials.html">credentials</a></li></ul>
  929. </nav>
  930. <br class="clear">
  931. <footer>
  932. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Wed Jun 28 2017 09:44:06 GMT-0700 (PDT)
  933. </footer>
  934. <script> prettyPrint(); </script>
  935. <script src="scripts/linenumber.js"> </script>
  936. </body>
  937. </html>