From: ra Date: Sun, 11 May 2014 07:25:01 +0000 (-0700) Subject: THRIFT-2511 Node.js compact protocol X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=20aeba3e384f6590770dc3b4343e6d5dfcbd3ce1;p=common%2Fthrift.git THRIFT-2511 Node.js compact protocol Client: Node Patch: Randy Abernethy Adds Compact Protocol to Node.js, tests in testAll.sh and repairs all library JSHint warnings. --- diff --git a/lib/nodejs/lib/thrift/binary.js b/lib/nodejs/lib/thrift/binary.js index 62c3f729..9813ffdb 100644 --- a/lib/nodejs/lib/thrift/binary.js +++ b/lib/nodejs/lib/thrift/binary.js @@ -17,18 +17,18 @@ * under the License. */ -var POW_8 = Math.pow(2, 8) -var POW_16 = Math.pow(2, 16) -var POW_24 = Math.pow(2, 24) -var POW_32 = Math.pow(2, 32) -var POW_40 = Math.pow(2, 40) -var POW_48 = Math.pow(2, 48) -var POW_52 = Math.pow(2, 52) -var POW_1022 = Math.pow(2, 1022) - -exports.readByte = function(byte){ - return byte > 127 ? byte-256 : byte; -} +var POW_8 = Math.pow(2, 8); +var POW_16 = Math.pow(2, 16); +var POW_24 = Math.pow(2, 24); +var POW_32 = Math.pow(2, 32); +var POW_40 = Math.pow(2, 40); +var POW_48 = Math.pow(2, 48); +var POW_52 = Math.pow(2, 52); +var POW_1022 = Math.pow(2, 1022); + +exports.readByte = function(b){ + return b > 127 ? b-256 : b; +}; exports.readI16 = function(buff, off) { off = off || 0; @@ -38,7 +38,7 @@ exports.readI16 = function(buff, off) { v -= POW_16; } return v; -} +}; exports.readI32 = function(buff, off) { off = off || 0; @@ -50,14 +50,14 @@ exports.readI32 = function(buff, off) { v -= POW_32; } return v; -} +}; exports.writeI16 = function(buff, v) { buff[1] = v & 0xff; v >>= 8; buff[0] = v & 0xff; return buff; -} +}; exports.writeI32 = function(buff, v) { buff[3] = v & 0xff; @@ -68,7 +68,7 @@ exports.writeI32 = function(buff, v) { v >>= 8; buff[0] = v & 0xff; return buff; -} +}; exports.readDouble = function(buff, off) { off = off || 0; @@ -86,7 +86,7 @@ exports.readDouble = function(buff, off) { switch (e) { case 0: - e = -1022 + e = -1022; break; case 2047: return m ? NaN : (signed ? -Infinity : Infinity); @@ -100,7 +100,7 @@ exports.readDouble = function(buff, off) { } return m * Math.pow(2, e - 52); -} +}; /* * Based on code from the jspack module: @@ -109,9 +109,9 @@ exports.readDouble = function(buff, off) { exports.writeDouble = function(buff, v) { var m, e, c; - buff[0] = (v < 0 ? 0x80 : 0x00) + buff[0] = (v < 0 ? 0x80 : 0x00); - v = Math.abs(v) + v = Math.abs(v); if (v !== v) { // NaN, use QNaN IEEE format m = 2251799813685248; @@ -120,8 +120,8 @@ exports.writeDouble = function(buff, v) { m = 0; e = 2047; } else { - e = Math.floor(Math.log(v) / Math.LN2) - c = Math.pow(2, -e) + e = Math.floor(Math.log(v) / Math.LN2); + c = Math.pow(2, -e); if (v * c < 1) { e--; c *= 2; @@ -165,4 +165,4 @@ exports.writeDouble = function(buff, v) { buff[1] |= m & 0x0f; return buff; -} +}; diff --git a/lib/nodejs/lib/thrift/index.js b/lib/nodejs/lib/thrift/index.js index 3a865f86..ea7fde0f 100644 --- a/lib/nodejs/lib/thrift/index.js +++ b/lib/nodejs/lib/thrift/index.js @@ -54,3 +54,4 @@ exports.TFramedTransport = require('./transport').TFramedTransport; exports.TBufferedTransport = require('./transport').TBufferedTransport; exports.TBinaryProtocol = require('./protocol').TBinaryProtocol; exports.TJSONProtocol = require('./protocol').TJSONProtocol; +exports.TCompactProtocol = require('./protocol').TCompactProtocol; diff --git a/lib/nodejs/lib/thrift/protocol.js b/lib/nodejs/lib/thrift/protocol.js index 3cf3f410..8ccb55d3 100644 --- a/lib/nodejs/lib/thrift/protocol.js +++ b/lib/nodejs/lib/thrift/protocol.js @@ -37,13 +37,20 @@ var TProtocolException = function(type, message) { Error.call(this, message); this.name = 'TProtocolException'; this.type = type; -} +}; util.inherits(TProtocolException, Error); -// NastyHaxx. JavaScript forces hex constants to be -// positive, converting this into a long. If we hardcode the int value -// instead it'll stay in 32 bit-land. -var VERSION_MASK = -65536, // 0xffff0000 + +// +// BINARY PROTOCOL +// +/////////////////////////////////////////////////////////// + +// JavaScript supports only numeric doubles, therefore even hex values are always signed. +// The largest integer value which can be represented in JavaScript is +/-2^53. +// Bitwise operations convert numbers to 32 bit integers but perform sign extension +// upon assigning values back to variables. +var VERSION_MASK = -65536, // 0xffff0000 VERSION_1 = -2147418112, // 0x80010000 TYPE_MASK = 0x000000ff; @@ -51,11 +58,11 @@ var TBinaryProtocol = exports.TBinaryProtocol = function(trans, strictRead, stri this.trans = trans; this.strictRead = (strictRead !== undefined ? strictRead : false); this.strictWrite = (strictWrite !== undefined ? strictWrite : true); -} +}; TBinaryProtocol.prototype.flush = function() { return this.trans.flush(); -} +}; TBinaryProtocol.prototype.writeMessageBegin = function(name, type, seqid) { if (this.strictWrite) { @@ -67,53 +74,53 @@ TBinaryProtocol.prototype.writeMessageBegin = function(name, type, seqid) { this.writeByte(type); this.writeI32(seqid); } -} +}; TBinaryProtocol.prototype.writeMessageEnd = function() { -} +}; TBinaryProtocol.prototype.writeStructBegin = function(name) { -} +}; TBinaryProtocol.prototype.writeStructEnd = function() { -} +}; TBinaryProtocol.prototype.writeFieldBegin = function(name, type, id) { this.writeByte(type); this.writeI16(id); -} +}; TBinaryProtocol.prototype.writeFieldEnd = function() { -} +}; TBinaryProtocol.prototype.writeFieldStop = function() { this.writeByte(Type.STOP); -} +}; TBinaryProtocol.prototype.writeMapBegin = function(ktype, vtype, size) { this.writeByte(ktype); this.writeByte(vtype); this.writeI32(size); -} +}; TBinaryProtocol.prototype.writeMapEnd = function() { -} +}; TBinaryProtocol.prototype.writeListBegin = function(etype, size) { this.writeByte(etype); this.writeI32(size); -} +}; TBinaryProtocol.prototype.writeListEnd = function() { -} +}; TBinaryProtocol.prototype.writeSetBegin = function(etype, size) { this.writeByte(etype); this.writeI32(size); -} +}; TBinaryProtocol.prototype.writeSetEnd = function() { -} +}; TBinaryProtocol.prototype.writeBool = function(bool) { if (bool) { @@ -121,55 +128,55 @@ TBinaryProtocol.prototype.writeBool = function(bool) { } else { this.writeByte(0); } -} +}; -TBinaryProtocol.prototype.writeByte = function(byte) { - this.trans.write(new Buffer([byte])); -} +TBinaryProtocol.prototype.writeByte = function(b) { + this.trans.write(new Buffer([b])); +}; TBinaryProtocol.prototype.writeI16 = function(i16) { this.trans.write(binary.writeI16(new Buffer(2), i16)); -} +}; TBinaryProtocol.prototype.writeI32 = function(i32) { this.trans.write(binary.writeI32(new Buffer(4), i32)); -} +}; TBinaryProtocol.prototype.writeI64 = function(i64) { if (i64.buffer) { this.trans.write(i64.buffer); } else { - this.trans.write(new Int64(i64).buffer) + this.trans.write(new Int64(i64).buffer); } -} +}; TBinaryProtocol.prototype.writeDouble = function(dub) { this.trans.write(binary.writeDouble(new Buffer(8), dub)); -} +}; TBinaryProtocol.prototype.writeString = function(arg) { if (typeof(arg) === 'string') { - this.writeI32(Buffer.byteLength(arg, 'utf8')) + this.writeI32(Buffer.byteLength(arg, 'utf8')); this.trans.write(arg, 'utf8'); } else if (arg instanceof Buffer) { - this.writeI32(arg.length) + this.writeI32(arg.length); this.trans.write(arg); } else { - throw new Error('writeString called without a string/Buffer argument: ' + arg) + throw new Error('writeString called without a string/Buffer argument: ' + arg); } -} +}; TBinaryProtocol.prototype.writeBinary = function(arg) { if (typeof(arg) === 'string') { - this.writeI32(Buffer.byteLength(arg, 'utf8')) + this.writeI32(Buffer.byteLength(arg, 'utf8')); this.trans.write(arg, 'utf8'); } else if (arg instanceof Buffer) { - this.writeI32(arg.length) + this.writeI32(arg.length); this.trans.write(arg); } else { - throw new Error('writeBinary called without a string/Buffer argument: ' + arg) + throw new Error('writeBinary called without a string/Buffer argument: ' + arg); } -} +}; TBinaryProtocol.prototype.readMessageBegin = function() { var sz = this.readI32(); @@ -193,17 +200,17 @@ TBinaryProtocol.prototype.readMessageBegin = function() { seqid = this.readI32(); } return {fname: name, mtype: type, rseqid: seqid}; -} +}; TBinaryProtocol.prototype.readMessageEnd = function() { -} +}; TBinaryProtocol.prototype.readStructBegin = function() { - return {fname: ''} -} + return {fname: ''}; +}; TBinaryProtocol.prototype.readStructEnd = function() { -} +}; TBinaryProtocol.prototype.readFieldBegin = function() { var type = this.readByte(); @@ -212,81 +219,81 @@ TBinaryProtocol.prototype.readFieldBegin = function() { } var id = this.readI16(); return {fname: null, ftype: type, fid: id}; -} +}; TBinaryProtocol.prototype.readFieldEnd = function() { -} +}; TBinaryProtocol.prototype.readMapBegin = function() { var ktype = this.readByte(); var vtype = this.readByte(); var size = this.readI32(); return {ktype: ktype, vtype: vtype, size: size}; -} +}; TBinaryProtocol.prototype.readMapEnd = function() { -} +}; TBinaryProtocol.prototype.readListBegin = function() { var etype = this.readByte(); var size = this.readI32(); return {etype: etype, size: size}; -} +}; TBinaryProtocol.prototype.readListEnd = function() { -} +}; TBinaryProtocol.prototype.readSetBegin = function() { var etype = this.readByte(); var size = this.readI32(); return {etype: etype, size: size}; -} +}; TBinaryProtocol.prototype.readSetEnd = function() { -} +}; TBinaryProtocol.prototype.readBool = function() { - var byte = this.readByte(); - if (byte == 0) { + var b = this.readByte(); + if (b === 0) { return false; } return true; -} +}; TBinaryProtocol.prototype.readByte = function() { return this.trans.readByte(); -} +}; TBinaryProtocol.prototype.readI16 = function() { return this.trans.readI16(); -} +}; TBinaryProtocol.prototype.readI32 = function() { return this.trans.readI32(); -} +}; TBinaryProtocol.prototype.readI64 = function() { var buff = this.trans.read(8); return new Int64(buff); -} +}; TBinaryProtocol.prototype.readDouble = function() { return this.trans.readDouble(); -} +}; TBinaryProtocol.prototype.readBinary = function() { var len = this.readI32(); return this.trans.read(len); -} +}; TBinaryProtocol.prototype.readString = function() { var len = this.readI32(); return this.trans.readString(len); -} +}; TBinaryProtocol.prototype.getTransport = function() { return this.trans; -} +}; TBinaryProtocol.prototype.skip = function(type) { switch (type) { @@ -326,35 +333,815 @@ TBinaryProtocol.prototype.skip = function(type) { this.readStructEnd(); break; case Type.MAP: - var r = this.readMapBegin(); - for (var i = 0; i < r.size; ++i) { - this.skip(r.ktype); - this.skip(r.vtype); + var mapBegin = this.readMapBegin(); + for (var i = 0; i < mapBegin.size; ++i) { + this.skip(mapBegin.ktype); + this.skip(mapBegin.vtype); } this.readMapEnd(); break; case Type.SET: - var r = this.readSetBegin(); - for (var i = 0; i < r.size; ++i) { - this.skip(r.etype); + var setBegin = this.readSetBegin(); + for (var i2 = 0; i2 < setBegin.size; ++i2) { + this.skip(setBegin.etype); } this.readSetEnd(); break; case Type.LIST: - var r = this.readListBegin(); - for (var i = 0; i < r.size; ++i) { - this.skip(r.etype); + var listBegin = this.readListBegin(); + for (var i3 = 0; i3 < listBegin.size; ++i3) { + this.skip(listBegin.etype); } this.readListEnd(); break; default: throw new Error("Invalid type: " + type); } -} +}; + + +// +// COMPACT PROTOCOL +// +/////////////////////////////////////////////////////////// + +/** + * Constructor Function for the Compact Protocol. + * @constructor + * @param {object} [trans] - The underlying transport to read/write. + * @classdesc The Apache Thrift Protocol layer performs serialization + * of base types, the compact protocol serializes data in binary + * form with minimal space used for scalar values. + */ +var TCompactProtocol = exports.TCompactProtocol = function(trans) { + this.trans = trans; + this.lastField_ = []; + this.lastFieldId_ = 0; + this.string_limit_ = 0; + this.string_buf_ = null; + this.string_buf_size_ = 0; + this.container_limit_ = 0; + this.booleanField_ = { + name: null, + hasBoolValue: false + }; + this.boolValue_ = { + hasBoolValue: false, + boolValue: false + }; +}; + + +// +// Compact Protocol Constants +// + +/** + * Compact Protocol ID number. + * @readonly + * @const {number} PROTOCOL_ID + */ +TCompactProtocol.PROTOCOL_ID = -126; //1000 0010 + +/** + * Compact Protocol version number. + * @readonly + * @const {number} VERSION_N + */ +TCompactProtocol.VERSION_N = 1; + +/** + * Compact Protocol version mask for combining protocol version and message type in one byte. + * @readonly + * @const {number} VERSION_MASK + */ +TCompactProtocol.VERSION_MASK = 0x1f; //0001 1111 + +/** + * Compact Protocol message type mask for combining protocol version and message type in one byte. + * @readonly + * @const {number} TYPE_MASK + */ +TCompactProtocol.TYPE_MASK = -32; //1110 0000 + +/** + * Compact Protocol message type shift amount for combining protocol version and message type in one byte. + * @readonly + * @const {number} TYPE_SHIFT_AMOUNT + */ +TCompactProtocol.TYPE_SHIFT_AMOUNT = 5; + +/** + * Compact Protocol type IDs used to keep type data within one nibble. + * @readonly + * @property {number} CT_STOP - End of a set of fields. + * @property {number} CT_BOOLEAN_TRUE - Flag for Boolean field with true value (packed field and value). + * @property {number} CT_BOOLEAN_FALSE - Flag for Boolean field with false value (packed field and value). + * @property {number} CT_BYTE - Signed 8 bit integer. + * @property {number} CT_I16 - Signed 16 bit integer. + * @property {number} CT_I32 - Signed 32 bit integer. + * @property {number} CT_I64 - Signed 64 bit integer (2^53 max in JavaScript). + * @property {number} CT_DOUBLE - 64 bit IEEE 854 floating point. + * @property {number} CT_BINARY - Array of bytes (used for strings also). + * @property {number} CT_LIST - A collection type (unordered). + * @property {number} CT_SET - A collection type (unordered and without repeated values). + * @property {number} CT_MAP - A collection type (map/associative-array/dictionary). + * @property {number} CT_STRUCT - A multifield type. + */ +TCompactProtocol.Types = { + CT_STOP: 0x00, + CT_BOOLEAN_TRUE: 0x01, + CT_BOOLEAN_FALSE: 0x02, + CT_BYTE: 0x03, + CT_I16: 0x04, + CT_I32: 0x05, + CT_I64: 0x06, + CT_DOUBLE: 0x07, + CT_BINARY: 0x08, + CT_LIST: 0x09, + CT_SET: 0x0A, + CT_MAP: 0x0B, + CT_STRUCT: 0x0C +}; + +/** + * Array mapping Compact type IDs to standard Thrift type IDs. + * @readonly + */ +TCompactProtocol.TTypeToCType = [ + TCompactProtocol.Types.CT_STOP, // T_STOP + 0, // unused + TCompactProtocol.Types.CT_BOOLEAN_TRUE, // T_BOOL + TCompactProtocol.Types.CT_BYTE, // T_BYTE + TCompactProtocol.Types.CT_DOUBLE, // T_DOUBLE + 0, // unused + TCompactProtocol.Types.CT_I16, // T_I16 + 0, // unused + TCompactProtocol.Types.CT_I32, // T_I32 + 0, // unused + TCompactProtocol.Types.CT_I64, // T_I64 + TCompactProtocol.Types.CT_BINARY, // T_STRING + TCompactProtocol.Types.CT_STRUCT, // T_STRUCT + TCompactProtocol.Types.CT_MAP, // T_MAP + TCompactProtocol.Types.CT_SET, // T_SET + TCompactProtocol.Types.CT_LIST, // T_LIST +]; + + +// +// Compact Protocol Utilities +// + +/** + * Returns the underlying transport layer. + * @return {object} The underlying transport layer. + */TCompactProtocol.prototype.getTransport = function() { + return this.trans; +}; + +/** + * Lookup a Compact Protocol Type value for a given Thrift Type value. + * N.B. Used only internally. + * @param {number} ttype - Thrift type value + * @returns {number} Compact protocol type value + */ +TCompactProtocol.prototype.getCompactType = function(ttype) { + return TCompactProtocol.TTypeToCType[ttype]; +}; + +/** + * Lookup a Thrift Type value for a given Compact Protocol Type value. + * N.B. Used only internally. + * @param {number} type - Compact Protocol type value + * @returns {number} Thrift Type value + */ +TCompactProtocol.prototype.getTType = function(type) { + switch (type) { + case Type.STOP: + return Type.STOP; + case TCompactProtocol.Types.CT_BOOLEAN_FALSE: + case TCompactProtocol.Types.CT_BOOLEAN_TRUE: + return Type.BOOL; + case TCompactProtocol.Types.CT_BYTE: + return Type.BYTE; + case TCompactProtocol.Types.CT_I16: + return Type.I16; + case TCompactProtocol.Types.CT_I32: + return Type.I32; + case TCompactProtocol.Types.CT_I64: + return Type.I64; + case TCompactProtocol.Types.CT_DOUBLE: + return Type.DOUBLE; + case TCompactProtocol.Types.CT_BINARY: + return Type.STRING; + case TCompactProtocol.Types.CT_LIST: + return Type.LIST; + case TCompactProtocol.Types.CT_SET: + return Type.SET; + case TCompactProtocol.Types.CT_MAP: + return Type.MAP; + case TCompactProtocol.Types.CT_STRUCT: + return Type.STRUCT; + default: + throw new TProtocolException(INVALID_DATA, "Unknown type: " + type); + } + return Type.STOP; +}; + + +// +// Compact Protocol write operations +// + +/** + * Send any buffered bytes to the end point. + */ +TCompactProtocol.prototype.flush = function() { + return this.trans.flush(); +}; + +/** + * Writes an RPC message header + * @param {string} name - The method name for the message. + * @param {number} type - The type of message (CALL, REPLY, EXCEPTION, ONEWAY). + * @param {number} seqid - The call sequence number (if any). + */ +TCompactProtocol.prototype.writeMessageBegin = function(name, type, seqid) { + this.writeByte(TCompactProtocol.PROTOCOL_ID); + this.writeByte((TCompactProtocol.VERSION_N & TCompactProtocol.VERSION_MASK) | + ((type << TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_MASK)); + this.writeVarint32(seqid); + this.writeString(name); +}; + +TCompactProtocol.prototype.writeMessageEnd = function() { +}; + +TCompactProtocol.prototype.writeStructBegin = function(name) { + this.lastField_.push(this.lastFieldId_); + this.lastFieldId_ = 0; +}; + +TCompactProtocol.prototype.writeStructEnd = function() { + this.lastFieldId_ = this.lastField_.pop(); +}; + +/** + * Writes a struct field header + * @param {string} name - The field name (not written with the compact protocol). + * @param {number} type - The field data type (a normal Thrift field Type). + * @param {number} id - The IDL field Id. + */ +TCompactProtocol.prototype.writeFieldBegin = function(name, type, id) { + if (type != Type.BOOL) { + return this.writeFieldBeginInternal(name, type, id, -1); + } + + this.booleanField_.name = name; + this.booleanField_.fieldType = type; + this.booleanField_.fieldId = id; +}; + +TCompactProtocol.prototype.writeFieldEnd = function() { +}; + +TCompactProtocol.prototype.writeFieldStop = function() { + this.writeByte(TCompactProtocol.Types.CT_STOP); +}; + +/** + * Writes a map collection header + * @param {number} keyType - The Thrift type of the map keys. + * @param {number} valType - The Thrift type of the map values. + * @param {number} size - The number of k/v pairs in the map. + */ +TCompactProtocol.prototype.writeMapBegin = function(keyType, valType, size) { + if (size === 0) { + this.writeByte(0); + } else { + this.writeVarint32(size); + this.writeByte(this.getCompactType(keyType) << 4 | this.getCompactType(valType)); + } +}; + +TCompactProtocol.prototype.writeMapEnd = function() { +}; + +/** + * Writes a list collection header + * @param {number} elemType - The Thrift type of the list elements. + * @param {number} size - The number of elements in the list. + */ +TCompactProtocol.prototype.writeListBegin = function(elemType, size) { + this.writeCollectionBegin(elemType, size); +}; + +TCompactProtocol.prototype.writeListEnd = function() { +}; + +/** + * Writes a set collection header + * @param {number} elemType - The Thrift type of the set elements. + * @param {number} size - The number of elements in the set. + */ +TCompactProtocol.prototype.writeSetBegin = function(elemType, size) { + this.writeCollectionBegin(elemType, size); +}; + +TCompactProtocol.prototype.writeSetEnd = function() { +}; + +TCompactProtocol.prototype.writeBool = function(value) { + if (booleanField_.name != NULL) { + // we haven't written the field header yet + this.writeFieldBeginInternal(booleanField_.name, + booleanField_.fieldType, + booleanField_.fieldId, + (value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE + : TCompactProtocol.Types.CT_BOOLEAN_FALSE)); + booleanField_.name = NULL; + } else { + // we're not part of a field, so just write the value + this.writeByte((value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE + : TCompactProtocol.Types.CT_BOOLEAN_FALSE)); + } +}; + +TCompactProtocol.prototype.writeByte = function(b) { + this.trans.write(new Buffer([b])); +}; + +TCompactProtocol.prototype.writeI16 = function(i16) { + this.writeVarint32(this.i32ToZigzag(i16)); +}; + +TCompactProtocol.prototype.writeI32 = function(i32) { + this.writeVarint32(this.i32ToZigzag(i32)); +}; + +TCompactProtocol.prototype.writeI64 = function(i64) { + this.writeVarint64(this.i64ToZigzag(i64)); +}; + +TCompactProtocol.prototype.writeDouble = function(dub) { + this.trans.write(binary.writeDouble(new Buffer(8), dub)); +}; + +TCompactProtocol.prototype.writeString = function(arg) { + this.writeBinary(arg); +}; + +TCompactProtocol.prototype.writeBinary = function(arg) { + if (typeof arg === 'string') { + this.writeVarint32(Buffer.byteLength(arg, 'utf8')) ; + this.trans.write(arg, 'utf8'); + } else if (arg instanceof Buffer) { + this.writeVarint32(arg.length); + this.trans.write(arg); + } else { + throw new Error('writeString/writeBinary called without a string/Buffer argument: ' + arg); + } +}; + + +// +// Compact Protocol internal write methods +// + +TCompactProtocol.prototype.writeFieldBeginInternal = function(name, + fieldType, + fieldId, + typeOverride) { + //If there's a type override, use that. + var typeToWrite = (typeOverride == -1 ? this.getCompactType(fieldType) : typeOverride); + //Check if we can delta encode the field id + if (fieldId > this.lastFieldId_ && fieldId - this.lastFieldId_ <= 15) { + //Include the type delta with the field ID + this.writeByte((fieldId - this.lastFieldId_) << 4 | typeToWrite); + } else { + //Write separate type and ID values + this.writeByte(typeToWrite); + this.writeI16(fieldId); + } + this.lastFieldId_ = fieldId; +}; + +TCompactProtocol.prototype.writeCollectionBegin = function(elemType, size) { + if (size <= 14) { + //Combine size and type in one byte if possible + this.writeByte(size << 4 | this.getCompactType(elemType)); + } else { + this.writeByte(0xf0 | this.getCompactType(elemType)); + this.writeVarint32(size); + } +}; + +/** + * Write an i32 as a varint. Results in 1-5 bytes on the wire. + */ +TCompactProtocol.prototype.writeVarint32 = function(n) { + var buf = new Buffer(5); + var wsize = 0; + while (true) { + if ((n & ~0x7F) === 0) { + buf[wsize++] = n; + break; + } else { + buf[wsize++] = ((n & 0x7F) | 0x80); + n = n >>> 7; + } + } + var wbuf = new Buffer(wsize); + buf.copy(wbuf,0,0,wsize); + this.trans.write(wbuf); +}; + +/** + * Write an i64 as a varint. Results in 1-10 bytes on the wire. + * N.B. node-int64 is always big endian + */ +TCompactProtocol.prototype.writeVarint64 = function(n) { + if (typeof n === "number"){ + n = new Int64(n); + } + if (! (n instanceof Int64)) { + throw new TProtocolError(INVALID_DATA, "Expected Int64 or Number, found: " + n); + } + + var buf = new Buffer(10); + var wsize = 0; + var hi = n.buffer.readUInt32BE(0, true); + var lo = n.buffer.readUInt32BE(4, true); + var mask = 0; + while (true) { + if (((lo & ~0x7F) === 0) && (hi === 0)) { + buf[wsize++] = lo; + break; + } else { + buf[wsize++] = ((lo & 0x7F) | 0x80); + mask = hi << 25; + lo = lo >>> 7; + hi = hi >>> 7; + lo = lo | mask; + } + } + var wbuf = new Buffer(wsize); + buf.copy(wbuf,0,0,wsize); + this.trans.write(wbuf); +}; + +/** + * Convert l into a zigzag long. This allows negative numbers to be + * represented compactly as a varint. + */ +TCompactProtocol.prototype.i64ToZigzag = function(l) { + if (typeof l === 'string') { + l = new Int64(parseInt(l, 10)); + } else if (typeof l === 'number') { + l = new Int64(l); + } + if (! (l instanceof Int64)) { + throw new TProtocolException(INVALID_DATA, "Expected Int64 or Number, found: " + l); + } + var hi = l.buffer.readUInt32BE(0, true); + var lo = l.buffer.readUInt32BE(4, true); + var sign = hi >>> 31; + hi = ((hi << 1) | (lo >>> 31)) ^ ((!!sign) ? 0xFFFFFFFF : 0); + lo = (lo << 1) ^ ((!!sign) ? 0xFFFFFFFF : 0); + return new Int64(hi, lo); +}; + +/** + * Convert n into a zigzag int. This allows negative numbers to be + * represented compactly as a varint. + */ +TCompactProtocol.prototype.i32ToZigzag = function(n) { + return (n << 1) ^ ((n & 0x80000000) ? 0xFFFFFFFF : 0); +}; + + +// +// Compact Protocol read operations +// + +TCompactProtocol.prototype.readMessageBegin = function() { + //Read protocol ID + var protocolId = this.trans.readByte(); + if (protocolId != TCompactProtocol.PROTOCOL_ID) { + throw new TProtocolException(BAD_VERSION, "Bad protocol identifier " + protocolId); + } + + //Read Version and Type + var versionAndType = this.trans.readByte(); + var version = (versionAndType & TCompactProtocol.VERSION_MASK); + if (version != TCompactProtocol.VERSION_N) { + throw new TProtocolException(BAD_VERSION, "Bad protocol version " + version); + } + var type = ((versionAndType >> TCompactProtocol.TYPE_SHIFT_AMOUNT) & 0x03); + + //Read SeqId + var seqid = this.readVarint32(); + + //Read name + var name = this.readString(); + + return {fname: name, mtype: type, rseqid: seqid}; +}; + +TCompactProtocol.prototype.readMessageEnd = function() { +}; + +TCompactProtocol.prototype.readStructBegin = function() { + this.lastField_.push(this.lastFieldId_); + this.lastFieldId_ = 0; + return {fname: ''}; +}; + +TCompactProtocol.prototype.readStructEnd = function() { + this.lastFieldId_ = this.lastField_.pop(); +}; + +TCompactProtocol.prototype.readFieldBegin = function() { + var fieldId = 0; + var b = this.trans.readByte(b); + var type = (b & 0x0f); + + if (type == TCompactProtocol.Types.CT_STOP) { + return {fname: null, ftype: Thrift.Type.STOP, fid: 0}; + } + + //Mask off the 4 MSB of the type header to check for field id delta. + var modifier = ((b & 0x000000f0) >>> 4); + if (modifier === 0) { + //If not a delta read the field id. + fieldId = this.readI16(); + } else { + //Recover the field id from the delta + fieldId = (this.lastFieldId_ + modifier); + } + var fieldType = this.getTType(type); + + //Boolean are encoded with the type + if (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE || + type == TCompactProtocol.Types.CT_BOOLEAN_FALSE) { + this.boolValue_.hasBoolValue = true; + this.boolValue_.boolValue = + (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE ? true : false); + } + + //Save the new field for the next delta computation. + this.lastFieldId_ = fieldId; + return {fname: null, ftype: fieldType, fid: fieldId}; +}; + +TCompactProtocol.prototype.readFieldEnd = function() { +}; + +TCompactProtocol.prototype.readMapBegin = function() { + var msize = this.readVarint32(); + if (msize < 0) { + throw new TProtocolException(NEGATIVE_SIZE, "Negative map size"); + } + + var kvtype = 0; + if (msize !== 0) { + kvType = this.trans.readByte(); + } + + var keyType = this.getTType((kvType & 0xf0) >>> 4); + var valType = this.getTType(kvType & 0xf); + return {ktype: keyType, vtype: valType, size: msize}; +}; + +TCompactProtocol.prototype.readMapEnd = function() { +}; + +TCompactProtocol.prototype.readListBegin = function() { + var size_and_type = this.trans.readByte(); + + var lsize = (size_and_type >>> 4) & 0x0000000f; + if (lsize == 15) { + lsize = this.readVarint32(); + } + + if (lsize < 0) { + throw TProtocolException(NEGATIVE_SIZE, "Negative list size"); + } + + var elemType = this.getTType(size_and_type & 0x0000000f); + + return {etype: elemType, size: lsize}; +}; + +TCompactProtocol.prototype.readListEnd = function() { +}; + +TCompactProtocol.prototype.readSetBegin = function() { + return this.readListBegin(); +}; + +TCompactProtocol.prototype.readSetEnd = function() { +}; + +TCompactProtocol.prototype.readBool = function() { + var value = false; + var rsize = 0; + if (this.boolValue_.hasBoolValue === true) { + value = this.boolValue_.boolValue; + this.boolValue_.hasBoolValue = false; + } else { + var res = this.trans.readByte(); + rsize = res.rsize; + value = (res.value == TCompactProtocol.Types.CT_BOOLEAN_TRUE); + } + return value; +}; + +TCompactProtocol.prototype.readByte = function() { + return this.trans.readByte(); +}; + +TCompactProtocol.prototype.readI16 = function() { + return this.readI32(); +}; + +TCompactProtocol.prototype.readI32 = function() { + return this.zigzagToI32(this.readVarint32()); +}; + +TCompactProtocol.prototype.readI64 = function() { + return this.zigzagToI64(this.readVarint64()); +}; + +TCompactProtocol.prototype.readDouble = function() { + return this.trans.readDouble(); +}; + +TCompactProtocol.prototype.readBinary = function() { + var size = this.readVarint32(); + // Catch empty string case + if (size === 0) { + return ""; + } + + // Catch error cases + if (size < 0) { + throw new TProtocolException(NEGATIVE_SIZE, "Negative binary/string size"); + } + var value = this.trans.readString(size); + + return value; +}; + +TCompactProtocol.prototype.readString = function() { + return this.readBinary(); +}; + + +// +// Compact Protocol internal read operations +// + +/** + * Read an i32 from the wire as a varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 5 bytes. + */ +TCompactProtocol.prototype.readVarint32 = function() { + return this.readVarint64(); +}; + +/** + * Read an i64 from the wire as a proper varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 10 bytes. + */ +TCompactProtocol.prototype.readVarint64 = function() { + var rsize = 0; + var lo = 0; + var hi = 0; + var shift = 0; + while (true) { + var b = this.trans.readByte(); + rsize ++; + if (shift <= 25) { + lo = lo | ((b & 0x7f) << shift); + } else if (25 < shift && shift < 32) { + lo = lo | ((b & 0x7f) << shift); + hi = hi | ((b & 0x7f) >>> (32-shift)); + } else { + hi = hi | ((b & 0x7f) << (shift-32)); + } + shift += 7; + if (!(b & 0x80)) { + break; + } + if (rsize >= 10) { + throw new TProtocolException(INVALID_DATA, "Variable-length int over 10 bytes."); + } + } + var i64 = new Int64(hi, lo); + return i64.toNumber(); +}; + +/** + * Convert from zigzag int to int. + */ +TCompactProtocol.prototype.zigzagToI32 = function(n) { + return (n >>> 1) ^ (-1 * (n & 1)); +}; + +/** + * Convert from zigzag long to long. + */ +TCompactProtocol.prototype.zigzagToI64 = function(n) { + var zz = new Int64(n); + var hi = zz.buffer.readUInt32BE(0, true); + var lo = zz.buffer.readUInt32BE(4, true); + + var neg = new Int64(hi & 0, lo & 1); + neg._2scomp(); + var hi_neg = neg.buffer.readUInt32BE(0, true); + var lo_neg = neg.buffer.readUInt32BE(4, true); + + var hi_lo = (hi << 31); + hi = (hi >>> 1) ^ (hi_neg); + lo = ((lo >>> 1) | hi_lo) ^ (lo_neg); + var i64 = new Int64(hi, lo); + return i64.toNumber(); +}; + +TCompactProtocol.prototype.skip = function(type) { + switch (type) { + case Type.STOP: + return; + case Type.BOOL: + this.readBool(); + break; + case Type.BYTE: + this.readByte(); + break; + case Type.I16: + this.readI16(); + break; + case Type.I32: + this.readI32(); + break; + case Type.I64: + this.readI64(); + break; + case Type.DOUBLE: + this.readDouble(); + break; + case Type.STRING: + this.readString(); + break; + case Type.STRUCT: + this.readStructBegin(); + while (true) { + var r = this.readFieldBegin(); + if (r.ftype === Type.STOP) { + break; + } + this.skip(r.ftype); + this.readFieldEnd(); + } + this.readStructEnd(); + break; + case Type.MAP: + var mapBegin = this.readMapBegin(); + for (var i = 0; i < mapBegin.size; ++i) { + this.skip(mapBegin.ktype); + this.skip(mapBegin.vtype); + } + this.readMapEnd(); + break; + case Type.SET: + var setBegin = this.readSetBegin(); + for (var i2 = 0; i2 < setBegin.size; ++i2) { + this.skip(setBegin.etype); + } + this.readSetEnd(); + break; + case Type.LIST: + var listBegin = this.readListBegin(); + for (var i3 = 0; i3 < listBegin.size; ++i3) { + this.skip(listBegin.etype); + } + this.readListEnd(); + break; + default: + throw new Error("Invalid type: " + type); + } +}; + + +// +// JSON PROTOCOL +// +/////////////////////////////////////////////////////////// var TJSONProtocol = exports.TJSONProtocol = function(trans) { this.trans = trans; -} +}; TJSONProtocol.Type = {}; TJSONProtocol.Type[Thrift.Type.BOOL] = '"tf"'; @@ -387,14 +1174,14 @@ TJSONProtocol.Version = 1; TJSONProtocol.prototype.flush = function() { return this.trans.flush(); -} +}; TJSONProtocol.prototype.writeMessageBegin = function(name, messageType, seqid) { this.tstack = []; this.tpos = []; this.tstack.push([TJSONProtocol.Version, '"' + name + '"', messageType, seqid]); -} +}; TJSONProtocol.prototype.writeMessageEnd = function() { var obj = this.tstack.pop(); @@ -405,12 +1192,12 @@ TJSONProtocol.prototype.writeMessageEnd = function() { this.wbuf = '[' + this.wobj.join(',') + ']'; this.trans.write(this.wbuf); -} +}; TJSONProtocol.prototype.writeStructBegin = function(name) { this.tpos.push(this.tstack.length); this.tstack.push({}); -} +}; TJSONProtocol.prototype.writeStructEnd = function() { var p = this.tpos.pop(); @@ -429,14 +1216,14 @@ TJSONProtocol.prototype.writeStructEnd = function() { str += '}'; this.tstack[p] = str; -} +}; TJSONProtocol.prototype.writeFieldBegin = function(name, fieldType, fieldId) { this.tpos.push(this.tstack.length); this.tstack.push({ 'fieldId': '"' + fieldId + '"', 'fieldType': TJSONProtocol.Type[fieldType] }); -} +}; TJSONProtocol.prototype.writeFieldEnd = function() { var value = this.tstack.pop(); @@ -450,16 +1237,16 @@ TJSONProtocol.prototype.writeFieldEnd = function() { fieldInfo.fieldType + ':' + value + '}'; } this.tpos.pop(); -} +}; TJSONProtocol.prototype.writeFieldStop = function() { -} +}; TJSONProtocol.prototype.writeMapBegin = function(ktype, vtype, size) { //size is invalid, we'll set it on end. this.tpos.push(this.tstack.length); this.tstack.push([TJSONProtocol.Type[ktype], TJSONProtocol.Type[vtype], 0]); -} +}; TJSONProtocol.prototype.writeMapEnd = function() { var p = this.tpos.pop(); @@ -494,12 +1281,12 @@ TJSONProtocol.prototype.writeMapEnd = function() { this.tstack[p].push(map); this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; -} +}; TJSONProtocol.prototype.writeListBegin = function(etype, size) { this.tpos.push(this.tstack.length); this.tstack.push([TJSONProtocol.Type[etype], size]); -} +}; TJSONProtocol.prototype.writeListEnd = function() { var p = this.tpos.pop(); @@ -511,12 +1298,12 @@ TJSONProtocol.prototype.writeListEnd = function() { } this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; -} +}; TJSONProtocol.prototype.writeSetBegin = function(etype, size) { this.tpos.push(this.tstack.length); this.tstack.push([TJSONProtocol.Type[etype], size]); -} +}; TJSONProtocol.prototype.writeSetEnd = function() { var p = this.tpos.pop(); @@ -528,31 +1315,31 @@ TJSONProtocol.prototype.writeSetEnd = function() { } this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; -} +}; TJSONProtocol.prototype.writeBool = function(bool) { this.tstack.push(bool ? 1 : 0); -} +}; TJSONProtocol.prototype.writeByte = function(byte) { this.tstack.push(byte); -} +}; TJSONProtocol.prototype.writeI16 = function(i16) { this.tstack.push(i16); -} +}; TJSONProtocol.prototype.writeI32 = function(i32) { this.tstack.push(i32); -} +}; TJSONProtocol.prototype.writeI64 = function(i64) { this.tstack.push(i64); -} +}; TJSONProtocol.prototype.writeDouble = function(dub) { this.tstack.push(dub); -} +}; TJSONProtocol.prototype.writeString = function(str) { // We do not encode uri components for wire transfer: @@ -591,11 +1378,11 @@ TJSONProtocol.prototype.writeString = function(str) { } this.tstack.push('"' + escapedString + '"'); } -} +}; TJSONProtocol.prototype.writeBinary = function(arg) { this.writeString(arg); -} +}; TJSONProtocol.prototype.readMessageBegin = function() { this.rstack = []; @@ -664,10 +1451,10 @@ TJSONProtocol.prototype.readMessageBegin = function() { r.rseqid = this.robj.shift(); this.rstack.push(this.robj.shift()); return r; -} +}; TJSONProtocol.prototype.readMessageEnd = function() { -} +}; TJSONProtocol.prototype.readStructBegin = function() { var r = {}; @@ -679,11 +1466,11 @@ TJSONProtocol.prototype.readStructBegin = function() { } return r; -} +}; TJSONProtocol.prototype.readStructEnd = function() { this.rstack.pop(); -} +}; TJSONProtocol.prototype.readFieldBegin = function() { var r = {}; @@ -728,7 +1515,7 @@ TJSONProtocol.prototype.readFieldBegin = function() { r.fid = fid; return r; -} +}; TJSONProtocol.prototype.readFieldEnd = function() { var pos = this.rpos.pop(); @@ -737,7 +1524,7 @@ TJSONProtocol.prototype.readFieldEnd = function() { while (this.rstack.length > pos) { this.rstack.pop(); } -} +}; TJSONProtocol.prototype.readMapBegin = function() { var map = this.rstack.pop(); @@ -752,11 +1539,11 @@ TJSONProtocol.prototype.readMapBegin = function() { this.rstack.push(map.shift()); return r; -} +}; TJSONProtocol.prototype.readMapEnd = function() { this.readFieldEnd(); -} +}; TJSONProtocol.prototype.readListBegin = function() { var list = this.rstack[this.rstack.length - 1]; @@ -769,19 +1556,19 @@ TJSONProtocol.prototype.readListBegin = function() { this.rstack.push(list); return r; -} +}; TJSONProtocol.prototype.readListEnd = function() { this.readFieldEnd(); -} +}; TJSONProtocol.prototype.readSetBegin = function() { return this.readListBegin(); -} +}; TJSONProtocol.prototype.readSetEnd = function() { return this.readListEnd(); -} +}; TJSONProtocol.prototype.readBool = function() { var r = this.readI32(); @@ -793,15 +1580,15 @@ TJSONProtocol.prototype.readBool = function() { } return r; -} +}; TJSONProtocol.prototype.readByte = function() { return this.readI32(); -} +}; TJSONProtocol.prototype.readI16 = function() { return this.readI32(); -} +}; TJSONProtocol.prototype.readI32 = function(f) { if (f === undefined) { @@ -833,31 +1620,31 @@ TJSONProtocol.prototype.readI32 = function(f) { } return r.value; -} +}; TJSONProtocol.prototype.readI64 = function() { return new Int64(this.readI32()); -} +}; TJSONProtocol.prototype.readDouble = function() { return this.readI32(); -} +}; TJSONProtocol.prototype.readBinary = function() { return this.readString(); -} +}; TJSONProtocol.prototype.readString = function() { var r = this.readI32(); return r; -} +}; TJSONProtocol.prototype.getTransport = function() { return this.trans; -} +}; //Method to arbitrarily skip over data. TJSONProtocol.prototype.skip = function(type) { throw 'skip not supported yet'; -} +}; diff --git a/lib/nodejs/lib/thrift/thrift.js b/lib/nodejs/lib/thrift/thrift.js index 94223e35..aabe11f5 100644 --- a/lib/nodejs/lib/thrift/thrift.js +++ b/lib/nodejs/lib/thrift/thrift.js @@ -36,19 +36,19 @@ var Type = exports.Type = { LIST: 15, UTF8: 16, UTF16: 17, -} +}; exports.MessageType = { CALL: 1, REPLY: 2, EXCEPTION: 3, ONEWAY: 4, -} +}; var TException = exports.TException = function(message) { Error.call(this, message); this.name = 'TException'; -} +}; util.inherits(TException, Error); var TApplicationExceptionType = exports.TApplicationExceptionType = { @@ -63,81 +63,73 @@ var TApplicationExceptionType = exports.TApplicationExceptionType = { INVALID_TRANSFORM: 8, INVALID_PROTOCOL: 9, UNSUPPORTED_CLIENT_TYPE: 10 -} +}; var TApplicationException = exports.TApplicationException = function(type, message) { TException.call(this, message); this.type = type || TApplicationExceptionType.UNKNOWN; this.name = 'TApplicationException'; -} +}; util.inherits(TApplicationException, TException); TApplicationException.prototype.read = function(input) { - var ftype - var fid - var ret = input.readStructBegin('TApplicationException') + var ftype; + var ret = input.readStructBegin('TApplicationException'); while(1){ - - ret = input.readFieldBegin() - + ret = input.readFieldBegin(); if(ret.ftype == Type.STOP) - break - - var fid = ret.fid + break; - switch(fid){ + switch(ret.fid){ case 1: if( ret.ftype == Type.STRING ){ - ret = input.readString() - this.message = ret + ret = input.readString(); + this.message = ret; } else { - ret = input.skip(ret.ftype) + ret = input.skip(ret.ftype); } - - break + break; case 2: if( ret.ftype == Type.I32 ){ - ret = input.readI32() - this.type = ret + ret = input.readI32(); + this.type = ret; } else { - ret = input.skip(ret.ftype) + ret = input.skip(ret.ftype); } - break - + break; default: - ret = input.skip(ret.ftype) - break + ret = input.skip(ret.ftype); + break; } - input.readFieldEnd() + input.readFieldEnd(); } - - input.readStructEnd() -} + input.readStructEnd(); +}; TApplicationException.prototype.write = function(output){ output.writeStructBegin('TApplicationException'); if (this.message) { - output.writeFieldBegin('message', Type.STRING, 1) - output.writeString(this.message) - output.writeFieldEnd() + output.writeFieldBegin('message', Type.STRING, 1); + output.writeString(this.message); + output.writeFieldEnd(); } if (this.code) { - output.writeFieldBegin('type', Type.I32, 2) - output.writeI32(this.code) - output.writeFieldEnd() + output.writeFieldBegin('type', Type.I32, 2); + output.writeI32(this.code); + output.writeFieldEnd(); } - output.writeFieldStop() - output.writeStructEnd() -} + output.writeFieldStop(); + output.writeStructEnd(); +}; exports.objectLength = function(obj) { return Object.keys(obj).length; -} +}; exports.inherits = function(constructor, superConstructor) { util.inherits(constructor, superConstructor); -} +}; diff --git a/lib/nodejs/lib/thrift/transport.js b/lib/nodejs/lib/thrift/transport.js index 2926d008..8423f897 100644 --- a/lib/nodejs/lib/thrift/transport.js +++ b/lib/nodejs/lib/thrift/transport.js @@ -169,7 +169,7 @@ TFramedTransport.prototype = { if (this.onFlush) { // TODO: optimize this better, allocate one buffer instead of both: var msg = new Buffer(out.length + 4); - binary.writeI32(msg, out.length) + binary.writeI32(msg, out.length); frameLeft = binary.readI32(this.inBuf, 0); out.copy(msg, 4, 0, out.length); this.onFlush(msg); @@ -235,7 +235,7 @@ TBufferedTransport.prototype = { }, read: function(len) { - this.ensureAvailable(len) + this.ensureAvailable(len); var buf = new Buffer(len); this.inBuf.copy(buf, 0, this.readCursor, this.readCursor + len); this.readCursor += len; @@ -243,33 +243,33 @@ TBufferedTransport.prototype = { }, readByte: function() { - this.ensureAvailable(1) + this.ensureAvailable(1); return binary.readByte(this.inBuf[this.readCursor++]); }, readI16: function() { - this.ensureAvailable(2) + this.ensureAvailable(2); var i16 = binary.readI16(this.inBuf, this.readCursor); this.readCursor += 2; return i16; }, readI32: function() { - this.ensureAvailable(4) + this.ensureAvailable(4); var i32 = binary.readI32(this.inBuf, this.readCursor); this.readCursor += 4; return i32; }, readDouble: function() { - this.ensureAvailable(8) + this.ensureAvailable(8); var d = binary.readDouble(this.inBuf, this.readCursor); this.readCursor += 8; return d; }, readString: function(len) { - this.ensureAvailable(len) + this.ensureAvailable(len); var str = this.inBuf.toString('utf8', this.readCursor, this.readCursor + len); this.readCursor += len; return str; diff --git a/lib/nodejs/test/client.js b/lib/nodejs/test/client.js index 8813f913..d57676ee 100644 --- a/lib/nodejs/test/client.js +++ b/lib/nodejs/test/client.js @@ -41,6 +41,8 @@ program var protocol = thrift.TBinaryProtocol; if (program.protocol === "json") { protocol = thrift.TJSONProtocol; +} else if (program.protocol === "compact") { + protocol = thrift.TCompactProtocol; } var transport = thrift.TBufferedTransport; diff --git a/lib/nodejs/test/server.js b/lib/nodejs/test/server.js index 605c7003..6afff078 100644 --- a/lib/nodejs/test/server.js +++ b/lib/nodejs/test/server.js @@ -41,6 +41,8 @@ if (program.transport === "framed") { var protocol = thrift.TBinaryProtocol; if (program.protocol === "json") { protocol = thrift.TJSONProtocol; +} else if (program.protocol === "compact") { + protocol = thrift.TCompactProtocol; } var handler = ThriftTestHandler; diff --git a/lib/nodejs/test/testAll.sh b/lib/nodejs/test/testAll.sh index 9d1da3fc..41c33cfa 100755 --- a/lib/nodejs/test/testAll.sh +++ b/lib/nodejs/test/testAll.sh @@ -73,6 +73,8 @@ node ${DIR}/binary.test.js || TESTOK=1 #integration tests #TCP connection tests +testClientServer compact buffered || TESTOK=1 +testClientServer compact framed || TESTOK=1 testClientServer binary buffered || TESTOK=1 testClientServer json buffered || TESTOK=1 testClientServer binary framed || TESTOK=1 @@ -82,7 +84,7 @@ testClientServer json framed || TESTOK=1 testMultiplexedClientServer binary buffered || TESTOK=1 testMultiplexedClientServer json buffered || TESTOK=1 testMultiplexedClientServer binary framed || TESTOK=1 -testMultiplexedClientServer json framed || TESTOK=1 +testMultiplexedClientServer compact framed || TESTOK=1 #test ssl connection testClientServer binary framed --ssl || TESTOK=1 @@ -90,8 +92,11 @@ testMultiplexedClientServer binary framed --ssl || TESTOK=1 #test promise style testClientServer binary framed --promise || TESTOK=1 +testClientServer compact buffered --promise || TESTOK=1 #HTTP tests +testHttpClientServer compact buffered || TESTOK=1 +testHttpClientServer compact framed || TESTOK=1 testHttpClientServer json buffered || TESTOK=1 testHttpClientServer json framed || TESTOK=1 testHttpClientServer binary buffered || TESTOK=1 diff --git a/lib/nodejs/test/thrift_test_driver.js b/lib/nodejs/test/thrift_test_driver.js index 02613ec6..b1d744b6 100644 --- a/lib/nodejs/test/thrift_test_driver.js +++ b/lib/nodejs/test/thrift_test_driver.js @@ -146,11 +146,21 @@ client.testI64(-5, function(err, response) { assert.equal(-5, response); }); +client.testI64(734359738368, function(err, response) { + assert( ! err); + assert.equal(734359738368, response); +}); + client.testI64(-34359738368, function(err, response) { assert( ! err); assert.equal(-34359738368, response); }); +client.testI64(-734359738368, function(err, response) { + assert( ! err); + assert.equal(-734359738368, response); +}); + client.testDouble(-5.2098523, function(err, response) { assert( ! err); assert.equal(-5.2098523, response); @@ -192,21 +202,22 @@ client.testMap(mapout, function(err, response) { var mapTestInput = { "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key", - "longValue":stringTest, stringTest:"long key" + "longValue":stringTest, "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, ":"long key" }; client.testStringMap(mapTestInput, function(err, response) { assert( ! err); assert.deepEqual(mapTestInput, response); }); -var setTestInput = [1,2,3]; -client.testSet(setTestInput, function(err, response) { +var setTestSetInput = [1,2,3]; +client.testSet(setTestSetInput, function(err, response) { assert( ! err); - assert.deepEqual(setTestInput, response); + assert.deepEqual(setTestSetInput, response); }); -client.testList(setTestInput, function(err, response) { +var setTestListInput = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]; +client.testList(setTestListInput, function(err, response) { assert( ! err); - assert.deepEqual(setTestInput, response); + assert.deepEqual(setTestListInput, response); }); client.testEnum(ttypes.Numberz.ONE, function(err, response) { @@ -223,7 +234,7 @@ var mapMapTest = { "4": {"1":1, "2":2, "3":3, "4":4}, "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1} }; -client.testMapMap(mapMapTest, function(err, response) { +client.testMapMap(1, function(err, response) { assert( ! err); assert.deepEqual(mapMapTest, response); }); diff --git a/lib/nodejs/test/thrift_test_driver_promise.js b/lib/nodejs/test/thrift_test_driver_promise.js index 22e2572a..22175cb5 100644 --- a/lib/nodejs/test/thrift_test_driver_promise.js +++ b/lib/nodejs/test/thrift_test_driver_promise.js @@ -289,7 +289,7 @@ var mapMapTest = { "4": {"1":1, "2":2, "3":3, "4":4}, "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1} }; -client.testMapMap(mapMapTest) +client.testMapMap(1) .then(function(response) { assert.deepEqual(mapMapTest, response); })