blob: c682605b81deb5a909ad025e6124428fbc17e547 [file] [log] [blame]
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20/*jshint evil:true*/
21
22/**
Kazuki Matsudab909a382016-02-13 19:36:09 +090023 * The Thrift namespace houses the Apache Thrift JavaScript library
24 * elements providing JavaScript bindings for the Apache Thrift RPC
25 * system. End users will typically only directly make use of the
26 * Transport (TXHRTransport/TWebSocketTransport) and Protocol
henrique2a7dccc2014-03-07 22:16:51 +010027 * (TJSONPRotocol/TBinaryProtocol) constructors.
Kazuki Matsudab909a382016-02-13 19:36:09 +090028 *
29 * Object methods beginning with a __ (e.g. __onOpen()) are internal
henrique2a7dccc2014-03-07 22:16:51 +010030 * and should not be called outside of the object's own methods.
Kazuki Matsudab909a382016-02-13 19:36:09 +090031 *
henrique2a7dccc2014-03-07 22:16:51 +010032 * This library creates one global object: Thrift
33 * Code in this library must never create additional global identifiers,
34 * all features must be scoped within the Thrift namespace.
Henrique Mendonça095ddb72013-09-20 19:38:03 +020035 * @namespace
36 * @example
Kazuki Matsudab909a382016-02-13 19:36:09 +090037 * var transport = new Thrift.Transport('http://localhost:8585');
Henrique Mendonça095ddb72013-09-20 19:38:03 +020038 * var protocol = new Thrift.Protocol(transport);
39 * var client = new MyThriftSvcClient(protocol);
40 * var result = client.MyMethod();
41 */
42var Thrift = {
43 /**
44 * Thrift JavaScript library version.
45 * @readonly
46 * @const {string} Version
47 * @memberof Thrift
48 */
Jens Geyere02559f2019-10-17 00:11:59 +020049 Version: '0.14.0',
Henrique Mendonça095ddb72013-09-20 19:38:03 +020050
51 /**
52 * Thrift IDL type string to Id mapping.
53 * @readonly
54 * @property {number} STOP - End of a set of fields.
55 * @property {number} VOID - No value (only legal for return types).
56 * @property {number} BOOL - True/False integer.
57 * @property {number} BYTE - Signed 8 bit integer.
Kazuki Matsudab909a382016-02-13 19:36:09 +090058 * @property {number} I08 - Signed 8 bit integer.
Henrique Mendonça095ddb72013-09-20 19:38:03 +020059 * @property {number} DOUBLE - 64 bit IEEE 854 floating point.
60 * @property {number} I16 - Signed 16 bit integer.
61 * @property {number} I32 - Signed 32 bit integer.
62 * @property {number} I64 - Signed 64 bit integer.
63 * @property {number} STRING - Array of bytes representing a string of characters.
64 * @property {number} UTF7 - Array of bytes representing a string of UTF7 encoded characters.
65 * @property {number} STRUCT - A multifield type.
66 * @property {number} MAP - A collection type (map/associative-array/dictionary).
67 * @property {number} SET - A collection type (unordered and without repeated values).
68 * @property {number} LIST - A collection type (unordered).
69 * @property {number} UTF8 - Array of bytes representing a string of UTF8 encoded characters.
70 * @property {number} UTF16 - Array of bytes representing a string of UTF16 encoded characters.
71 */
72 Type: {
Kazuki Matsudab909a382016-02-13 19:36:09 +090073 STOP: 0,
74 VOID: 1,
75 BOOL: 2,
76 BYTE: 3,
77 I08: 3,
78 DOUBLE: 4,
79 I16: 6,
80 I32: 8,
81 I64: 10,
82 STRING: 11,
83 UTF7: 11,
84 STRUCT: 12,
85 MAP: 13,
86 SET: 14,
87 LIST: 15,
88 UTF8: 16,
89 UTF16: 17
Henrique Mendonça095ddb72013-09-20 19:38:03 +020090 },
91
92 /**
93 * Thrift RPC message type string to Id mapping.
94 * @readonly
95 * @property {number} CALL - RPC call sent from client to server.
96 * @property {number} REPLY - RPC call normal response from server to client.
97 * @property {number} EXCEPTION - RPC call exception response from server to client.
98 * @property {number} ONEWAY - Oneway RPC call from client to server with no response.
99 */
100 MessageType: {
Kazuki Matsudab909a382016-02-13 19:36:09 +0900101 CALL: 1,
102 REPLY: 2,
103 EXCEPTION: 3,
104 ONEWAY: 4
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200105 },
106
107 /**
108 * Utility function returning the count of an object's own properties.
109 * @param {object} obj - Object to test.
110 * @returns {number} number of object's own properties
111 */
112 objectLength: function(obj) {
113 var length = 0;
114 for (var k in obj) {
115 if (obj.hasOwnProperty(k)) {
116 length++;
117 }
118 }
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200119 return length;
120 },
121
122 /**
123 * Utility function to establish prototype inheritance.
124 * @see {@link http://javascript.crockford.com/prototypal.html|Prototypal Inheritance}
125 * @param {function} constructor - Contstructor function to set as derived.
126 * @param {function} superConstructor - Contstructor function to set as base.
127 * @param {string} [name] - Type name to set as name property in derived prototype.
128 */
129 inherits: function(constructor, superConstructor, name) {
130 function F() {}
131 F.prototype = superConstructor.prototype;
132 constructor.prototype = new F();
Kazuki Matsudab909a382016-02-13 19:36:09 +0900133 constructor.prototype.name = name || '';
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200134 }
135};
136
137/**
138 * Initializes a Thrift TException instance.
139 * @constructor
140 * @augments Error
141 * @param {string} message - The TException message (distinct from the Error message).
142 * @classdesc TException is the base class for all Thrift exceptions types.
143 */
144Thrift.TException = function(message) {
145 this.message = message;
146};
147Thrift.inherits(Thrift.TException, Error, 'TException');
148
149/**
150 * Returns the message set on the exception.
151 * @readonly
152 * @returns {string} exception message
153 */
154Thrift.TException.prototype.getMessage = function() {
155 return this.message;
156};
157
158/**
159 * Thrift Application Exception type string to Id mapping.
160 * @readonly
161 * @property {number} UNKNOWN - Unknown/undefined.
162 * @property {number} UNKNOWN_METHOD - Client attempted to call a method unknown to the server.
163 * @property {number} INVALID_MESSAGE_TYPE - Client passed an unknown/unsupported MessageType.
164 * @property {number} WRONG_METHOD_NAME - Unused.
165 * @property {number} BAD_SEQUENCE_ID - Unused in Thrift RPC, used to flag proprietary sequence number errors.
166 * @property {number} MISSING_RESULT - Raised by a server processor if a handler fails to supply the required return result.
167 * @property {number} INTERNAL_ERROR - Something bad happened.
168 * @property {number} PROTOCOL_ERROR - The protocol layer failed to serialize or deserialize data.
169 * @property {number} INVALID_TRANSFORM - Unused.
170 * @property {number} INVALID_PROTOCOL - The protocol (or version) is not supported.
171 * @property {number} UNSUPPORTED_CLIENT_TYPE - Unused.
172 */
173Thrift.TApplicationExceptionType = {
Kazuki Matsudab909a382016-02-13 19:36:09 +0900174 UNKNOWN: 0,
175 UNKNOWN_METHOD: 1,
176 INVALID_MESSAGE_TYPE: 2,
177 WRONG_METHOD_NAME: 3,
178 BAD_SEQUENCE_ID: 4,
179 MISSING_RESULT: 5,
180 INTERNAL_ERROR: 6,
181 PROTOCOL_ERROR: 7,
182 INVALID_TRANSFORM: 8,
183 INVALID_PROTOCOL: 9,
184 UNSUPPORTED_CLIENT_TYPE: 10
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200185};
186
187/**
188 * Initializes a Thrift TApplicationException instance.
189 * @constructor
190 * @augments Thrift.TException
191 * @param {string} message - The TApplicationException message (distinct from the Error message).
192 * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code.
193 * @classdesc TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client.
194*/
195Thrift.TApplicationException = function(message, code) {
196 this.message = message;
Kazuki Matsudab909a382016-02-13 19:36:09 +0900197 this.code = typeof code === 'number' ? code : 0;
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200198};
199Thrift.inherits(Thrift.TApplicationException, Thrift.TException, 'TApplicationException');
200
201/**
202 * Read a TApplicationException from the supplied protocol.
203 * @param {object} input - The input protocol to read from.
204 */
205Thrift.TApplicationException.prototype.read = function(input) {
206 while (1) {
207 var ret = input.readFieldBegin();
208
209 if (ret.ftype == Thrift.Type.STOP) {
210 break;
211 }
212
213 var fid = ret.fid;
214
215 switch (fid) {
216 case 1:
217 if (ret.ftype == Thrift.Type.STRING) {
218 ret = input.readString();
219 this.message = ret.value;
220 } else {
221 ret = input.skip(ret.ftype);
222 }
223 break;
224 case 2:
225 if (ret.ftype == Thrift.Type.I32) {
226 ret = input.readI32();
227 this.code = ret.value;
228 } else {
229 ret = input.skip(ret.ftype);
230 }
231 break;
232 default:
233 ret = input.skip(ret.ftype);
234 break;
235 }
236
237 input.readFieldEnd();
238 }
239
240 input.readStructEnd();
241};
242
243/**
244 * Wite a TApplicationException to the supplied protocol.
245 * @param {object} output - The output protocol to write to.
246 */
247Thrift.TApplicationException.prototype.write = function(output) {
248 output.writeStructBegin('TApplicationException');
249
250 if (this.message) {
251 output.writeFieldBegin('message', Thrift.Type.STRING, 1);
252 output.writeString(this.getMessage());
253 output.writeFieldEnd();
254 }
255
256 if (this.code) {
257 output.writeFieldBegin('type', Thrift.Type.I32, 2);
258 output.writeI32(this.code);
259 output.writeFieldEnd();
260 }
261
262 output.writeFieldStop();
263 output.writeStructEnd();
264};
265
266/**
267 * Returns the application exception code set on the exception.
268 * @readonly
269 * @returns {Thrift.TApplicationExceptionType} exception code
270 */
271Thrift.TApplicationException.prototype.getCode = function() {
272 return this.code;
273};
274
Liyin Tangf5399b22016-03-05 14:54:53 -0800275Thrift.TProtocolExceptionType = {
276 UNKNOWN: 0,
277 INVALID_DATA: 1,
278 NEGATIVE_SIZE: 2,
279 SIZE_LIMIT: 3,
280 BAD_VERSION: 4,
281 NOT_IMPLEMENTED: 5,
282 DEPTH_LIMIT: 6
283};
284
285Thrift.TProtocolException = function TProtocolException(type, message) {
286 Error.call(this);
Márton Csordásdfd6df72020-04-02 12:23:22 +0200287 if (Error.captureStackTrace) {
288 Error.captureStackTrace(this, this.constructor);
289 }
290
Liyin Tangf5399b22016-03-05 14:54:53 -0800291 this.name = this.constructor.name;
292 this.type = type;
293 this.message = message;
294};
295Thrift.inherits(Thrift.TProtocolException, Thrift.TException, 'TProtocolException');
296
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200297/**
henrique2a7dccc2014-03-07 22:16:51 +0100298 * Constructor Function for the XHR transport.
299 * If you do not specify a url then you must handle XHR operations on
300 * your own. This type can also be constructed using the Transport alias
301 * for backward compatibility.
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200302 * @constructor
303 * @param {string} [url] - The URL to connect to.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900304 * @classdesc The Apache Thrift Transport layer performs byte level I/O
305 * between RPC clients and servers. The JavaScript TXHRTransport object
henrique2a7dccc2014-03-07 22:16:51 +0100306 * uses Http[s]/XHR. Target servers must implement the http[s] transport
307 * (see: node.js example server_http.js).
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200308 * @example
henrique2a7dccc2014-03-07 22:16:51 +0100309 * var transport = new Thrift.TXHRTransport("http://localhost:8585");
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200310 */
Roger Meier52744ee2014-03-12 09:38:42 +0100311Thrift.Transport = Thrift.TXHRTransport = function(url, options) {
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200312 this.url = url;
313 this.wpos = 0;
314 this.rpos = 0;
Roger Meier52744ee2014-03-12 09:38:42 +0100315 this.useCORS = (options && options.useCORS);
Randy Abernethy3ca89e62016-04-13 06:24:57 -0700316 this.customHeaders = options ? (options.customHeaders ? options.customHeaders : {}): {};
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200317 this.send_buf = '';
318 this.recv_buf = '';
319};
320
henrique2a7dccc2014-03-07 22:16:51 +0100321Thrift.TXHRTransport.prototype = {
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200322 /**
323 * Gets the browser specific XmlHttpRequest Object.
324 * @returns {object} the browser XHR interface object
325 */
326 getXmlHttpRequestObject: function() {
327 try { return new XMLHttpRequest(); } catch (e1) { }
328 try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
329 try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
330
331 throw "Your browser doesn't support XHR.";
332 },
333
334 /**
Kazuki Matsudab909a382016-02-13 19:36:09 +0900335 * Sends the current XRH request if the transport was created with a URL
henrique2a7dccc2014-03-07 22:16:51 +0100336 * and the async parameter is false. If the transport was not created with
Kazuki Matsudab909a382016-02-13 19:36:09 +0900337 * a URL, or the async parameter is True and no callback is provided, or
henrique2a7dccc2014-03-07 22:16:51 +0100338 * the URL is an empty string, the current send buffer is returned.
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200339 * @param {object} async - If true the current send buffer is returned.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900340 * @param {object} callback - Optional async completion callback
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200341 * @returns {undefined|string} Nothing or the current send buffer.
342 * @throws {string} If XHR fails.
343 */
henriquea2de4102014-02-07 14:12:56 +0100344 flush: function(async, callback) {
henrique2a7dccc2014-03-07 22:16:51 +0100345 var self = this;
henriquea2de4102014-02-07 14:12:56 +0100346 if ((async && !callback) || this.url === undefined || this.url === '') {
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200347 return this.send_buf;
348 }
349
350 var xreq = this.getXmlHttpRequestObject();
351
352 if (xreq.overrideMimeType) {
henriqueeec445e2015-05-04 21:37:51 +1000353 xreq.overrideMimeType('application/vnd.apache.thrift.json; charset=utf-8');
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200354 }
355
henriquea2de4102014-02-07 14:12:56 +0100356 if (callback) {
henrique2a7dccc2014-03-07 22:16:51 +0100357 //Ignore XHR callbacks until the data arrives, then call the
358 // client's callback
Kazuki Matsudab909a382016-02-13 19:36:09 +0900359 xreq.onreadystatechange =
henrique2a7dccc2014-03-07 22:16:51 +0100360 (function() {
Kazuki Matsudab909a382016-02-13 19:36:09 +0900361 var clientCallback = callback;
henrique2a7dccc2014-03-07 22:16:51 +0100362 return function() {
363 if (this.readyState == 4 && this.status == 200) {
364 self.setRecvBuffer(this.responseText);
365 clientCallback();
366 }
367 };
368 }());
HIRANO Satoshi84cf3632015-12-07 17:17:15 +0900369
370 // detect net::ERR_CONNECTION_REFUSED and call the callback.
371 xreq.onerror =
372 (function() {
373 var clientCallback = callback;
374 return function() {
375 clientCallback();
376 };
377 }());
378
henriquea2de4102014-02-07 14:12:56 +0100379 }
380
381 xreq.open('POST', this.url, !!async);
henriqueeec445e2015-05-04 21:37:51 +1000382
Randy Abernethy3ca89e62016-04-13 06:24:57 -0700383 // add custom headers
384 Object.keys(self.customHeaders).forEach(function(prop) {
385 xreq.setRequestHeader(prop, self.customHeaders[prop]);
386 });
387
henriqueeec445e2015-05-04 21:37:51 +1000388 if (xreq.setRequestHeader) {
389 xreq.setRequestHeader('Accept', 'application/vnd.apache.thrift.json; charset=utf-8');
390 xreq.setRequestHeader('Content-Type', 'application/vnd.apache.thrift.json; charset=utf-8');
391 }
392
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200393 xreq.send(this.send_buf);
henriquea2de4102014-02-07 14:12:56 +0100394 if (async && callback) {
395 return;
396 }
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200397
398 if (xreq.readyState != 4) {
399 throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
400 }
401
402 if (xreq.status != 200) {
403 throw 'encountered a unknown request status: ' + xreq.status;
404 }
405
406 this.recv_buf = xreq.responseText;
407 this.recv_buf_sz = this.recv_buf.length;
408 this.wpos = this.recv_buf.length;
409 this.rpos = 0;
410 },
411
412 /**
413 * Creates a jQuery XHR object to be used for a Thrift server call.
414 * @param {object} client - The Thrift Service client object generated by the IDL compiler.
415 * @param {object} postData - The message to send to the server.
henrique2a7dccc2014-03-07 22:16:51 +0100416 * @param {function} args - The original call arguments with the success call back at the end.
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200417 * @param {function} recv_method - The Thrift Service Client receive method for the call.
418 * @returns {object} A new jQuery XHR object.
419 * @throws {string} If the jQuery version is prior to 1.5 or if jQuery is not found.
420 */
421 jqRequest: function(client, postData, args, recv_method) {
422 if (typeof jQuery === 'undefined' ||
423 typeof jQuery.Deferred === 'undefined') {
424 throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
425 }
426
427 var thriftTransport = this;
428
429 var jqXHR = jQuery.ajax({
430 url: this.url,
431 data: postData,
432 type: 'POST',
433 cache: false,
henriqueeec445e2015-05-04 21:37:51 +1000434 contentType: 'application/vnd.apache.thrift.json; charset=utf-8',
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200435 dataType: 'text thrift',
436 converters: {
437 'text thrift' : function(responseData) {
438 thriftTransport.setRecvBuffer(responseData);
439 var value = recv_method.call(client);
440 return value;
441 }
442 },
443 context: client,
Christian Bürckertf61d9e52019-01-14 14:36:22 +0100444 success: jQuery.makeArray(args).pop(),
445 beforeSend: function (xreq) {
446 Object.keys(thriftTransport.customHeaders).forEach(function (prop) {
447 xreq.setRequestHeader(prop, thriftTransport.customHeaders[prop]);
448 });
449 }
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200450 });
451
452 return jqXHR;
453 },
454
455 /**
henrique2a7dccc2014-03-07 22:16:51 +0100456 * Sets the buffer to provide the protocol when deserializing.
457 * @param {string} buf - The buffer to supply the protocol.
458 */
459 setRecvBuffer: function(buf) {
460 this.recv_buf = buf;
461 this.recv_buf_sz = this.recv_buf.length;
462 this.wpos = this.recv_buf.length;
463 this.rpos = 0;
464 },
465
466 /**
467 * Returns true if the transport is open, XHR always returns true.
468 * @readonly
469 * @returns {boolean} Always True.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900470 */
henrique2a7dccc2014-03-07 22:16:51 +0100471 isOpen: function() {
472 return true;
473 },
474
475 /**
476 * Opens the transport connection, with XHR this is a nop.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900477 */
henrique2a7dccc2014-03-07 22:16:51 +0100478 open: function() {},
479
480 /**
481 * Closes the transport connection, with XHR this is a nop.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900482 */
henrique2a7dccc2014-03-07 22:16:51 +0100483 close: function() {},
484
485 /**
486 * Returns the specified number of characters from the response
487 * buffer.
488 * @param {number} len - The number of characters to return.
489 * @returns {string} Characters sent by the server.
490 */
491 read: function(len) {
492 var avail = this.wpos - this.rpos;
493
494 if (avail === 0) {
495 return '';
496 }
497
498 var give = len;
499
500 if (avail < len) {
501 give = avail;
502 }
503
504 var ret = this.read_buf.substr(this.rpos, give);
505 this.rpos += give;
506
507 //clear buf when complete?
508 return ret;
509 },
510
511 /**
512 * Returns the entire response buffer.
513 * @returns {string} Characters sent by the server.
514 */
515 readAll: function() {
516 return this.recv_buf;
517 },
518
519 /**
520 * Sets the send buffer to buf.
521 * @param {string} buf - The buffer to send.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900522 */
henrique2a7dccc2014-03-07 22:16:51 +0100523 write: function(buf) {
524 this.send_buf = buf;
525 },
526
527 /**
528 * Returns the send buffer.
529 * @readonly
530 * @returns {string} The send buffer.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900531 */
henrique2a7dccc2014-03-07 22:16:51 +0100532 getSendBuffer: function() {
533 return this.send_buf;
534 }
535
536};
537
538
539/**
540 * Constructor Function for the WebSocket transport.
541 * @constructor
542 * @param {string} [url] - The URL to connect to.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900543 * @classdesc The Apache Thrift Transport layer performs byte level I/O
544 * between RPC clients and servers. The JavaScript TWebSocketTransport object
henrique2a7dccc2014-03-07 22:16:51 +0100545 * uses the WebSocket protocol. Target servers must implement WebSocket.
546 * (see: node.js example server_http.js).
547 * @example
548 * var transport = new Thrift.TWebSocketTransport("http://localhost:8585");
549 */
550Thrift.TWebSocketTransport = function(url) {
551 this.__reset(url);
552};
553
554Thrift.TWebSocketTransport.prototype = {
555 __reset: function(url) {
556 this.url = url; //Where to connect
557 this.socket = null; //The web socket
558 this.callbacks = []; //Pending callbacks
559 this.send_pending = []; //Buffers/Callback pairs waiting to be sent
560 this.send_buf = ''; //Outbound data, immutable until sent
561 this.recv_buf = ''; //Inbound data
562 this.rb_wpos = 0; //Network write position in receive buffer
563 this.rb_rpos = 0; //Client read position in receive buffer
564 },
565
566 /**
Kazuki Matsudab909a382016-02-13 19:36:09 +0900567 * Sends the current WS request and registers callback. The async
568 * parameter is ignored (WS flush is always async) and the callback
henrique2a7dccc2014-03-07 22:16:51 +0100569 * function parameter is required.
570 * @param {object} async - Ignored.
571 * @param {object} callback - The client completion callback.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900572 * @returns {undefined|string} Nothing (undefined)
henrique2a7dccc2014-03-07 22:16:51 +0100573 */
574 flush: function(async, callback) {
575 var self = this;
576 if (this.isOpen()) {
577 //Send data and register a callback to invoke the client callback
Kazuki Matsudab909a382016-02-13 19:36:09 +0900578 this.socket.send(this.send_buf);
henrique2a7dccc2014-03-07 22:16:51 +0100579 this.callbacks.push((function() {
Kazuki Matsudab909a382016-02-13 19:36:09 +0900580 var clientCallback = callback;
henrique2a7dccc2014-03-07 22:16:51 +0100581 return function(msg) {
582 self.setRecvBuffer(msg);
Philip Frank0a84eae2017-12-27 12:54:28 +0100583 if (clientCallback) {
584 clientCallback();
585 }
henrique2a7dccc2014-03-07 22:16:51 +0100586 };
587 }()));
588 } else {
589 //Queue the send to go out __onOpen
590 this.send_pending.push({
591 buf: this.send_buf,
Kazuki Matsudab909a382016-02-13 19:36:09 +0900592 cb: callback
henrique2a7dccc2014-03-07 22:16:51 +0100593 });
594 }
595 },
596
Kazuki Matsudab909a382016-02-13 19:36:09 +0900597 __onOpen: function() {
henrique2a7dccc2014-03-07 22:16:51 +0100598 var self = this;
599 if (this.send_pending.length > 0) {
Kazuki Matsudab909a382016-02-13 19:36:09 +0900600 //If the user made calls before the connection was fully
henrique2a7dccc2014-03-07 22:16:51 +0100601 //open, send them now
602 this.send_pending.forEach(function(elem) {
Philip Frank05a08ce2017-12-04 13:29:58 +0100603 self.socket.send(elem.buf);
604 self.callbacks.push((function() {
Kazuki Matsudab909a382016-02-13 19:36:09 +0900605 var clientCallback = elem.cb;
henrique2a7dccc2014-03-07 22:16:51 +0100606 return function(msg) {
607 self.setRecvBuffer(msg);
608 clientCallback();
609 };
610 }()));
611 });
612 this.send_pending = [];
613 }
614 },
Kazuki Matsudab909a382016-02-13 19:36:09 +0900615
616 __onClose: function(evt) {
henrique2a7dccc2014-03-07 22:16:51 +0100617 this.__reset(this.url);
618 },
Kazuki Matsudab909a382016-02-13 19:36:09 +0900619
henrique2a7dccc2014-03-07 22:16:51 +0100620 __onMessage: function(evt) {
621 if (this.callbacks.length) {
622 this.callbacks.shift()(evt.data);
623 }
624 },
Kazuki Matsudab909a382016-02-13 19:36:09 +0900625
626 __onError: function(evt) {
627 console.log('Thrift WebSocket Error: ' + evt.toString());
henrique2a7dccc2014-03-07 22:16:51 +0100628 this.socket.close();
629 },
630
631 /**
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200632 * Sets the buffer to use when receiving server responses.
633 * @param {string} buf - The buffer to receive server responses.
634 */
635 setRecvBuffer: function(buf) {
636 this.recv_buf = buf;
637 this.recv_buf_sz = this.recv_buf.length;
638 this.wpos = this.recv_buf.length;
639 this.rpos = 0;
640 },
641
642 /**
henrique2a7dccc2014-03-07 22:16:51 +0100643 * Returns true if the transport is open
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200644 * @readonly
Kazuki Matsudab909a382016-02-13 19:36:09 +0900645 * @returns {boolean}
646 */
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200647 isOpen: function() {
henrique2a7dccc2014-03-07 22:16:51 +0100648 return this.socket && this.socket.readyState == this.socket.OPEN;
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200649 },
650
651 /**
henrique2a7dccc2014-03-07 22:16:51 +0100652 * Opens the transport connection
Kazuki Matsudab909a382016-02-13 19:36:09 +0900653 */
henrique2a7dccc2014-03-07 22:16:51 +0100654 open: function() {
655 //If OPEN/CONNECTING/CLOSING ignore additional opens
656 if (this.socket && this.socket.readyState != this.socket.CLOSED) {
657 return;
658 }
659 //If there is no socket or the socket is closed:
660 this.socket = new WebSocket(this.url);
Kazuki Matsudab909a382016-02-13 19:36:09 +0900661 this.socket.onopen = this.__onOpen.bind(this);
662 this.socket.onmessage = this.__onMessage.bind(this);
663 this.socket.onerror = this.__onError.bind(this);
664 this.socket.onclose = this.__onClose.bind(this);
henrique2a7dccc2014-03-07 22:16:51 +0100665 },
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200666
667 /**
henrique2a7dccc2014-03-07 22:16:51 +0100668 * Closes the transport connection
Kazuki Matsudab909a382016-02-13 19:36:09 +0900669 */
henrique2a7dccc2014-03-07 22:16:51 +0100670 close: function() {
671 this.socket.close();
672 },
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200673
674 /**
675 * Returns the specified number of characters from the response
676 * buffer.
677 * @param {number} len - The number of characters to return.
678 * @returns {string} Characters sent by the server.
679 */
680 read: function(len) {
681 var avail = this.wpos - this.rpos;
682
683 if (avail === 0) {
684 return '';
685 }
686
687 var give = len;
688
689 if (avail < len) {
690 give = avail;
691 }
692
693 var ret = this.read_buf.substr(this.rpos, give);
694 this.rpos += give;
695
696 //clear buf when complete?
697 return ret;
698 },
699
700 /**
701 * Returns the entire response buffer.
702 * @returns {string} Characters sent by the server.
703 */
704 readAll: function() {
705 return this.recv_buf;
706 },
707
708 /**
709 * Sets the send buffer to buf.
710 * @param {string} buf - The buffer to send.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900711 */
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200712 write: function(buf) {
713 this.send_buf = buf;
714 },
715
716 /**
717 * Returns the send buffer.
718 * @readonly
719 * @returns {string} The send buffer.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900720 */
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200721 getSendBuffer: function() {
722 return this.send_buf;
723 }
724
725};
726
727/**
728 * Initializes a Thrift JSON protocol instance.
729 * @constructor
730 * @param {Thrift.Transport} transport - The transport to serialize to/from.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900731 * @classdesc Apache Thrift Protocols perform serialization which enables cross
732 * language RPC. The Protocol type is the JavaScript browser implementation
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200733 * of the Apache Thrift TJSONProtocol.
734 * @example
735 * var protocol = new Thrift.Protocol(transport);
736 */
Roger Meier52744ee2014-03-12 09:38:42 +0100737Thrift.TJSONProtocol = Thrift.Protocol = function(transport) {
radekg1d305582015-01-01 20:35:01 +0100738 this.tstack = [];
739 this.tpos = [];
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200740 this.transport = transport;
741};
742
743/**
744 * Thrift IDL type Id to string mapping.
745 * @readonly
746 * @see {@link Thrift.Type}
747 */
748Thrift.Protocol.Type = {};
749Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"';
750Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"';
751Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"';
752Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"';
753Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"';
754Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"';
755Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"';
756Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"';
757Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"';
758Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"';
759Thrift.Protocol.Type[Thrift.Type.SET] = '"set"';
760
761/**
762 * Thrift IDL type string to Id mapping.
763 * @readonly
764 * @see {@link Thrift.Type}
765 */
766Thrift.Protocol.RType = {};
767Thrift.Protocol.RType.tf = Thrift.Type.BOOL;
768Thrift.Protocol.RType.i8 = Thrift.Type.BYTE;
769Thrift.Protocol.RType.i16 = Thrift.Type.I16;
770Thrift.Protocol.RType.i32 = Thrift.Type.I32;
771Thrift.Protocol.RType.i64 = Thrift.Type.I64;
772Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE;
773Thrift.Protocol.RType.rec = Thrift.Type.STRUCT;
774Thrift.Protocol.RType.str = Thrift.Type.STRING;
775Thrift.Protocol.RType.map = Thrift.Type.MAP;
776Thrift.Protocol.RType.lst = Thrift.Type.LIST;
777Thrift.Protocol.RType.set = Thrift.Type.SET;
778
779/**
780 * The TJSONProtocol version number.
781 * @readonly
782 * @const {number} Version
783 * @memberof Thrift.Protocol
784 */
785 Thrift.Protocol.Version = 1;
786
787Thrift.Protocol.prototype = {
788 /**
789 * Returns the underlying transport.
790 * @readonly
791 * @returns {Thrift.Transport} The underlying transport.
Kazuki Matsudab909a382016-02-13 19:36:09 +0900792 */
Henrique Mendonça095ddb72013-09-20 19:38:03 +0200793 getTransport: function() {
794 return this.transport;
795 },
796
797 /**
798 * Serializes the beginning of a Thrift RPC message.
799 * @param {string} name - The service method to call.
800 * @param {Thrift.MessageType} messageType - The type of method call.
801 * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift).
802 */
803 writeMessageBegin: function(name, messageType, seqid) {
804 this.tstack = [];
805 this.tpos = [];
806
807 this.tstack.push([Thrift.Protocol.Version, '"' +
808 name + '"', messageType, seqid]);
809 },
810
811 /**
812 * Serializes the end of a Thrift RPC message.
813 */
814 writeMessageEnd: function() {
815 var obj = this.tstack.pop();
816
817 this.wobj = this.tstack.pop();
818 this.wobj.push(obj);
819
820 this.wbuf = '[' + this.wobj.join(',') + ']';
821
822 this.transport.write(this.wbuf);
823 },
824
825
826 /**
827 * Serializes the beginning of a struct.
828 * @param {string} name - The name of the struct.
829 */
830 writeStructBegin: function(name) {
831 this.tpos.push(this.tstack.length);
832 this.tstack.push({});
833 },
834
835 /**
836 * Serializes the end of a struct.
837 */
838 writeStructEnd: function() {
839
840 var p = this.tpos.pop();
841 var struct = this.tstack[p];
842 var str = '{';
843 var first = true;
844 for (var key in struct) {
845 if (first) {
846 first = false;
847 } else {
848 str += ',';
849 }
850
851 str += key + ':' + struct[key];
852 }
853
854 str += '}';
855 this.tstack[p] = str;
856 },
857
858 /**
859 * Serializes the beginning of a struct field.
860 * @param {string} name - The name of the field.
861 * @param {Thrift.Protocol.Type} fieldType - The data type of the field.
862 * @param {number} fieldId - The field's unique identifier.
863 */
864 writeFieldBegin: function(name, fieldType, fieldId) {
865 this.tpos.push(this.tstack.length);
866 this.tstack.push({ 'fieldId': '"' +
867 fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType]
868 });
869
870 },
871
872 /**
873 * Serializes the end of a field.
874 */
875 writeFieldEnd: function() {
876 var value = this.tstack.pop();
877 var fieldInfo = this.tstack.pop();
878
879 this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
880 fieldInfo.fieldType + ':' + value + '}';
881 this.tpos.pop();
882 },
883
884 /**
885 * Serializes the end of the set of fields for a struct.
886 */
887 writeFieldStop: function() {
888 //na
889 },
890
891 /**
892 * Serializes the beginning of a map collection.
893 * @param {Thrift.Type} keyType - The data type of the key.
894 * @param {Thrift.Type} valType - The data type of the value.
895 * @param {number} [size] - The number of elements in the map (ignored).
896 */
897 writeMapBegin: function(keyType, valType, size) {
898 this.tpos.push(this.tstack.length);
899 this.tstack.push([Thrift.Protocol.Type[keyType],
900 Thrift.Protocol.Type[valType], 0]);
901 },
902
903 /**
904 * Serializes the end of a map.
905 */
906 writeMapEnd: function() {
907 var p = this.tpos.pop();
908
909 if (p == this.tstack.length) {
910 return;
911 }
912
913 if ((this.tstack.length - p - 1) % 2 !== 0) {
914 this.tstack.push('');
915 }
916
917 var size = (this.tstack.length - p - 1) / 2;
918
919 this.tstack[p][this.tstack[p].length - 1] = size;
920
921 var map = '}';
922 var first = true;
923 while (this.tstack.length > p + 1) {
924 var v = this.tstack.pop();
925 var k = this.tstack.pop();
926 if (first) {
927 first = false;
928 } else {
929 map = ',' + map;
930 }
931
932 if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
933 map = k + ':' + v + map;
934 }
935 map = '{' + map;
936
937 this.tstack[p].push(map);
938 this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
939 },
940
941 /**
942 * Serializes the beginning of a list collection.
943 * @param {Thrift.Type} elemType - The data type of the elements.
944 * @param {number} size - The number of elements in the list.
945 */
946 writeListBegin: function(elemType, size) {
947 this.tpos.push(this.tstack.length);
948 this.tstack.push([Thrift.Protocol.Type[elemType], size]);
949 },
950
951 /**
952 * Serializes the end of a list.
953 */
954 writeListEnd: function() {
955 var p = this.tpos.pop();
956
957 while (this.tstack.length > p + 1) {
958 var tmpVal = this.tstack[p + 1];
959 this.tstack.splice(p + 1, 1);
960 this.tstack[p].push(tmpVal);
961 }
962
963 this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
964 },
965
966 /**
967 * Serializes the beginning of a set collection.
968 * @param {Thrift.Type} elemType - The data type of the elements.
969 * @param {number} size - The number of elements in the list.
970 */
971 writeSetBegin: function(elemType, size) {
972 this.tpos.push(this.tstack.length);
973 this.tstack.push([Thrift.Protocol.Type[elemType], size]);
974 },
975
976 /**
977 * Serializes the end of a set.
978 */
979 writeSetEnd: function() {
980 var p = this.tpos.pop();
981
982 while (this.tstack.length > p + 1) {
983 var tmpVal = this.tstack[p + 1];
984 this.tstack.splice(p + 1, 1);
985 this.tstack[p].push(tmpVal);
986 }
987
988 this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
989 },
990
991 /** Serializes a boolean */
992 writeBool: function(value) {
993 this.tstack.push(value ? 1 : 0);
994 },
995
996 /** Serializes a number */
997 writeByte: function(i8) {
998 this.tstack.push(i8);
999 },
1000
1001 /** Serializes a number */
1002 writeI16: function(i16) {
1003 this.tstack.push(i16);
1004 },
1005
1006 /** Serializes a number */
1007 writeI32: function(i32) {
1008 this.tstack.push(i32);
1009 },
1010
1011 /** Serializes a number */
1012 writeI64: function(i64) {
Mustafa Senol Cosarf86845e2018-12-05 17:50:18 +03001013 if (typeof i64 === 'number') {
1014 this.tstack.push(i64);
1015 } else {
1016 this.tstack.push(Int64Util.toDecimalString(i64));
1017 }
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001018 },
1019
1020 /** Serializes a number */
1021 writeDouble: function(dbl) {
1022 this.tstack.push(dbl);
1023 },
1024
1025 /** Serializes a string */
1026 writeString: function(str) {
1027 // We do not encode uri components for wire transfer:
1028 if (str === null) {
1029 this.tstack.push(null);
1030 } else {
1031 // concat may be slower than building a byte buffer
1032 var escapedString = '';
1033 for (var i = 0; i < str.length; i++) {
1034 var ch = str.charAt(i); // a single double quote: "
1035 if (ch === '\"') {
1036 escapedString += '\\\"'; // write out as: \"
Roger Meier52744ee2014-03-12 09:38:42 +01001037 } else if (ch === '\\') { // a single backslash
Kazuki Matsudab909a382016-02-13 19:36:09 +09001038 escapedString += '\\\\'; // write out as double backslash
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001039 } else if (ch === '\b') { // a single backspace: invisible
1040 escapedString += '\\b'; // write out as: \b"
1041 } else if (ch === '\f') { // a single formfeed: invisible
1042 escapedString += '\\f'; // write out as: \f"
1043 } else if (ch === '\n') { // a single newline: invisible
1044 escapedString += '\\n'; // write out as: \n"
1045 } else if (ch === '\r') { // a single return: invisible
1046 escapedString += '\\r'; // write out as: \r"
1047 } else if (ch === '\t') { // a single tab: invisible
1048 escapedString += '\\t'; // write out as: \t"
1049 } else {
1050 escapedString += ch; // Else it need not be escaped
1051 }
1052 }
1053 this.tstack.push('"' + escapedString + '"');
1054 }
1055 },
1056
1057 /** Serializes a string */
Nobuaki Sukegawa6defea52015-11-14 17:36:29 +09001058 writeBinary: function(binary) {
1059 var str = '';
1060 if (typeof binary == 'string') {
1061 str = binary;
1062 } else if (binary instanceof Uint8Array) {
1063 var arr = binary;
1064 for (var i = 0; i < arr.length; ++i) {
1065 str += String.fromCharCode(arr[i]);
1066 }
1067 } else {
1068 throw new TypeError('writeBinary only accepts String or Uint8Array.');
1069 }
1070 this.tstack.push('"' + btoa(str) + '"');
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001071 },
1072
1073 /**
1074 @class
1075 @name AnonReadMessageBeginReturn
1076 @property {string} fname - The name of the service method.
1077 @property {Thrift.MessageType} mtype - The type of message call.
1078 @property {number} rseqid - The sequence number of the message (0 in Thrift RPC).
1079 */
Kazuki Matsudab909a382016-02-13 19:36:09 +09001080 /**
1081 * Deserializes the beginning of a message.
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001082 * @returns {AnonReadMessageBeginReturn}
1083 */
1084 readMessageBegin: function() {
1085 this.rstack = [];
1086 this.rpos = [];
1087
Mustafa Senol Cosarf86845e2018-12-05 17:50:18 +03001088 received = this.transport.readAll();
1089
1090 if (typeof JSONInt64 !== 'undefined' && typeof JSONInt64.parse === 'function') {
1091 this.robj = JSONInt64.parse(received);
1092 } else if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') {
1093 this.robj = JSON.parse(received);
Roger Meier52744ee2014-03-12 09:38:42 +01001094 } else if (typeof jQuery !== 'undefined') {
Mustafa Senol Cosarf86845e2018-12-05 17:50:18 +03001095 this.robj = jQuery.parseJSON(received);
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001096 } else {
Mustafa Senol Cosarf86845e2018-12-05 17:50:18 +03001097 this.robj = eval(received);
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001098 }
1099
1100 var r = {};
1101 var version = this.robj.shift();
1102
1103 if (version != Thrift.Protocol.Version) {
1104 throw 'Wrong thrift protocol version: ' + version;
1105 }
1106
1107 r.fname = this.robj.shift();
1108 r.mtype = this.robj.shift();
1109 r.rseqid = this.robj.shift();
1110
1111
1112 //get to the main obj
1113 this.rstack.push(this.robj.shift());
1114
1115 return r;
1116 },
1117
1118 /** Deserializes the end of a message. */
1119 readMessageEnd: function() {
1120 },
1121
Kazuki Matsudab909a382016-02-13 19:36:09 +09001122 /**
1123 * Deserializes the beginning of a struct.
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001124 * @param {string} [name] - The name of the struct (ignored)
1125 * @returns {object} - An object with an empty string fname property
Kazuki Matsudab909a382016-02-13 19:36:09 +09001126 */
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001127 readStructBegin: function(name) {
1128 var r = {};
1129 r.fname = '';
1130
1131 //incase this is an array of structs
1132 if (this.rstack[this.rstack.length - 1] instanceof Array) {
1133 this.rstack.push(this.rstack[this.rstack.length - 1].shift());
1134 }
1135
1136 return r;
1137 },
1138
1139 /** Deserializes the end of a struct. */
1140 readStructEnd: function() {
1141 if (this.rstack[this.rstack.length - 2] instanceof Array) {
1142 this.rstack.pop();
1143 }
1144 },
1145
1146 /**
1147 @class
1148 @name AnonReadFieldBeginReturn
1149 @property {string} fname - The name of the field (always '').
1150 @property {Thrift.Type} ftype - The data type of the field.
1151 @property {number} fid - The unique identifier of the field.
1152 */
Kazuki Matsudab909a382016-02-13 19:36:09 +09001153 /**
1154 * Deserializes the beginning of a field.
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001155 * @returns {AnonReadFieldBeginReturn}
1156 */
1157 readFieldBegin: function() {
1158 var r = {};
1159
1160 var fid = -1;
1161 var ftype = Thrift.Type.STOP;
1162
1163 //get a fieldId
1164 for (var f in (this.rstack[this.rstack.length - 1])) {
1165 if (f === null) {
1166 continue;
1167 }
1168
1169 fid = parseInt(f, 10);
1170 this.rpos.push(this.rstack.length);
1171
1172 var field = this.rstack[this.rstack.length - 1][fid];
1173
1174 //remove so we don't see it again
1175 delete this.rstack[this.rstack.length - 1][fid];
1176
1177 this.rstack.push(field);
1178
1179 break;
1180 }
1181
1182 if (fid != -1) {
1183
1184 //should only be 1 of these but this is the only
1185 //way to match a key
1186 for (var i in (this.rstack[this.rstack.length - 1])) {
1187 if (Thrift.Protocol.RType[i] === null) {
1188 continue;
1189 }
1190
1191 ftype = Thrift.Protocol.RType[i];
1192 this.rstack[this.rstack.length - 1] =
1193 this.rstack[this.rstack.length - 1][i];
1194 }
1195 }
1196
1197 r.fname = '';
1198 r.ftype = ftype;
1199 r.fid = fid;
1200
1201 return r;
1202 },
1203
1204 /** Deserializes the end of a field. */
1205 readFieldEnd: function() {
1206 var pos = this.rpos.pop();
1207
1208 //get back to the right place in the stack
1209 while (this.rstack.length > pos) {
1210 this.rstack.pop();
1211 }
1212
1213 },
1214
1215 /**
1216 @class
1217 @name AnonReadMapBeginReturn
1218 @property {Thrift.Type} ktype - The data type of the key.
1219 @property {Thrift.Type} vtype - The data type of the value.
1220 @property {number} size - The number of elements in the map.
1221 */
Kazuki Matsudab909a382016-02-13 19:36:09 +09001222 /**
1223 * Deserializes the beginning of a map.
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001224 * @returns {AnonReadMapBeginReturn}
1225 */
1226 readMapBegin: function() {
1227 var map = this.rstack.pop();
Liangliang He5d6378f2014-08-19 18:25:37 +08001228 var first = map.shift();
1229 if (first instanceof Array) {
1230 this.rstack.push(map);
1231 map = first;
1232 first = map.shift();
1233 }
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001234
1235 var r = {};
Liangliang He5d6378f2014-08-19 18:25:37 +08001236 r.ktype = Thrift.Protocol.RType[first];
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001237 r.vtype = Thrift.Protocol.RType[map.shift()];
1238 r.size = map.shift();
1239
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001240 this.rpos.push(this.rstack.length);
1241 this.rstack.push(map.shift());
1242
1243 return r;
1244 },
1245
1246 /** Deserializes the end of a map. */
1247 readMapEnd: function() {
1248 this.readFieldEnd();
1249 },
1250
1251 /**
1252 @class
1253 @name AnonReadColBeginReturn
1254 @property {Thrift.Type} etype - The data type of the element.
1255 @property {number} size - The number of elements in the collection.
1256 */
Kazuki Matsudab909a382016-02-13 19:36:09 +09001257 /**
1258 * Deserializes the beginning of a list.
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001259 * @returns {AnonReadColBeginReturn}
1260 */
1261 readListBegin: function() {
1262 var list = this.rstack[this.rstack.length - 1];
1263
1264 var r = {};
1265 r.etype = Thrift.Protocol.RType[list.shift()];
1266 r.size = list.shift();
1267
1268 this.rpos.push(this.rstack.length);
Henrique Mendonça15d90422015-06-25 22:31:41 +10001269 this.rstack.push(list.shift());
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001270
1271 return r;
1272 },
1273
1274 /** Deserializes the end of a list. */
1275 readListEnd: function() {
Philip Frank55ddf192018-01-02 09:00:36 +01001276 var pos = this.rpos.pop() - 2;
1277 var st = this.rstack;
1278 st.pop();
1279 if (st instanceof Array && st.length > pos && st[pos].length > 0) {
1280 st.push(st[pos].shift());
1281 }
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001282 },
1283
Kazuki Matsudab909a382016-02-13 19:36:09 +09001284 /**
1285 * Deserializes the beginning of a set.
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001286 * @returns {AnonReadColBeginReturn}
1287 */
1288 readSetBegin: function(elemType, size) {
1289 return this.readListBegin(elemType, size);
1290 },
1291
1292 /** Deserializes the end of a set. */
1293 readSetEnd: function() {
1294 return this.readListEnd();
1295 },
1296
Kazuki Matsudab909a382016-02-13 19:36:09 +09001297 /** Returns an object with a value property set to
1298 * False unless the next number in the protocol buffer
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +01001299 * is 1, in which case the value property is True */
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001300 readBool: function() {
1301 var r = this.readI32();
1302
1303 if (r !== null && r.value == '1') {
1304 r.value = true;
1305 } else {
1306 r.value = false;
1307 }
1308
1309 return r;
1310 },
1311
Kazuki Matsudab909a382016-02-13 19:36:09 +09001312 /** Returns the an object with a value property set to the
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001313 next value found in the protocol buffer */
1314 readByte: function() {
1315 return this.readI32();
1316 },
1317
Kazuki Matsudab909a382016-02-13 19:36:09 +09001318 /** Returns the an object with a value property set to the
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001319 next value found in the protocol buffer */
1320 readI16: function() {
1321 return this.readI32();
1322 },
1323
Kazuki Matsudab909a382016-02-13 19:36:09 +09001324 /** Returns the an object with a value property set to the
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001325 next value found in the protocol buffer */
1326 readI32: function(f) {
1327 if (f === undefined) {
1328 f = this.rstack[this.rstack.length - 1];
1329 }
1330
1331 var r = {};
1332
1333 if (f instanceof Array) {
1334 if (f.length === 0) {
1335 r.value = undefined;
1336 } else {
Drew Ritterc0a5eed2018-06-27 10:28:00 -07001337 if (!f.isReversed) {
1338 f.reverse();
1339 f.isReversed = true;
1340 }
1341 r.value = f.pop();
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001342 }
1343 } else if (f instanceof Object) {
1344 for (var i in f) {
1345 if (i === null) {
1346 continue;
1347 }
1348 this.rstack.push(f[i]);
1349 delete f[i];
1350
1351 r.value = i;
1352 break;
1353 }
1354 } else {
1355 r.value = f;
1356 this.rstack.pop();
1357 }
1358
1359 return r;
1360 },
1361
Kazuki Matsudab909a382016-02-13 19:36:09 +09001362 /** Returns the an object with a value property set to the
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001363 next value found in the protocol buffer */
Mustafa Senol Cosarf86845e2018-12-05 17:50:18 +03001364 readI64: function(f) {
1365 if (f === undefined) {
1366 f = this.rstack[this.rstack.length - 1];
1367 }
1368
1369 var r = {};
1370
1371 if (f instanceof Array) {
1372 if (f.length === 0) {
1373 r.value = undefined;
1374 } else {
1375 if (!f.isReversed) {
1376 f.reverse();
1377 f.isReversed = true;
1378 }
1379 r.value = f.pop();
1380 }
1381 } else if (f instanceof Object) {
1382 var int64Object = true;
1383 var objectKeys = Object.keys(f).sort();
1384 var int64Keys = ['buffer', 'offset'];
1385 if (objectKeys.length !== int64Keys.length) {
1386 int64Object = false;
1387 }
1388 for (var it=0; int64Object && it < objectKeys.length; ++it) {
1389 if (objectKeys[it] !== int64Keys[it]) {
1390 int64Object = false;
1391 }
1392 }
1393 if (int64Object) {
1394 r.value = f;
1395 } else {
1396 for (var i in f) {
1397 if (i === null) {
1398 continue;
1399 }
1400 this.rstack.push(f[i]);
1401 delete f[i];
1402
1403 r.value = i;
1404 break;
1405 }
1406 }
1407 } else {
1408 r.value = f;
1409 this.rstack.pop();
1410 }
1411 return r;
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001412 },
1413
Kazuki Matsudab909a382016-02-13 19:36:09 +09001414 /** Returns the an object with a value property set to the
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001415 next value found in the protocol buffer */
1416 readDouble: function() {
1417 return this.readI32();
1418 },
1419
Kazuki Matsudab909a382016-02-13 19:36:09 +09001420 /** Returns the an object with a value property set to the
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001421 next value found in the protocol buffer */
1422 readString: function() {
1423 var r = this.readI32();
1424 return r;
1425 },
1426
Kazuki Matsudab909a382016-02-13 19:36:09 +09001427 /** Returns the an object with a value property set to the
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001428 next value found in the protocol buffer */
1429 readBinary: function() {
Nobuaki Sukegawa6defea52015-11-14 17:36:29 +09001430 var r = this.readI32();
1431 r.value = atob(r.value);
1432 return r;
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001433 },
1434
Kazuki Matsudab909a382016-02-13 19:36:09 +09001435 /**
Jens Geyer329d59a2014-06-19 22:11:53 +02001436 * Method to arbitrarily skip over data */
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001437 skip: function(type) {
Jens Geyer329d59a2014-06-19 22:11:53 +02001438 var ret, i;
1439 switch (type) {
Jens Geyer329d59a2014-06-19 22:11:53 +02001440 case Thrift.Type.BOOL:
1441 return this.readBool();
1442
1443 case Thrift.Type.BYTE:
1444 return this.readByte();
1445
1446 case Thrift.Type.I16:
1447 return this.readI16();
1448
1449 case Thrift.Type.I32:
1450 return this.readI32();
1451
1452 case Thrift.Type.I64:
1453 return this.readI64();
1454
1455 case Thrift.Type.DOUBLE:
1456 return this.readDouble();
1457
1458 case Thrift.Type.STRING:
1459 return this.readString();
1460
1461 case Thrift.Type.STRUCT:
1462 this.readStructBegin();
1463 while (true) {
1464 ret = this.readFieldBegin();
1465 if (ret.ftype == Thrift.Type.STOP) {
1466 break;
1467 }
1468 this.skip(ret.ftype);
1469 this.readFieldEnd();
1470 }
1471 this.readStructEnd();
1472 return null;
1473
1474 case Thrift.Type.MAP:
1475 ret = this.readMapBegin();
1476 for (i = 0; i < ret.size; i++) {
1477 if (i > 0) {
1478 if (this.rstack.length > this.rpos[this.rpos.length - 1] + 1) {
1479 this.rstack.pop();
1480 }
1481 }
1482 this.skip(ret.ktype);
1483 this.skip(ret.vtype);
1484 }
1485 this.readMapEnd();
1486 return null;
1487
1488 case Thrift.Type.SET:
1489 ret = this.readSetBegin();
1490 for (i = 0; i < ret.size; i++) {
1491 this.skip(ret.etype);
1492 }
1493 this.readSetEnd();
1494 return null;
1495
1496 case Thrift.Type.LIST:
1497 ret = this.readListBegin();
1498 for (i = 0; i < ret.size; i++) {
1499 this.skip(ret.etype);
1500 }
1501 this.readListEnd();
1502 return null;
Philip Frank50862912018-03-07 21:21:30 +01001503
1504 default:
1505 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA);
Jens Geyer329d59a2014-06-19 22:11:53 +02001506 }
Henrique Mendonça095ddb72013-09-20 19:38:03 +02001507 }
1508};
henrique5ba91f22013-12-20 21:13:13 +01001509
1510
1511/**
1512 * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol
1513 * @constructor
1514 */
Kazuki Matsudab909a382016-02-13 19:36:09 +09001515Thrift.MultiplexProtocol = function(srvName, trans, strictRead, strictWrite) {
henrique5ba91f22013-12-20 21:13:13 +01001516 Thrift.Protocol.call(this, trans, strictRead, strictWrite);
1517 this.serviceName = srvName;
1518};
1519Thrift.inherits(Thrift.MultiplexProtocol, Thrift.Protocol, 'multiplexProtocol');
1520
1521/** Override writeMessageBegin method of prototype*/
Kazuki Matsudab909a382016-02-13 19:36:09 +09001522Thrift.MultiplexProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
henrique5ba91f22013-12-20 21:13:13 +01001523
1524 if (type === Thrift.MessageType.CALL || type === Thrift.MessageType.ONEWAY) {
Kazuki Matsudab909a382016-02-13 19:36:09 +09001525 Thrift.Protocol.prototype.writeMessageBegin.call(this, this.serviceName + ':' + name, type, seqid);
henrique5ba91f22013-12-20 21:13:13 +01001526 } else {
1527 Thrift.Protocol.prototype.writeMessageBegin.call(this, name, type, seqid);
1528 }
1529};
1530
Kazuki Matsudab909a382016-02-13 19:36:09 +09001531Thrift.Multiplexer = function() {
henrique5ba91f22013-12-20 21:13:13 +01001532 this.seqid = 0;
1533};
1534
1535/** Instantiates a multiplexed client for a specific service
1536 * @constructor
1537 * @param {String} serviceName - The transport to serialize to/from.
1538 * @param {Thrift.ServiceClient} SCl - The Service Client Class
1539 * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port
1540 * @example
1541 * var mp = new Thrift.Multiplexer();
1542 * var transport = new Thrift.Transport("http://localhost:9090/foo.thrift");
1543 * var protocol = new Thrift.Protocol(transport);
1544 * var client = mp.createClient('AuthService', AuthServiceClient, transport);
1545*/
Kazuki Matsudab909a382016-02-13 19:36:09 +09001546Thrift.Multiplexer.prototype.createClient = function(serviceName, SCl, transport) {
henrique5ba91f22013-12-20 21:13:13 +01001547 if (SCl.Client) {
1548 SCl = SCl.Client;
1549 }
1550 var self = this;
Kazuki Matsudab909a382016-02-13 19:36:09 +09001551 SCl.prototype.new_seqid = function() {
henrique5ba91f22013-12-20 21:13:13 +01001552 self.seqid += 1;
1553 return self.seqid;
1554 };
1555 var client = new SCl(new Thrift.MultiplexProtocol(serviceName, transport));
1556
1557 return client;
1558};
1559
henriquea2de4102014-02-07 14:12:56 +01001560
henrique2a7dccc2014-03-07 22:16:51 +01001561
Henrique Mendonça15d90422015-06-25 22:31:41 +10001562var copyList, copyMap;
1563
1564copyList = function(lst, types) {
1565
1566 if (!lst) {return lst; }
1567
1568 var type;
1569
1570 if (types.shift === undefined) {
1571 type = types;
1572 }
1573 else {
1574 type = types[0];
1575 }
1576 var Type = type;
1577
1578 var len = lst.length, result = [], i, val;
1579 for (i = 0; i < len; i++) {
1580 val = lst[i];
1581 if (type === null) {
1582 result.push(val);
1583 }
1584 else if (type === copyMap || type === copyList) {
1585 result.push(type(val, types.slice(1)));
1586 }
1587 else {
1588 result.push(new Type(val));
1589 }
1590 }
1591 return result;
1592};
1593
Kazuki Matsudab909a382016-02-13 19:36:09 +09001594copyMap = function(obj, types) {
Henrique Mendonça15d90422015-06-25 22:31:41 +10001595
1596 if (!obj) {return obj; }
1597
1598 var type;
1599
1600 if (types.shift === undefined) {
1601 type = types;
1602 }
1603 else {
1604 type = types[0];
1605 }
1606 var Type = type;
1607
1608 var result = {}, val;
Kazuki Matsudab909a382016-02-13 19:36:09 +09001609 for (var prop in obj) {
1610 if (obj.hasOwnProperty(prop)) {
Henrique Mendonça15d90422015-06-25 22:31:41 +10001611 val = obj[prop];
1612 if (type === null) {
1613 result[prop] = val;
1614 }
1615 else if (type === copyMap || type === copyList) {
1616 result[prop] = type(val, types.slice(1));
1617 }
1618 else {
1619 result[prop] = new Type(val);
1620 }
1621 }
1622 }
1623 return result;
1624};
1625
1626Thrift.copyMap = copyMap;
1627Thrift.copyList = copyList;