| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| var Thrift = { |
| Version: '0.9.0-dev', |
| /* |
| Description: 'JavaScript bindings for the Apache Thrift RPC system', |
| License: 'http://www.apache.org/licenses/LICENSE-2.0', |
| Homepage: 'http://thrift.apache.org', |
| BugReports: 'https://issues.apache.org/jira/browse/THRIFT', |
| Maintainer: 'dev@thrift.apache.org', |
| */ |
| |
| Type: { |
| 'STOP' : 0, |
| 'VOID' : 1, |
| 'BOOL' : 2, |
| 'BYTE' : 3, |
| 'I08' : 3, |
| 'DOUBLE' : 4, |
| 'I16' : 6, |
| 'I32' : 8, |
| 'I64' : 10, |
| 'STRING' : 11, |
| 'UTF7' : 11, |
| 'STRUCT' : 12, |
| 'MAP' : 13, |
| 'SET' : 14, |
| 'LIST' : 15, |
| 'UTF8' : 16, |
| 'UTF16' : 17 |
| }, |
| |
| MessageType: { |
| 'CALL' : 1, |
| 'REPLY' : 2, |
| 'EXCEPTION' : 3 |
| }, |
| |
| objectLength: function(obj) { |
| var length = 0; |
| for (var k in obj) { |
| if (obj.hasOwnProperty(k)) { |
| length++; |
| } |
| } |
| |
| return length; |
| }, |
| |
| inherits: function(constructor, superConstructor) { |
| //Prototypal Inheritance http://javascript.crockford.com/prototypal.html |
| function F() {} |
| F.prototype = superConstructor.prototype; |
| constructor.prototype = new F(); |
| } |
| }; |
| |
| |
| |
| Thrift.TException = function(message) { |
| this.message = message; |
| }; |
| Thrift.inherits(Thrift.TException, Error); |
| Thrift.TException.prototype.name = 'TException'; |
| |
| Thrift.TApplicationExceptionType = { |
| 'UNKNOWN' : 0, |
| 'UNKNOWN_METHOD' : 1, |
| 'INVALID_MESSAGE_TYPE' : 2, |
| 'WRONG_METHOD_NAME' : 3, |
| 'BAD_SEQUENCE_ID' : 4, |
| 'MISSING_RESULT' : 5, |
| 'INTERNAL_ERROR' : 6, |
| 'PROTOCOL_ERROR' : 7 |
| }; |
| |
| Thrift.TApplicationException = function(message, code) { |
| this.message = message; |
| this.code = (code === null) ? 0 : code; |
| }; |
| Thrift.inherits(Thrift.TApplicationException, Thrift.TException); |
| Thrift.TApplicationException.prototype.name = 'TApplicationException'; |
| |
| Thrift.TApplicationException.prototype.read = function(input) { |
| while (1) { |
| var ret = input.readFieldBegin(); |
| |
| if (ret.ftype == Thrift.Type.STOP) { |
| break; |
| } |
| |
| var fid = ret.fid; |
| |
| switch (fid) { |
| case 1: |
| if (ret.ftype == Thrift.Type.STRING) { |
| ret = input.readString(); |
| this.message = ret.value; |
| } else { |
| ret = input.skip(ret.ftype); |
| } |
| break; |
| case 2: |
| if (ret.ftype == Thrift.Type.I32) { |
| ret = input.readI32(); |
| this.code = ret.value; |
| } else { |
| ret = input.skip(ret.ftype); |
| } |
| break; |
| default: |
| ret = input.skip(ret.ftype); |
| break; |
| } |
| |
| input.readFieldEnd(); |
| } |
| |
| input.readStructEnd(); |
| }; |
| |
| Thrift.TApplicationException.prototype.write = function(output) { |
| var xfer = 0; |
| |
| output.writeStructBegin('TApplicationException'); |
| |
| if (this.message) { |
| output.writeFieldBegin('message', Thrift.Type.STRING, 1); |
| output.writeString(this.getMessage()); |
| output.writeFieldEnd(); |
| } |
| |
| if (this.code) { |
| output.writeFieldBegin('type', Thrift.Type.I32, 2); |
| output.writeI32(this.code); |
| output.writeFieldEnd(); |
| } |
| |
| output.writeFieldStop(); |
| output.writeStructEnd(); |
| }; |
| |
| Thrift.TApplicationException.prototype.getCode = function() { |
| return this.code; |
| }; |
| |
| Thrift.TApplicationException.prototype.getMessage = function() { |
| return this.message; |
| }; |
| |
| /** |
| *If you do not specify a url then you must handle ajax on your own. |
| *This is how to use js bindings in a async fashion. |
| */ |
| Thrift.Transport = function(url) { |
| this.url = url; |
| this.wpos = 0; |
| this.rpos = 0; |
| |
| this.send_buf = ''; |
| this.recv_buf = ''; |
| }; |
| |
| Thrift.Transport.prototype = { |
| |
| //Gets the browser specific XmlHttpRequest Object |
| getXmlHttpRequestObject: function() { |
| try { return new XMLHttpRequest(); } catch (e1) { } |
| try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { } |
| try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { } |
| |
| throw "Your browser doesn't support the XmlHttpRequest object."; |
| }, |
| |
| flush: function(async) { |
| //async mode |
| if (async || this.url === undefined || this.url === '') { |
| return this.send_buf; |
| } |
| |
| var xreq = this.getXmlHttpRequestObject(); |
| |
| if (xreq.overrideMimeType) { |
| xreq.overrideMimeType('application/json'); |
| } |
| |
| xreq.open('POST', this.url, false); |
| xreq.send(this.send_buf); |
| |
| if (xreq.readyState != 4) { |
| throw 'encountered an unknown ajax ready state: ' + xreq.readyState; |
| } |
| |
| if (xreq.status != 200) { |
| throw 'encountered a unknown request status: ' + xreq.status; |
| } |
| |
| this.recv_buf = xreq.responseText; |
| this.recv_buf_sz = this.recv_buf.length; |
| this.wpos = this.recv_buf.length; |
| this.rpos = 0; |
| }, |
| |
| jqRequest: function(client, postData, args, recv_method) { |
| if (typeof jQuery === 'undefined' || |
| typeof jQuery.Deferred === 'undefined') { |
| throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests'; |
| } |
| |
| var thriftTransport = this; |
| |
| var jqXHR = jQuery.ajax({ |
| url: this.url, |
| data: postData, |
| type: 'POST', |
| cache: false, |
| dataType: 'text thrift', |
| converters: { |
| 'text thrift' : function(responseData) { |
| thriftTransport.setRecvBuffer(responseData); |
| var value = recv_method.call(client); |
| return value; |
| } |
| }, |
| context: client, |
| success: jQuery.makeArray(args).pop() |
| }); |
| |
| return jqXHR; |
| }, |
| |
| setRecvBuffer: function(buf) { |
| this.recv_buf = buf; |
| this.recv_buf_sz = this.recv_buf.length; |
| this.wpos = this.recv_buf.length; |
| this.rpos = 0; |
| }, |
| |
| isOpen: function() { |
| return true; |
| }, |
| |
| open: function() {}, |
| |
| close: function() {}, |
| |
| read: function(len) { |
| var avail = this.wpos - this.rpos; |
| |
| if (avail === 0) { |
| return ''; |
| } |
| |
| var give = len; |
| |
| if (avail < len) { |
| give = avail; |
| } |
| |
| var ret = this.read_buf.substr(this.rpos, give); |
| this.rpos += give; |
| |
| //clear buf when complete? |
| return ret; |
| }, |
| |
| readAll: function() { |
| return this.recv_buf; |
| }, |
| |
| write: function(buf) { |
| this.send_buf = buf; |
| }, |
| |
| getSendBuffer: function() { |
| return this.send_buf; |
| } |
| |
| }; |
| |
| |
| |
| Thrift.Protocol = function(transport) { |
| this.transport = transport; |
| }; |
| |
| Thrift.Protocol.Type = {}; |
| Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"'; |
| Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"'; |
| Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"'; |
| Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"'; |
| Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"'; |
| Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"'; |
| Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"'; |
| Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"'; |
| Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"'; |
| Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"'; |
| Thrift.Protocol.Type[Thrift.Type.SET] = '"set"'; |
| |
| |
| Thrift.Protocol.RType = {}; |
| Thrift.Protocol.RType.tf = Thrift.Type.BOOL; |
| Thrift.Protocol.RType.i8 = Thrift.Type.BYTE; |
| Thrift.Protocol.RType.i16 = Thrift.Type.I16; |
| Thrift.Protocol.RType.i32 = Thrift.Type.I32; |
| Thrift.Protocol.RType.i64 = Thrift.Type.I64; |
| Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE; |
| Thrift.Protocol.RType.rec = Thrift.Type.STRUCT; |
| Thrift.Protocol.RType.str = Thrift.Type.STRING; |
| Thrift.Protocol.RType.map = Thrift.Type.MAP; |
| Thrift.Protocol.RType.lst = Thrift.Type.LIST; |
| Thrift.Protocol.RType.set = Thrift.Type.SET; |
| |
| Thrift.Protocol.Version = 1; |
| |
| Thrift.Protocol.prototype = { |
| |
| getTransport: function() { |
| return this.transport; |
| }, |
| |
| //Write functions |
| writeMessageBegin: function(name, messageType, seqid) { |
| this.tstack = []; |
| this.tpos = []; |
| |
| this.tstack.push([Thrift.Protocol.Version, '"' + |
| name + '"', messageType, seqid]); |
| }, |
| |
| writeMessageEnd: function() { |
| var obj = this.tstack.pop(); |
| |
| this.wobj = this.tstack.pop(); |
| this.wobj.push(obj); |
| |
| this.wbuf = '[' + this.wobj.join(',') + ']'; |
| |
| this.transport.write(this.wbuf); |
| }, |
| |
| |
| writeStructBegin: function(name) { |
| this.tpos.push(this.tstack.length); |
| this.tstack.push({}); |
| }, |
| |
| writeStructEnd: function() { |
| |
| var p = this.tpos.pop(); |
| var struct = this.tstack[p]; |
| var str = '{'; |
| var first = true; |
| for (var key in struct) { |
| if (first) { |
| first = false; |
| } else { |
| str += ','; |
| } |
| |
| str += key + ':' + struct[key]; |
| } |
| |
| str += '}'; |
| this.tstack[p] = str; |
| }, |
| |
| writeFieldBegin: function(name, fieldType, fieldId) { |
| this.tpos.push(this.tstack.length); |
| this.tstack.push({ 'fieldId': '"' + |
| fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType] |
| }); |
| |
| }, |
| |
| writeFieldEnd: function() { |
| var value = this.tstack.pop(); |
| var fieldInfo = this.tstack.pop(); |
| |
| this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + |
| fieldInfo.fieldType + ':' + value + '}'; |
| this.tpos.pop(); |
| }, |
| |
| writeFieldStop: function() { |
| //na |
| }, |
| |
| writeMapBegin: function(keyType, valType, size) { |
| //size is invalid, we'll set it on end. |
| this.tpos.push(this.tstack.length); |
| this.tstack.push([Thrift.Protocol.Type[keyType], |
| Thrift.Protocol.Type[valType], 0]); |
| }, |
| |
| writeMapEnd: function() { |
| var p = this.tpos.pop(); |
| |
| if (p == this.tstack.length) { |
| return; |
| } |
| |
| if ((this.tstack.length - p - 1) % 2 !== 0) { |
| this.tstack.push(''); |
| } |
| |
| var size = (this.tstack.length - p - 1) / 2; |
| |
| this.tstack[p][this.tstack[p].length - 1] = size; |
| |
| var map = '}'; |
| var first = true; |
| while (this.tstack.length > p + 1) { |
| var v = this.tstack.pop(); |
| var k = this.tstack.pop(); |
| if (first) { |
| first = false; |
| } else { |
| map = ',' + map; |
| } |
| |
| if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings |
| map = k + ':' + v + map; |
| } |
| map = '{' + map; |
| |
| this.tstack[p].push(map); |
| this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; |
| }, |
| |
| writeListBegin: function(elemType, size) { |
| this.tpos.push(this.tstack.length); |
| this.tstack.push([Thrift.Protocol.Type[elemType], size]); |
| }, |
| |
| writeListEnd: function() { |
| var p = this.tpos.pop(); |
| |
| while (this.tstack.length > p + 1) { |
| var tmpVal = this.tstack[p + 1]; |
| this.tstack.splice(p + 1, 1); |
| this.tstack[p].push(tmpVal); |
| } |
| |
| this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; |
| }, |
| |
| writeSetBegin: function(elemType, size) { |
| this.tpos.push(this.tstack.length); |
| this.tstack.push([Thrift.Protocol.Type[elemType], size]); |
| }, |
| |
| writeSetEnd: function() { |
| var p = this.tpos.pop(); |
| |
| while (this.tstack.length > p + 1) { |
| var tmpVal = this.tstack[p + 1]; |
| this.tstack.splice(p + 1, 1); |
| this.tstack[p].push(tmpVal); |
| } |
| |
| this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; |
| }, |
| |
| writeBool: function(value) { |
| this.tstack.push(value ? 1 : 0); |
| }, |
| |
| writeByte: function(i8) { |
| this.tstack.push(i8); |
| }, |
| |
| writeI16: function(i16) { |
| this.tstack.push(i16); |
| }, |
| |
| writeI32: function(i32) { |
| this.tstack.push(i32); |
| }, |
| |
| writeI64: function(i64) { |
| this.tstack.push(i64); |
| }, |
| |
| writeDouble: function(dbl) { |
| this.tstack.push(dbl); |
| }, |
| |
| writeString: function(str) { |
| // We do not encode uri components for wire transfer: |
| if (str === null) { |
| this.tstack.push(null); |
| } else { |
| // concat may be slower than building a byte buffer |
| var escapedString = ''; |
| for (var i = 0; i < str.length; i++) { |
| var ch = str.charAt(i); // a single double quote: " |
| if (ch === '\"') { |
| escapedString += '\\\"'; // write out as: \" |
| } else if (ch === '\\') { // a single backslash: \ |
| escapedString += '\\\\'; // write out as: \\ |
| /* Currently escaped forward slashes break TJSONProtocol. |
| * As it stands, we can simply pass forward slashes into |
| * our strings across the wire without being escaped. |
| * I think this is the protocol's bug, not thrift.js |
| * } else if(ch === '/') { // a single forward slash: / |
| * escapedString += '\\/'; // write out as \/ |
| * } |
| */ |
| } else if (ch === '\b') { // a single backspace: invisible |
| escapedString += '\\b'; // write out as: \b" |
| } else if (ch === '\f') { // a single formfeed: invisible |
| escapedString += '\\f'; // write out as: \f" |
| } else if (ch === '\n') { // a single newline: invisible |
| escapedString += '\\n'; // write out as: \n" |
| } else if (ch === '\r') { // a single return: invisible |
| escapedString += '\\r'; // write out as: \r" |
| } else if (ch === '\t') { // a single tab: invisible |
| escapedString += '\\t'; // write out as: \t" |
| } else { |
| escapedString += ch; // Else it need not be escaped |
| } |
| } |
| this.tstack.push('"' + escapedString + '"'); |
| } |
| }, |
| |
| writeBinary: function(str) { |
| this.writeString(str); |
| }, |
| |
| |
| |
| // Reading functions |
| readMessageBegin: function(name, messageType, seqid) { |
| this.rstack = []; |
| this.rpos = []; |
| |
| if (typeof jQuery !== 'undefined') { |
| this.robj = jQuery.parseJSON(this.transport.readAll()); |
| } else { |
| this.robj = eval(this.transport.readAll()); |
| } |
| |
| var r = {}; |
| var version = this.robj.shift(); |
| |
| if (version != Thrift.Protocol.Version) { |
| throw 'Wrong thrift protocol version: ' + version; |
| } |
| |
| r.fname = this.robj.shift(); |
| r.mtype = this.robj.shift(); |
| r.rseqid = this.robj.shift(); |
| |
| |
| //get to the main obj |
| this.rstack.push(this.robj.shift()); |
| |
| return r; |
| }, |
| |
| readMessageEnd: function() { |
| }, |
| |
| readStructBegin: function(name) { |
| var r = {}; |
| r.fname = ''; |
| |
| //incase this is an array of structs |
| if (this.rstack[this.rstack.length - 1] instanceof Array) { |
| this.rstack.push(this.rstack[this.rstack.length - 1].shift()); |
| } |
| |
| return r; |
| }, |
| |
| readStructEnd: function() { |
| if (this.rstack[this.rstack.length - 2] instanceof Array) { |
| this.rstack.pop(); |
| } |
| }, |
| |
| readFieldBegin: function() { |
| var r = {}; |
| |
| var fid = -1; |
| var ftype = Thrift.Type.STOP; |
| |
| //get a fieldId |
| for (var f in (this.rstack[this.rstack.length - 1])) { |
| if (f === null) { |
| continue; |
| } |
| |
| fid = parseInt(f, 10); |
| this.rpos.push(this.rstack.length); |
| |
| var field = this.rstack[this.rstack.length - 1][fid]; |
| |
| //remove so we don't see it again |
| delete this.rstack[this.rstack.length - 1][fid]; |
| |
| this.rstack.push(field); |
| |
| break; |
| } |
| |
| if (fid != -1) { |
| |
| //should only be 1 of these but this is the only |
| //way to match a key |
| for (var i in (this.rstack[this.rstack.length - 1])) { |
| if (Thrift.Protocol.RType[i] === null) { |
| continue; |
| } |
| |
| ftype = Thrift.Protocol.RType[i]; |
| this.rstack[this.rstack.length - 1] = |
| this.rstack[this.rstack.length - 1][i]; |
| } |
| } |
| |
| r.fname = ''; |
| r.ftype = ftype; |
| r.fid = fid; |
| |
| return r; |
| }, |
| |
| readFieldEnd: function() { |
| var pos = this.rpos.pop(); |
| |
| //get back to the right place in the stack |
| while (this.rstack.length > pos) { |
| this.rstack.pop(); |
| } |
| |
| }, |
| |
| readMapBegin: function(keyType, valType, size) { |
| var map = this.rstack.pop(); |
| |
| var r = {}; |
| r.ktype = Thrift.Protocol.RType[map.shift()]; |
| r.vtype = Thrift.Protocol.RType[map.shift()]; |
| r.size = map.shift(); |
| |
| |
| this.rpos.push(this.rstack.length); |
| this.rstack.push(map.shift()); |
| |
| return r; |
| }, |
| |
| readMapEnd: function() { |
| this.readFieldEnd(); |
| }, |
| |
| readListBegin: function(elemType, size) { |
| var list = this.rstack[this.rstack.length - 1]; |
| |
| var r = {}; |
| r.etype = Thrift.Protocol.RType[list.shift()]; |
| r.size = list.shift(); |
| |
| this.rpos.push(this.rstack.length); |
| this.rstack.push(list); |
| |
| return r; |
| }, |
| |
| readListEnd: function() { |
| this.readFieldEnd(); |
| }, |
| |
| readSetBegin: function(elemType, size) { |
| return this.readListBegin(elemType, size); |
| }, |
| |
| readSetEnd: function() { |
| return this.readListEnd(); |
| }, |
| |
| readBool: function() { |
| var r = this.readI32(); |
| |
| if (r !== null && r.value == '1') { |
| r.value = true; |
| } else { |
| r.value = false; |
| } |
| |
| return r; |
| }, |
| |
| readByte: function() { |
| return this.readI32(); |
| }, |
| |
| readI16: function() { |
| return this.readI32(); |
| }, |
| |
| readI32: function(f) { |
| if (f === undefined) { |
| f = this.rstack[this.rstack.length - 1]; |
| } |
| |
| var r = {}; |
| |
| if (f instanceof Array) { |
| if (f.length === 0) { |
| r.value = undefined; |
| } else { |
| r.value = f.shift(); |
| } |
| } else if (f instanceof Object) { |
| for (var i in f) { |
| if (i === null) { |
| continue; |
| } |
| this.rstack.push(f[i]); |
| delete f[i]; |
| |
| r.value = i; |
| break; |
| } |
| } else { |
| r.value = f; |
| this.rstack.pop(); |
| } |
| |
| return r; |
| }, |
| |
| readI64: function() { |
| return this.readI32(); |
| }, |
| |
| readDouble: function() { |
| return this.readI32(); |
| }, |
| |
| readString: function() { |
| var r = this.readI32(); |
| return r; |
| }, |
| |
| readBinary: function() { |
| return this.readString(); |
| }, |
| |
| |
| //Method to arbitrarily skip over data. |
| skip: function(type) { |
| throw 'skip not supported yet'; |
| } |
| }; |