THRIFT-1033: node.js target and lib
git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1056613 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/nodejs/README.md b/lib/nodejs/README.md
new file mode 100644
index 0000000..2832c1b
--- /dev/null
+++ b/lib/nodejs/README.md
@@ -0,0 +1,60 @@
+# 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.
+
+
+NOTE: you must use the framed thrift transport, TFramedTransport in most
+implementations, on the server side. Using a popular example, this is enabled
+by default in Cassandra 0.7 (but configuration must be changed in Cassandra
+0.6.x and earlier).
+
+## Install
+
+ npm install thrift
+
+## Thrift Compiler
+
+You can compile nodejs sources by running the following:
+
+ thrift --gen js:node thrift_file
+
+## Cassandra Client Example:
+
+Here is a Cassandra example:
+
+ var thrift = require('thrift'),
+ Cassandra = require('./gen-nodejs/Cassandra')
+ ttypes = require('./gen-nodejs/cassandra_types');
+
+ var connection = thrift.createConnection("localhost", 9160),
+ client = thrift.createClient(Cassandra, connection);
+
+ connection.on('error', function(err) {
+ console.error(err);
+ });
+
+ client.get_slice("Keyspace", "key", new ttypes.ColumnParent({column_family: "ExampleCF"}), new ttypes.SlicePredicate({slice_range: new ttypes.SliceRange({start: '', finish: ''})}), ttypes.ConsistencyLevel.ONE, function(err, data) {
+ if (err) {
+ // handle err
+ } else {
+ // data == [ttypes.ColumnOrSuperColumn, ...]
+ }
+ connection.end();
+ });
+
+## Custom client and server example
+
+An example based on the one shown on the Thrift front page is included in the examples/ folder.
diff --git a/lib/nodejs/examples/Makefile b/lib/nodejs/examples/Makefile
new file mode 100644
index 0000000..1930279
--- /dev/null
+++ b/lib/nodejs/examples/Makefile
@@ -0,0 +1,18 @@
+# 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.
+ALL:
+ ../../../compiler/cpp/thrift --gen js:node user.thrift
diff --git a/lib/nodejs/examples/README.md b/lib/nodejs/examples/README.md
new file mode 100644
index 0000000..a87581f
--- /dev/null
+++ b/lib/nodejs/examples/README.md
@@ -0,0 +1,29 @@
+# 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.
+# Running the user example
+
+#Generate the bindings:
+../../../compiler/cpp/thrift --gen js:node user.thrift
+
+#To run the user example, first start up the server in one terminal:
+NODE_PATH=../lib:../lib/thrift node server.js
+
+#Now run the client:
+NODE_PATH=../lib:../lib/thrift node client.js
+
+
+
diff --git a/lib/nodejs/examples/client.js b/lib/nodejs/examples/client.js
new file mode 100644
index 0000000..c83b342
--- /dev/null
+++ b/lib/nodejs/examples/client.js
@@ -0,0 +1,49 @@
+/*
+ * 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 = require('thrift');
+
+var UserStorage = require('./gen-nodejs/UserStorage.js'),
+ ttypes = require('./gen-nodejs/user_types');
+
+var connection = thrift.createConnection('localhost', 9090),
+ client = thrift.createClient(UserStorage, connection);
+
+var user = new ttypes.UserProfile({uid: 1,
+ name: "Mark Slee",
+ blurb: "I'll find something to put here."});
+
+connection.on('error', function(err) {
+ console.error(err);
+});
+
+client.store(user, function(err, response) {
+ if (err) {
+ console.error(err);
+ } else {
+ console.log("client stored:", user.uid);
+ client.retrieve(user.uid, function(err, responseUser) {
+ if (err) {
+ console.error(err);
+ } else {
+ console.log("client retrieved:", responseUser.uid);
+ connection.end();
+ }
+ });
+ }
+});
diff --git a/lib/nodejs/examples/server.js b/lib/nodejs/examples/server.js
new file mode 100644
index 0000000..3b8c046
--- /dev/null
+++ b/lib/nodejs/examples/server.js
@@ -0,0 +1,39 @@
+/*
+ * 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 = require('thrift');
+
+var UserStorage = require('./gen-nodejs/UserStorage.js'),
+ ttypes = require('./gen-nodejs/user_types');
+
+var users = {};
+
+var server = thrift.createServer(UserStorage, {
+ store: function(user, success) {
+ console.log("server stored:", user.uid);
+ users[user.uid] = user;
+ success();
+ },
+
+ retrieve: function(uid, success) {
+ console.log("server retrieved:", uid);
+ success(users[uid]);
+ },
+});
+
+server.listen(9090);
diff --git a/lib/nodejs/examples/user.thrift b/lib/nodejs/examples/user.thrift
new file mode 100644
index 0000000..ee260e5
--- /dev/null
+++ b/lib/nodejs/examples/user.thrift
@@ -0,0 +1,27 @@
+# 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.
+
+struct UserProfile {
+ 1: i32 uid,
+ 2: string name,
+ 3: string blurb
+}
+
+service UserStorage {
+ void store(1: UserProfile user),
+ UserProfile retrieve(1: i32 uid)
+}
diff --git a/lib/nodejs/lib/thrift/binary_parser.js b/lib/nodejs/lib/thrift/binary_parser.js
new file mode 100644
index 0000000..2aeda46
--- /dev/null
+++ b/lib/nodejs/lib/thrift/binary_parser.js
@@ -0,0 +1,274 @@
+/*
+ * 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 sys = require('sys');
+var chr = String.fromCharCode;
+
+var p = exports.BinaryParser = function( bigEndian, allowExceptions ){
+ this.bigEndian = bigEndian || true;
+ this.allowExceptions = allowExceptions;
+};
+p.bigEndian = true;
+
+var IBuffer = exports.BinaryParser.IBuffer = function( bigEndian, buffer ){
+ this.bigEndian = bigEndian || 1;
+ this.buffer = [];
+ this.setBuffer( buffer );
+};
+
+IBuffer.prototype.setBuffer = function( data ){
+ if( data ){
+ for( var l, i = l = data.length, b = this.buffer = new Array( l ); i; b[l - i] = data[--i] );
+ this.bigEndian && b.reverse();
+ }
+};
+
+IBuffer.prototype.hasNeededBits = function( neededBits ){
+ return this.buffer.length >= -( -neededBits >> 3 );
+};
+
+IBuffer.prototype.checkBuffer = function( neededBits ){
+ if( !this.hasNeededBits( neededBits ) ) {
+ console.log("missing: " + neededBits + " " + this.buffer.length);
+ throw new Error( "checkBuffer::missing bytes" );
+ }
+};
+
+IBuffer.prototype.readBits = function( start, length ){
+ //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
+ function shl( a, b ){
+ for( ; b--; a = ( ( a %= 0x7fffffff + 1 ) & 0x40000000 ) == 0x40000000 ? a * 2 : ( a - 0x40000000 ) * 2 + 0x7fffffff + 1 );
+ return a;
+ }
+ if( start < 0 || length <= 0 )
+ return 0;
+ this.checkBuffer( start + length );
+ for( var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - ( start >> 3 ) - 1, lastByte = this.buffer.length + ( -( start + length ) >> 3 ), diff = curByte - lastByte, sum = ( ( this.buffer[ curByte ] >> offsetRight ) & ( ( 1 << ( diff ? 8 - offsetRight : length ) ) - 1 ) ) + ( diff && ( offsetLeft = ( start + length ) % 8 ) ? ( this.buffer[ lastByte++ ] & ( ( 1 << offsetLeft ) - 1 ) ) << ( diff-- << 3 ) - offsetRight : 0 ); diff; sum += shl( this.buffer[ lastByte++ ], ( diff-- << 3 ) - offsetRight ) );
+ return sum;
+};
+
+p.warn = function( msg ){
+ if( this.allowExceptions )
+ throw new Error( msg );
+ return 1;
+};
+p.decodeFloat = function( data, precisionBits, exponentBits ){
+ var b = new this.IBuffer( this.bigEndian, data );
+ b.checkBuffer( precisionBits + exponentBits + 1 );
+ var bias = Math.pow( 2, exponentBits - 1 ) - 1, signal = b.readBits( precisionBits + exponentBits, 1 ), exponent = b.readBits( precisionBits, exponentBits ), significand = 0,
+ divisor = 2, curByte = b.buffer.length + ( -precisionBits >> 3 ) - 1;
+ do{
+ for( var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
+ }while( precisionBits -= startBit );
+ return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 );
+};
+p.decodeInt = function( data, bits, signed, forceBigEndian ){
+ //console.log("decodeInt: ", data, bits, signed);
+ var b = new this.IBuffer( this.bigEndian||forceBigEndian, data ), x = b.readBits( 0, bits ), max = Math.pow( 2, bits );
+ return signed && x >= max / 2 ? x - max : x;
+};
+p.encodeFloat = function( data, precisionBits, exponentBits ){
+ var bias = Math.pow( 2, exponentBits - 1 ) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits,
+ status = isNaN( n = parseFloat( data ) ) || n == -Infinity || n == +Infinity ? n : 0,
+ exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array( len ),
+ signal = ( n = status !== 0 ? 0 : n ) < 0, n = Math.abs( n ), intPart = Math.floor( n ), floatPart = n - intPart,
+ i, lastBit, rounded, j, result;
+ for( i = len; i; bin[--i] = 0 );
+ for( i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor( intPart / 2 ) );
+ for( i = bias + 1; floatPart > 0 && i; ( bin[++i] = ( ( floatPart *= 2 ) >= 1 ) - 0 ) && --floatPart );
+ for( i = -1; ++i < len && !bin[i]; );
+ if( bin[( lastBit = precisionBits - 1 + ( i = ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - ( exp = minExp - 1 ) ) ) + 1] ){
+ if( !( rounded = bin[lastBit] ) ){
+ for( j = lastBit + 2; !rounded && j < len; rounded = bin[j++] );
+ }
+ for( j = lastBit + 1; rounded && --j >= 0; ( bin[j] = !bin[j] - 0 ) && ( rounded = 0 ) );
+ }
+ for( i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i]; );
+ if( ( exp = bias + 1 - i ) >= minExp && exp <= maxExp )
+ ++i;
+ else if( exp < minExp ){
+ exp != bias + 1 - len && exp < minUnnormExp && this.warn( "encodeFloat::float underflow" );
+ i = bias + 1 - ( exp = minExp - 1 );
+ }
+ if( intPart || status !== 0 ){
+ this.warn( intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status );
+ exp = maxExp + 1;
+ i = bias + 2;
+ if( status == -Infinity )
+ signal = 1;
+ else if( isNaN( status ) )
+ bin[i] = 1;
+ }
+ for( n = Math.abs( exp + bias ), j = exponentBits + 1, result = ""; --j; result = ( n % 2 ) + result, n = n >>= 1 );
+ for( n = 0, j = 0, i = ( result = ( signal ? "1" : "0" ) + result + bin.slice( i, i + precisionBits ).join( "" ) ).length, r = []; i; j = ( j + 1 ) % 8 ){
+ n += ( 1 << j ) * result.charAt( --i );
+ if( j == 7 ){
+ r[r.length] = n;
+ n = 0;
+ }
+ }
+ if (n) {
+ r[r.length] = n;
+ }
+ return new Buffer( this.bigEndian ? r.reverse() : r );
+};
+p.encodeInt = function( data, bits, signed, forceBigEndian ){
+ var max = Math.pow( 2, bits );
+ ( data >= max || data < -( max / 2 ) ) && this.warn( "encodeInt::overflow" ) && ( data = 0 );
+ data < 0 && ( data += max );
+ for( var r = []; data; r[r.length] = data % 256, data = Math.floor( data / 256 ) );
+ for( bits = -( -bits >> 3 ) - r.length; bits--; r[r.length] = 0 );
+ return new Buffer((this.bigEndian||forceBigEndian) ? r.reverse() : r );
+};
+p.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
+p.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
+p.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
+p.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
+p.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
+p.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
+p.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
+p.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
+p.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
+p.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
+p.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
+p.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
+p.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
+p.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
+p.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
+p.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
+p.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
+p.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
+p.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
+p.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
+
+// Factor out the encode so it can be shared by add_header and push_int32
+p.encode_int32 = function(number) {
+ var a, b, c, d, unsigned;
+ unsigned = (number < 0) ? (number + 0x100000000) : number;
+ a = Math.floor(unsigned / 0xffffff);
+ unsigned &= 0xffffff;
+ b = Math.floor(unsigned / 0xffff);
+ unsigned &= 0xffff;
+ c = Math.floor(unsigned / 0xff);
+ unsigned &= 0xff;
+ d = Math.floor(unsigned);
+ return chr(a) + chr(b) + chr(c) + chr(d);
+};
+
+p.encode_int64 = function(number) {
+ var a, b, c, d, e, f, g, h, unsigned;
+ unsigned = (number < 0) ? (number + 0x10000000000000000) : number;
+ a = Math.floor(unsigned / 0xffffffffffffff);
+ unsigned &= 0xffffffffffffff;
+ b = Math.floor(unsigned / 0xffffffffffff);
+ unsigned &= 0xffffffffffff;
+ c = Math.floor(unsigned / 0xffffffffff);
+ unsigned &= 0xffffffffff;
+ d = Math.floor(unsigned / 0xffffffff);
+ unsigned &= 0xffffffff;
+ e = Math.floor(unsigned / 0xffffff);
+ unsigned &= 0xffffff;
+ f = Math.floor(unsigned / 0xffff);
+ unsigned &= 0xffff;
+ g = Math.floor(unsigned / 0xff);
+ unsigned &= 0xff;
+ h = Math.floor(unsigned);
+ return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h);
+};
+
+/**
+ UTF8 methods
+**/
+
+// Take a raw binary string and return a utf8 string
+p.decode_utf8 = function(a) {
+ var string = "";
+ var i = 0;
+ var c = c1 = c2 = 0;
+
+ while ( i < a.length ) {
+ c = a.charCodeAt(i);
+ if (c < 128) {
+ string += String.fromCharCode(c);
+ i++;
+ } else if((c > 191) && (c < 224)) {
+ c2 = a.charCodeAt(i+1);
+ string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+ i += 2;
+ } else {
+ c2 = a.charCodeAt(i+1);
+ c3 = a.charCodeAt(i+2);
+ string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+ i += 3;
+ }
+ }
+ return string;
+};
+
+// Encode a cstring correctly
+p.encode_cstring = function(s) {
+ return unescape(encodeURIComponent(s)) + p.fromByte(0);
+};
+
+// Take a utf8 string and return a binary string
+p.encode_utf8 = function(s) {
+ var a="";
+ for (var n=0; n< s.length; n++) {
+ var c=s.charCodeAt(n);
+ if (c<128) {
+ a += String.fromCharCode(c);
+ } else if ((c>127)&&(c<2048)) {
+ a += String.fromCharCode( (c>>6) | 192) ;
+ a += String.fromCharCode( (c&63) | 128);
+ } else {
+ a += String.fromCharCode( (c>>12) | 224);
+ a += String.fromCharCode( ((c>>6) & 63) | 128);
+ a += String.fromCharCode( (c&63) | 128);
+ }
+ }
+ return a;
+};
+
+p.hprint = function(s) {
+ for (var i=0; i<s.length; i++) {
+ if (s.charCodeAt(i)<32) {
+ var number = s.charCodeAt(i) <= 15 ? "0" + s.charCodeAt(i).toString(16) : s.charCodeAt(i).toString(16);
+ sys.debug(number+' : ');}
+ else {
+ var number = s.charCodeAt(i) <= 15 ? "0" + s.charCodeAt(i).toString(16) : s.charCodeAt(i).toString(16);
+ sys.debug(number+' : '+ s.charAt(i));}
+ }
+};
+
+p.to_byte_array = function(s) {
+ var array = [];
+
+ for (var i=0; i<s.length; i++) {
+ if (s.charCodeAt(i)<32) {array.push(s.charCodeAt(i));}
+ else {array.push(s.charCodeAt(i))}
+ }
+
+ sys.puts(array);
+}
+
+p.pprint = function(s) {
+ for (var i=0; i<s.length; i++) {
+ if (s.charCodeAt(i)<32) {sys.puts(s.charCodeAt(i)+' : ');}
+ else {sys.puts(s.charCodeAt(i)+' : '+ s.charAt(i));}
+ }
+};
diff --git a/lib/nodejs/lib/thrift/connection.js b/lib/nodejs/lib/thrift/connection.js
new file mode 100644
index 0000000..e469f49
--- /dev/null
+++ b/lib/nodejs/lib/thrift/connection.js
@@ -0,0 +1,150 @@
+/*
+ * 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 sys = require('sys'),
+ EventEmitter = require("events").EventEmitter,
+ net = require('net'),
+ TMemoryBuffer = require('./transport').TMemoryBuffer,
+ TBinaryProtocol = require('./protocol').TBinaryProtocol;
+
+var BinaryParser = require('./binary_parser').BinaryParser;
+BinaryParser.bigEndian = true;
+
+var int32FramedReceiver = exports.int32FramedReceiver = function (callback) {
+ var frameLeft = 0,
+ framePos = 0,
+ frame = null;
+
+ return function(data) {
+ // var buf = new Buffer(data, 'binary');
+ // console.log(buf);
+ // framed transport
+ while (data.length) {
+ if (frameLeft === 0) {
+ // TODO assumes we have all 4 bytes
+ if (data.length < 4) {
+ throw Error("Not enough bytes");
+ }
+ frameLeft = BinaryParser.toInt(data.slice(0,4));
+ frame = new Buffer(frameLeft);
+ framePos = 0;
+ data = data.slice(4, data.length);
+ }
+
+ if (data.length >= frameLeft) {
+ data.copy(frame, framePos, 0, frameLeft);
+ data = data.slice(frameLeft, data.length);
+
+ frameLeft = 0;
+ callback(frame);
+ } else if (data.length) {
+ data.copy(frame, framePos, 0, data.length);
+ frameLeft -= data.length;
+ framePos += data.length;
+ data = data.slice(data.length, data.length);
+ }
+ }
+ };
+}
+
+var Connection = exports.Connection = function(stream, options) {
+ var self = this;
+ EventEmitter.call(this);
+
+ this.connection = stream;
+ this.offline_queue = [];
+ this.options = options || {};
+ this.connected = false;
+
+ this.connection.addListener("connect", function() {
+ self.connected = true;
+ this.setTimeout(self.options.timeout || 0);
+ this.setNoDelay();
+ this.frameLeft = 0;
+ this.framePos = 0;
+ this.frame = null;
+
+ self.offline_queue.forEach(function(data) {
+ self.connection.write(data);
+ });
+
+ self.emit("connect");
+ });
+
+ this.connection.addListener("error", function(err) {
+ self.emit("error", err);
+ });
+
+ // Add a close listener
+ this.connection.addListener("close", function() {
+ self.emit("close");
+ });
+
+ this.connection.addListener("timeout", function() {
+ self.emit("timeout");
+ });
+
+ this.connection.addListener("data", int32FramedReceiver(function(data) {
+ // console.log(typeof(data));
+ var input = new TBinaryProtocol(new TMemoryBuffer(data));
+ var r = input.readMessageBegin();
+ // console.log(r);
+ self.client['recv_' + r.fname](input, r.mtype, r.rseqid);
+ // self.emit("data", data);
+ }));
+}
+sys.inherits(Connection, EventEmitter);
+
+exports.createConnection = function(host, port, options) {
+ var stream = net.createConnection(port, host);
+ var connection = new Connection(stream, options);
+ connection.host = host;
+ connection.port = port;
+
+ return connection;
+}
+
+exports.createClient = function(cls, connection) {
+ if (cls.Client) {
+ cls = cls.Client;
+ }
+ var client = new cls(new TMemoryBuffer(undefined, function(buf) {
+ connection.write(buf);
+ }), TBinaryProtocol);
+
+ // TODO clean this up
+ connection.client = client;
+
+ return client;
+}
+
+Connection.prototype.end = function() {
+ this.connection.end();
+}
+
+Connection.prototype.write = function(buf) {
+ // TODO: optimize this better, allocate one buffer instead of both:
+ var msg = new Buffer(buf.length + 4);
+ BinaryParser.fromInt(buf.length).copy(msg, 0, 0, 4);
+ buf.copy(msg, 4, 0, buf.length);
+ if (!this.connected) {
+ this.offline_queue.push(msg);
+ } else {
+ this.connection.write(msg);
+ }
+}
diff --git a/lib/nodejs/lib/thrift/index.js b/lib/nodejs/lib/thrift/index.js
new file mode 100644
index 0000000..f4fa3cd
--- /dev/null
+++ b/lib/nodejs/lib/thrift/index.js
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+exports.Thrift = require('./thrift');
+
+var connection = require('./connection');
+exports.Connection = connection.Connection;
+exports.createClient = connection.createClient;
+exports.createConnection = connection.createConnection;
+
+exports.createServer = require('./server').createServer;
diff --git a/lib/nodejs/lib/thrift/protocol.js b/lib/nodejs/lib/thrift/protocol.js
new file mode 100644
index 0000000..f333bb9
--- /dev/null
+++ b/lib/nodejs/lib/thrift/protocol.js
@@ -0,0 +1,337 @@
+/*
+ * 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 sys = require('sys'),
+ Thrift = require('./thrift'),
+ Type = Thrift.Type;
+
+var BinaryParser = require('./binary_parser').BinaryParser;
+BinaryParser.bigEndian = true;
+
+var UNKNOWN = 0,
+ INVALID_DATA = 1,
+ NEGATIVE_SIZE = 2,
+ SIZE_LIMIT = 3,
+ BAD_VERSION = 4;
+
+var TProtocolException = function(type, message) {
+ Error.call(this, message);
+ this.name = 'TProtocolException';
+ this.type = type;
+}
+sys.inherits(TProtocolException, Error);
+
+var TBinaryProtocol = exports.TBinaryProtocol = function(trans, strictRead, strictWrite) {
+ this.trans = trans;
+ this.strictRead = (strictRead !== undefined ? strictRead : false);
+ this.strictWrite = (strictWrite !== undefined ? strictWrite : true);
+}
+
+TBinaryProtocol.prototype.flush = function() {
+ return this.trans.flush();
+}
+
+// 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
+ VERSION_1 = -2147418112, // 0x80010000
+ TYPE_MASK = 0x000000ff;
+
+TBinaryProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
+ if (this.strictWrite) {
+ this.writeI32(VERSION_1 | type);
+ this.writeString(name);
+ this.writeI32(seqid);
+ } else {
+ this.writeString(name);
+ 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) {
+ console.log('write set', etype, size);
+ this.writeByte(etype);
+ this.writeI32(size);
+}
+
+TBinaryProtocol.prototype.writeSetEnd = function() {
+}
+
+TBinaryProtocol.prototype.writeBool = function(bool) {
+ if (bool) {
+ this.writeByte(1);
+ } else {
+ this.writeByte(0);
+ }
+}
+
+TBinaryProtocol.prototype.writeByte = function(byte) {
+ this.trans.write(BinaryParser.fromByte(byte));
+}
+
+TBinaryProtocol.prototype.writeI16 = function(i16) {
+ this.trans.write(BinaryParser.fromShort(i16));
+}
+
+TBinaryProtocol.prototype.writeI32 = function(i32) {
+ this.trans.write(BinaryParser.fromInt(i32));
+}
+
+TBinaryProtocol.prototype.writeI64 = function(i64) {
+ this.trans.write(BinaryParser.fromLong(i64));
+}
+
+TBinaryProtocol.prototype.writeDouble = function(dub) {
+ this.trans.write(BinaryParser.fromDouble(dub));
+}
+
+TBinaryProtocol.prototype.writeString = function(str) {
+ this.writeI32(str.length);
+ this.trans.write(str);
+}
+
+TBinaryProtocol.prototype.readMessageBegin = function() {
+ var sz = this.readI32();
+ var type, name, seqid;
+
+ if (sz < 0) {
+ var version = sz & VERSION_MASK;
+ if (version != VERSION_1) {
+ console.log("BAD: " + version);
+ throw TProtocolException(BAD_VERSION, "Bad version in readMessageBegin: " + sz);
+ }
+ type = sz & TYPE_MASK;
+ name = this.readString();
+ seqid = this.readI32();
+ } else {
+ if (this.strictRead) {
+ throw TProtocolException(BAD_VERSION, "No protocol version header");
+ }
+ name = this.trans.read(sz);
+ type = this.readByte();
+ seqid = this.readI32();
+ }
+ return {fname: name, mtype: type, rseqid: seqid};
+}
+
+TBinaryProtocol.prototype.readMessageEnd = function() {
+}
+
+TBinaryProtocol.prototype.readStructBegin = function() {
+ return {fname: ''}
+}
+
+TBinaryProtocol.prototype.readStructEnd = function() {
+}
+
+TBinaryProtocol.prototype.readFieldBegin = function() {
+ var type = this.readByte();
+ if (type == Type.STOP) {
+ return {fname: null, ftype: type, fid: 0};
+ }
+ 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) {
+ return false;
+ }
+ return true;
+}
+
+TBinaryProtocol.prototype.readByte = function() {
+ var buff = this.trans.read(1);
+ return BinaryParser.toByte(buff);
+}
+
+TBinaryProtocol.prototype.readI16 = function() {
+ var buff = this.trans.read(2);
+ return BinaryParser.toShort(buff);
+}
+
+TBinaryProtocol.prototype.readI32 = function() {
+ var buff = this.trans.read(4);
+ // console.log("read buf: ");
+ // console.log(buff);
+ // console.log("result: " + BinaryParser.toInt(buff));
+ return BinaryParser.toInt(buff);
+}
+
+TBinaryProtocol.prototype.readI64 = function() {
+ var buff = this.trans.read(8);
+ return BinaryParser.toLong(buff);
+}
+
+TBinaryProtocol.prototype.readDouble = function() {
+ var buff = this.trans.read(8);
+ return BinaryParser.toFloat(buff);
+}
+
+TBinaryProtocol.prototype.readBinary = function() {
+ var len = this.readI32();
+ return this.trans.read(len);
+}
+
+TBinaryProtocol.prototype.readString = function() {
+ var r = this.readBinary().toString('binary');
+ // console.log("readString: " + r);
+ return r;
+}
+
+TBinaryProtocol.prototype.getTransport = function() {
+ return this.trans;
+}
+
+TBinaryProtocol.prototype.skip = function(type) {
+ // console.log("skip: " + 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 r = this.readMapBegin();
+ for (var i = 0; i < r.size; ++i) {
+ this.skip(r.ktype);
+ this.skip(r.vtype);
+ }
+ this.readMapEnd();
+ break;
+ case Type.SET:
+ var r = this.readSetBegin();
+ for (var i = 0; i < r.size; ++i) {
+ this.skip(r.etype);
+ }
+ this.readSetEnd();
+ break;
+ case Type.LIST:
+ var r = this.readListBegin();
+ for (var i = 0; i < r.size; ++i) {
+ this.skip(r.etype);
+ }
+ this.readListEnd();
+ break;
+ default:
+ throw Error("Invalid type: " + type);
+ }
+}
diff --git a/lib/nodejs/lib/thrift/server.js b/lib/nodejs/lib/thrift/server.js
new file mode 100644
index 0000000..43a7967
--- /dev/null
+++ b/lib/nodejs/lib/thrift/server.js
@@ -0,0 +1,51 @@
+/*
+ * 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 sys = require('sys'),
+ net = require('net');
+
+var BinaryParser = require('./binary_parser').BinaryParser,
+ TMemoryBuffer = require('./transport').TMemoryBuffer,
+ TBinaryProtocol = require('./protocol').TBinaryProtocol,
+ int32FramedReceiver = require('./connection').int32FramedReceiver;
+
+exports.createServer = function(cls, handler) {
+ if (cls.Processor) {
+ cls = cls.Processor;
+ }
+ var processor = new cls(handler);
+
+ return net.createServer(function(stream) {
+ stream.on('data', int32FramedReceiver(function(data) {
+ var input = new TBinaryProtocol(new TMemoryBuffer(data));
+ var output = new TBinaryProtocol(new TMemoryBuffer(undefined, function(buf) {
+ // TODO: optimize this better, allocate one buffer instead of both:
+ var msg = new Buffer(buf.length + 4);
+ BinaryParser.fromInt(buf.length).copy(msg, 0, 0, 4);
+ buf.copy(msg, 4, 0, buf.length);
+ stream.write(msg);
+ }));
+
+ processor.process(input, output);
+ }));
+
+ stream.on('end', function() {
+ stream.end();
+ });
+ });
+}
diff --git a/lib/nodejs/lib/thrift/thrift.js b/lib/nodejs/lib/thrift/thrift.js
new file mode 100644
index 0000000..73f772b
--- /dev/null
+++ b/lib/nodejs/lib/thrift/thrift.js
@@ -0,0 +1,130 @@
+/*
+ * 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 sys = require('sys');
+
+var Type = exports.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,
+}
+
+exports.MessageType = {
+ CALL: 1,
+ REPLY: 2,
+ EXCEPTION: 3,
+ ONEWAY: 4,
+}
+
+var TException = exports.TException = function(message) {
+ Error.call(this, message);
+ this.name = 'TException';
+}
+sys.inherits(TException, Error);
+
+var TApplicationExceptionType = exports.TApplicationExceptionType = {
+ UNKNOWN: 0,
+ UNKNOWN_METHOD: 1,
+ INVALID_MESSAGE_TYPE: 2,
+ WRONG_METHOD_NAME: 3,
+ BAD_SEQUENCE_ID: 4,
+ MISSING_RESULT: 5
+}
+
+var TApplicationException = exports.TApplicationException = function(type, message) {
+ TException.call(this, message);
+ this.type = type || TApplicationExceptionType.UNKNOWN;
+ this.name = 'TApplicationException';
+}
+sys.inherits(TApplicationException, TException);
+
+TApplicationException.prototype.read = function(input) {
+ var ftype
+ var fid
+ var ret = input.readStructBegin('TApplicationException')
+
+ while(1){
+
+ ret = input.readFieldBegin()
+
+ if(ret.ftype == Type.STOP)
+ break
+
+ var fid = ret.fid
+
+ switch(fid){
+ case 1:
+ if( ret.ftype == Type.STRING ){
+ ret = input.readString()
+ this.message = ret.value
+ } else {
+ ret = input.skip(ret.ftype)
+ }
+
+ break
+ case 2:
+ if( ret.ftype == Type.I32 ){
+ ret = input.readI32()
+ this.type = ret.value
+ } else {
+ ret = input.skip(ret.ftype)
+ }
+ break
+
+ default:
+ ret = input.skip(ret.ftype)
+ break
+ }
+ input.readFieldEnd()
+ }
+
+ 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()
+ }
+
+ if (this.code) {
+ output.writeFieldBegin('type', Type.I32, 2)
+ output.writeI32(this.code)
+ output.writeFieldEnd()
+ }
+
+ output.writeFieldStop()
+ output.writeStructEnd()
+}
diff --git a/lib/nodejs/lib/thrift/transport.js b/lib/nodejs/lib/thrift/transport.js
new file mode 100644
index 0000000..0c10ef0
--- /dev/null
+++ b/lib/nodejs/lib/thrift/transport.js
@@ -0,0 +1,87 @@
+/*
+ * 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 TMemoryBuffer = exports.TMemoryBuffer = function(buffer, flushCallback) {
+ if (buffer !== undefined) {
+ this.recv_buf = buffer;
+ } else {
+ this.recv_buf = new Buffer(0);
+ }
+ this.recv_buf_sz = this.recv_buf.length;
+ this.send_buf = [];
+ this.rpos = 0;
+ this.flushCallback = flushCallback;
+}
+
+TMemoryBuffer.prototype.isOpen = function() {
+ // TODO
+ return true;
+}
+
+TMemoryBuffer.prototype.open = function() {
+}
+
+TMemoryBuffer.prototype.close = function() {
+}
+
+TMemoryBuffer.prototype.read = function(len) {
+ var avail = this.recv_buf_sz - this.rpos;
+ // console.log("avail: " + avail);
+
+ if(avail == 0)
+ return new Buffer(0);
+
+ var give = len
+
+ if(avail < len) {
+ console.log("asked for: " + len);
+ throw new Error("asked for too much");
+ give = avail
+ }
+
+ // console.log(this.rpos + "," + give);
+ var ret = this.recv_buf.slice(this.rpos,this.rpos + give)
+ this.rpos += give
+ // console.log(ret);
+
+ //clear buf when complete?
+ return ret
+
+}
+
+TMemoryBuffer.prototype.readAll = function() {
+ return this.recv_buf;
+}
+
+TMemoryBuffer.prototype.write = function(buf) {
+ // TODO
+ if (typeof(buf) === "string") {
+ for (var i = 0; i < buf.length; ++i) {
+ this.send_buf.push(buf.charCodeAt(i));
+ }
+ } else {
+ for (var i = 0; i < buf.length; ++i) {
+ this.send_buf.push(buf[i]);
+ }
+ }
+}
+
+TMemoryBuffer.prototype.flush = function() {
+ this.flushCallback(new Buffer(this.send_buf));
+ this.send_buf = [];
+}
diff --git a/lib/nodejs/package.json b/lib/nodejs/package.json
new file mode 100644
index 0000000..e6ebca9
--- /dev/null
+++ b/lib/nodejs/package.json
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+{
+ "name": "thrift",
+ "description": "node-thrift",
+ "version": "0.6.0",
+ "author": "Apache Thrift",
+ "directories" : { "lib" : "./lib/thrift" },
+ "main": "./lib/thrift",
+ "engines": { "node": ">= 0.2.4" },
+}