Skip to content
Browse files

first commit

  • Loading branch information...
0 parents commit 25609f93045a526208eff544efdca0b8c0d38388 @juzna committed Feb 16, 2011
Showing with 823 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +47 −0 lib_class.js
  3. +125 −0 lib_fifo.js
  4. +53 −0 lib_misc.js
  5. +95 −0 lib_pack.js
  6. +114 −0 lib_tools.js
  7. +47 −0 tbase.js
  8. +340 −0 tprotocol-json.js
2 .gitignore
@@ -0,0 +1,2 @@
+/.idea
+thrift-old.js
47 lib_class.js
@@ -0,0 +1,47 @@
+/**
+ * Working with classes easily
+ */
+
+// Working with classes
+var Class = exports.Class = function Class(def) {
+ // pokud není konstruktor definován, použijeme nový (nechceme použít zděděný)
+ var constructor = def.hasOwnProperty('init') ? def.init : function() { };
+
+ // proces vytváření třídy rozdělíme do kroků
+ for (var name in Class.Initializers) {
+ Class.Initializers[name].call(constructor, def[name], def);
+ }
+ return constructor;
+};
+
+Class.Initializers = {
+ Extends: function(parent) {
+ if (parent) {
+ var F = function() { };
+ this._superClass = F.prototype = parent.prototype;
+ this.prototype = new F;
+ }
+ },
+
+ Mixins: function(mixins, def) {
+ // kostruktoru přidáme metodu mixin
+ this.mixin = function(mixin) {
+ for (var key in mixin) {
+ if (key in Class.Initializers) continue;
+ this.prototype[key] = mixin[key];
+ }
+ this.prototype.constructor = this;
+ };
+ // a přidanou metodu hned využijeme pro rozšíření prototype
+ var objects = [def].concat(mixins || []);
+ for (var i = 0, l = objects.length; i < l; i++) {
+ this.mixin(objects[i]);
+ }
+ },
+
+ // Add static functions
+ Static: function(methods) {
+ for(var name in methods) this[name] = methods[name];
+ },
+};
+
125 lib_fifo.js
@@ -0,0 +1,125 @@
+/**
+ * Implementation if FIFO (queue)
+ */
+
+var Buffer = require('buffer').Buffer,
+ Class = require('./lib_class').Class,
+ _;
+
+
+/**
+* FIFO buffer with autoresize
+*/
+var FIFO = exports.FIFO = Class({
+ init: function(size) {
+ this.size = size || 4096;
+ this.start = this.end = 0;
+ this.buffer = new Buffer(this.size);
+ },
+
+ length: function() {
+ return this.end - this.start;
+ },
+
+ available: function(len) {
+ return this.length() >= len;
+ },
+
+ peek: function() {
+ if(this.start == this.end) return false;
+ else return this.buffer.slice(this.start, this.end);
+ },
+
+ peekString: function() {
+ if(this.start == this.end) return '';
+ else return this.buffer.slice(this.start, this.end).toString('ascii');
+ },
+
+ read: function(len, skip) {
+ if(this.end - this.start < len) throw new Error("Not enough data");
+ var ret = this.buffer.slice(this.start, this.start + len);
+ this.start += len;
+
+ if(skip) this.skip(skip);
+
+ return ret;
+ },
+
+ skip: function(len) {
+ this.start += len;
+ },
+
+ skipRegMatch: function(x) {
+ this.skip(x.index + x[0].length);
+ },
+
+ write: function(buf) {
+ if(!(buf instanceof Buffer)) buf = new Buffer(buf);
+ var len = buf.length;
+
+ // If not enough space, make some
+ if(this.end + len > this.size) this.requiredMoreSpace(len);
+
+ // Copy new data to our buffer
+ buf.copy(this.buffer, this.end, 0);
+ this.end += len;
+ return len;
+ },
+
+ clear: function() {
+ this.start = this.end = 0;
+ },
+
+ // Make more space if needed
+ requiredMoreSpace: function(len) {
+ // Double size if needed
+ var requiredLen = this.end - this.start + len;
+ while(requiredLen > this.size) this.size *= 2;
+
+ // Prepare swap buffer
+ var buf = new Buffer(this.size);
+ this.buffer.copy(buf, 0, this.start, this.end);
+
+ // Swap 'em
+ this.buffer = buf;
+
+ this.end -= this.start;
+ this.start = 0;
+ },
+
+ // Find position of char
+ find: function(chr, offset) {
+ if(offset === undefined) offset = 0;
+
+ for(var i = this.start + offset; i < this.end; ++i) {
+ if(this.buffer[i] == chr) return i - this.start;
+ }
+ }
+
+});
+
+/***********
+// TESTING FOR FIFO
+var f = new FIFO(5);
+console.log('Size:', sys.inspect(f.size));
+console.log('Length:', sys.inspect(f.length()));
+console.log('Avail :', sys.inspect(f.available(2)));
+
+console.log('Write', "\n");
+f.write("ahoj ka");
+
+console.log('Size:', sys.inspect(f.size));
+console.log('Length:', sys.inspect(f.length()));
+console.log('Avail :', sys.inspect(f.available(4)));
+console.log('Peek :', sys.inspect(f.peek()));
+console.log();
+
+console.log('Read :', sys.inspect(f.read(4)));
+console.log('Size:', sys.inspect(f.size));
+console.log('Length:', sys.inspect(f.length()));
+console.log('Avail :', sys.inspect(f.available(4)));
+console.log('Peek :', sys.inspect(f.peek()));
+
+return;
+*****************************/
+
53 lib_misc.js
@@ -0,0 +1,53 @@
+/**
+ * Some useful functions
+ */
+
+exports.merge = function merge(a, b) {
+ var ret = [];
+ for(var i = 0; i < a.length; i++) ret.push(a[i]);
+ for(var i = 0; i < b.length; i++) ret.push(b[i]);
+ return ret;
+}
+
+exports.ip2long = function(s) {
+ var x = s.split(/\./);
+ return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3];
+}
+
+exports.long2ip = function(i) {
+ return [
+ i >> 24 & 0xff,
+ i >> 16 & 0xff,
+ i >> 8 & 0xff,
+ i & 0xff
+ ].join('.');
+}
+
+exports.compareIP = function(a, b) {
+ function str(s) {
+ return s.split(/\./).map(function(i) { var x = parseInt(i).toString(16); return x.length == 1 ? '0' + x : x; }).join(' ');
+ }
+ var aa = str(a), bb = str(b);
+
+ return aa == bb ? 0 : (aa < bb ? -1 : 1);
+}
+
+// Filter for interesting IPs
+exports.filterIP = function(item) {
+ return item
+ && item.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
+ && !item.match(/^192\.168\.[012]\.\d+$/) // Behind NAT
+ && !item.match(/^10\.87\.\d+\.\d+$/) // TV, fuck off
+ ;
+}
+
+// Compare two buffers
+exports.buffCompare = function(buf1, buf2) {
+ if(!(buf1 instanceof Buffer)) return false;
+ if(!(buf2 instanceof Buffer)) return false;
+ if(buf1.length != buf2.length) return false;
+
+ for(var i = 0; i < buf1.length; i++) if(buf1[i] != buf2[i]) return false;
+
+ return true;
+}
95 lib_pack.js
@@ -0,0 +1,95 @@
+/**
+ * Packing un unpacking
+ * Decoders are based on code from http://github.com/mranney/node_pcap/ with some modifications
+ */
+
+
+// Pack numbers or other data stuctures to binary format
+var pack = {
+ ethernet_addr: function (mac, buf, offset) {
+ var parts = mac.split(':');
+ if(parts.length != 6) return false;
+
+ for(var i = 0; i < 6; i++) buf[offset + i] = parseInt(parts[i], 16);
+ return true;
+ },
+
+ uint16: function (num, buf, offset) {
+ buf[offset] = (num >> 8) & 0xff;
+ buf[offset + 1] = num & 0xff;
+ return true;
+ },
+
+ uint32: function (num, buf, offset) {
+ buf[offset] = (num >> 24) & 0xff;
+ buf[offset + 1] = (num >> 16) & 0xff;
+ buf[offset + 2] = (num >> 8) & 0xff;
+ buf[offset + 3] = (num) & 0xff;
+ },
+
+ uint64: function (num, buf, offset) {
+ buf[offset] = (num >> 56) & 0xff;
+ buf[offset + 1] = (num >> 48) & 0xff;
+ buf[offset + 2] = (num >> 40) & 0xff;
+ buf[offset + 3] = (num >> 32) & 0xff;
+ buf[offset + 4] = (num >> 24) & 0xff;
+ buf[offset + 5] = (num >> 16) & 0xff;
+ buf[offset + 6] = (num >> 8) & 0xff;
+ buf[offset + 7] = (num) & 0xff;
+ },
+
+ ipv4_addr: function (ip, buf, offset) {
+ var parts = ip.split('.');
+ if(parts.length != 4) return false;
+
+ for(var i = 0; i < 4; i++) buf[offset + i] = parseInt(parts[i]);
+ return true;
+ },
+};
+exports.pack = pack;
+
+
+var unpack = {
+ ethernet_addr: function (raw_packet, offset) {
+ return [
+ lpad(raw_packet[offset].toString(16), 2),
+ lpad(raw_packet[offset + 1].toString(16), 2),
+ lpad(raw_packet[offset + 2].toString(16), 2),
+ lpad(raw_packet[offset + 3].toString(16), 2),
+ lpad(raw_packet[offset + 4].toString(16), 2),
+ lpad(raw_packet[offset + 5].toString(16), 2)
+ ].join(":");
+ },
+ uint16: function (raw_packet, offset) {
+ return ((raw_packet[offset] * 256) + raw_packet[offset + 1]);
+ },
+ uint32: function (raw_packet, offset) {
+ return (
+ (raw_packet[offset] * 16777216) +
+ (raw_packet[offset + 1] * 65536) +
+ (raw_packet[offset + 2] * 256) +
+ raw_packet[offset + 3]
+ );
+ },
+ uint64: function (raw_packet, offset) {
+ return (
+ (raw_packet[offset] * 72057594037927936) +
+ (raw_packet[offset + 1] * 281474976710656) +
+ (raw_packet[offset + 2] * 1099511627776) +
+ (raw_packet[offset + 3] * 4294967296) +
+ (raw_packet[offset + 4] * 16777216) +
+ (raw_packet[offset + 5] * 65536) +
+ (raw_packet[offset + 6] * 256) +
+ raw_packet[offset + 7]
+ );
+ },
+ ipv4_addr: function (raw_packet, offset) {
+ return [
+ raw_packet[offset],
+ raw_packet[offset + 1],
+ raw_packet[offset + 2],
+ raw_packet[offset + 3]
+ ].join('.');
+ }
+};
+exports.unpack = unpack;
114 lib_tools.js
@@ -0,0 +1,114 @@
+/**
+ * Basic tools
+ *
+ * Add some useful features to Object, Array and Function, just call
+ * require('./lib_tools').setup(Object, Array, Function)
+ *
+ */
+
+function extend(dst, src) {
+ for(var i in src) dst[i] = src[i];
+ return dst;
+}
+
+
+/**
+* Basic setup
+*/
+exports.setup = function(Object, Array, Function) {
+
+// Object methods
+extend(Object, {
+ extend: extend,
+
+ isArray: function(x) {
+ return !!x.__proto__.constructor.toString().match(/function Array/);
+ },
+
+ values: function(x) {
+ var ret = [];
+ for(var i in x) ret.push(x[i]);
+ return ret;
+ },
+
+ keys: function(x) {
+ var ret = [];
+ for(var i in x) ret.push(i);
+ return ret;
+ },
+
+ clone: function(x) {
+ var ret = {};
+ for(var i in x) ret[i] = x[i];
+ return ret;
+ },
+
+ cloneDeep: function(x) {
+ return JSON.parse(JSON.stringify(x));
+ },
+});
+
+
+// Array static methods
+extend(Array, {
+ merge: function(a, b) {
+ return a.copy().merge(b);
+ },
+
+ copy: function(a) {
+ return a.copy();
+ },
+
+ is: function(a) {
+ return Object.isArray(a);
+ },
+
+});
+
+
+// Array methods
+extend(Array.prototype, {
+ merge: function(b) {
+ for(var i = 0; i < b.length; i++) this.push(b[i]);
+ return this;
+ },
+
+ copy: function() {
+ return this.slice(0, this.length);
+ },
+
+ include: function(object) {
+ return (this.indexOf(object) !== -1);
+ },
+
+ uniq: function() {
+ var ret = [];
+ this.forEach(function(i) { if(ret.indexOf(i) === -1) ret.push(i); });
+ return ret;
+ },
+
+ pluck: function(prop) {
+ return this.map(function(item) { return item && item[prop]; });
+ },
+
+ compact: function() {
+ return this.filter(function(value) {
+ return value != null;
+ });
+ },
+
+
+});
+
+
+extend(Function.prototype, {
+ getClassName: function() {
+ try {
+ return this.__proto__.constructor.toString().match(/function (.*)\(/)[1];
+ }
+ catch(e) {}
+ },
+});
+
+
+} // eof: setup
47 tbase.js
@@ -0,0 +1,47 @@
+/**
+ * Basic Thrift
+ */
+
+// Field types
+exports.types = {
+ "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
+};
+
+// Message types
+exports.messageTypes = {
+ "CALL" : 1,
+ "REPLY" : 2,
+ "EXCEPTION" : 3
+};
+
+
+/**
+ * TProtocol:
+ * - init(transport)
+ * - write/read methods
+ *
+ *
+ * TTransport:
+ * - init(...)
+ * - write(buf)
+ * - flush()
+ * - read(len)
+ * - peek() -> bool - are some data available
+ * - readAll() - reads all data
+ */
340 tprotocol-json.js
@@ -0,0 +1,340 @@
+/**
+ * JSON protocol
+ */
+require('./lib_tools').setup(Object, Array, Function); // Add useful stuff
+var TBase = require('./tbase'),
+ types = TBase.types,
+ Class = require('./lib_class').Class,
+ FIFO = require('./lib_fifo').FIFO,
+ Buffer = require('buffer').Buffer,
+ _;
+
+
+// Map of types
+var mapType = exports.mapType = {};
+mapType[types.BOOL ] = 'tf';
+mapType[types.BYTE ] = 'i8';
+mapType[types.I16 ] = 'i16';
+mapType[types.I32 ] = 'i32';
+mapType[types.I64 ] = 'i64';
+mapType[types.DOUBLE ] = 'dbl';
+mapType[types.STRUCT ] = 'rec';
+mapType[types.STRING ] = 'str';
+mapType[types.MAP ] = 'map';
+mapType[types.LIST ] = 'lst';
+mapType[types.SET ] = 'set';
+
+// Create reversed map of types
+var mapRType = exports.mapRType = {};
+for(var i in mapType) mapRType[mapType[i]] = i;
+
+// Comma reference
+var comma = {};
+
+// Write as JSON string
+function str(x) {
+ return JSON.stringify(String(x));
+}
+function toVal(x) {
+ return { value: x };
+}
+
+var Proto = exports.ThriftJSONProtocol = Class({
+ /**
+ * Initializes new protocol
+ * @param transport
+ */
+ init: function(transport) {
+ this.transport = transport;
+ this.context = [ [ 'TOP' ] ];
+
+ this.fifo = null; // Output queue (which can serve as buffer as well)
+ this.incoming = null;
+ },
+
+ // Protocol version
+ version: 1,
+
+
+ /************* Write methods **********/
+
+ /**
+ * Write all arguments to buffer
+ * @return int Number of written bytes
+ */
+ _write: function() {
+ var item, sum = 0;
+
+ // We're writing map, writing key, and we're not the first one
+ if(this.context[0][0] === 'map' && this.context[0][1] && this.context[0][2]++ > 0) sum += this.fifo.write(', ');
+
+ for(var i = 0; i < arguments.length; i++) {
+ var item = arguments[i];
+
+ // Convert to string if needed
+ if(item === comma) item = ', ';
+ else if(item instanceof Buffer) { }
+ else if(typeof item !== 'string') item = String(item);
+
+ sum += this.fifo.write(item);
+ }
+
+ // We are in map
+ if(this.context[0][0] == 'map') {
+ if(!(this.context[0][1] = !this.context[0][1])) {
+ sum += this.fifo.write(': ');
+ }
+ }
+
+ return sum;
+ },
+
+ writeMessageBegin: function(name, messageType, seqid) {
+ this.fifo = new FIFO; // Initialize new buffer
+ return this._write('[ ', this.version, comma, str(name), comma, messageType, comma, seqid, comma);
+ },
+
+ writeMessageEnd: function() {
+ var x = this._write(' ]');
+
+ // Write to transport and flush it
+ this.transport.write(this.fifo.peek());
+ this.transport.flush();
+
+ return x;
+ },
+
+ writeStructBegin: function(name) {
+ this.context.unshift([ 'struct', 0 ]); // Struct + counter
+ return this._write('/** struct ' + name + '*/ { ');
+ },
+
+ writeStructureEnd: function() {
+ this.context.shift();
+
+ return this._write(' } ');
+ },
+
+ writeFieldBegin: function(name, fieldType, fieldId) {
+ return this._write(
+ (this.context[0][1]++ ? ', ' : '') +
+ ' { ' + str(fieldId) + ': { ' + str(mapType[fieldType]) + ': '
+ );
+ },
+
+ writeFieldEnd: function() {
+ return this._write(' } } ');
+ },
+
+ writeFieldStop: function() {
+ // nothing to do
+ },
+
+ writeMapBegin: function(keyType, valType, size) {
+ this.context.unshift( [ 'map', true, 0 ] ); // Map + writingKey? + counter
+ return this._write(' [ ', str(mapType[keyType]), comma, str(mapType[valType]), comma, size, comma, ' { ');
+ },
+
+ writeMapEnd: function() {
+ this.context.shift();
+ return this._write(' } ] ');
+ },
+
+ writeListBegin: function(elemType, size) {
+ this.context.unshift('list');
+ return this._write(' [ ', str(mapType(elemType)), comma, size, comma);
+ },
+
+ writeListEnd: function() {
+ this.context.shift();
+ return this._write(' ] ');
+ },
+
+ writeSetBegin: function(elemType, size) {
+ this.context.unshift('set');
+ return this._write(' [ ', str(mapType(elemType)), comma, size, comma);
+ },
+
+ writeSetEnd: function() {
+ this.context.shift();
+ return this._write(' ] ');
+ },
+
+ writeBool: function(value) {
+ return this._write(value ? 1 : 0);
+ },
+
+ writeByte: function(i8) {
+ return this._write(i8);
+ },
+
+ writeI16 : function(i16){
+ return this._write(i16);
+ },
+
+ writeI32 : function(i32){
+ return this._write(i32);
+ },
+
+ writeI64 : function(i64){
+ return this._write(i64);
+ },
+
+ writeDouble : function(dbl){
+ return this._write(dbl);
+ },
+
+ writeString: function(x) {
+ return this._write(str(x))
+ },
+
+ writeBinary: function(x) {
+ // TODO: encode base64
+ return this._write(x);
+ },
+
+
+
+ /************* Read methods **********/
+
+ readMessageBegin: function() {
+ // Parse incoming JSON object
+ var buf = JSON.parse(this.transport.readAll());
+
+ if(buf[0] != this.version) throw new Error('Unknown version: ' + buf[0]);
+
+ var ret = {
+ version: buf[0],
+ fname: buf[1],
+ mtype: buf[2],
+ rseqid: buf[3]
+ };
+
+ // Populate rest
+ this.incoming = buf.slice(4);
+
+ return ret;
+ },
+
+ readMessageEnd: function() {
+ // nothing to do
+ },
+
+ readStructBegin: function() {
+ this.context.unshift([ 'struct', this.incoming.shift() ]); // Struct + contents as object
+ return { fname: '' }; // Name it not there
+ },
+
+ readStructureEnd: function() {
+ this.context.shift();
+ },
+
+ readFieldBegin: function() {
+ // Take first key from object
+ for(var fId in this.context[0][1]) break;
+ if(typeof fId === 'undefined') throw new Error('Key is missing');
+
+ // Take type
+ for(var fType in this.context[0][1][fId]) break;
+
+ var ret = {
+ fid: fId,
+ ftype: mapRType[fType],
+ fname: ''
+ };
+
+ // Put value back to queue
+ this.incoming.unshift(this.context[0][1][fId][fType]);
+
+ // Remote it from struct-context
+ delete this.context[0][1][fId];
+
+ return ret;
+ },
+
+ readFieldEnd: function() {
+ // n/a
+ },
+
+ readMapBegin: function() {
+ var map = this.incoming.shift();
+ var ret = {
+ ktype: mapRType[map[0]],
+ vtype: mapRType[map[1]],
+ size: map[2]
+ };
+
+ // Make simple list from rest of it
+ var contents = map[3], list = [];
+ for(var i in contents) {
+ list.push(i, contents[i]);
+ }
+
+ // Put this list at the beginning of incoming
+ Array.prototype.unshift.apply(this.incoming, list);
+
+ return ret;
+ },
+
+ readMapEnd: function() {
+ // n/a
+ },
+
+ readListBegin: function() {
+ var lst = this.incoming.shift();
+ var ret = {
+ etype: mapRType[lst[0]],
+ size: lst[1]
+ };
+
+ // Put this list at the beginning of incoming
+ Array.prototype.unshift.apply(this.incoming, list.slice(2));
+
+ return ret;
+ },
+
+ readListEnd: function() {
+ // n/a
+ },
+
+ readSetBegin: function(elemType, size) {
+ return this.readListBegin();
+ },
+
+ readSetEnd: function() {
+ return this.readListEnd();
+ },
+
+ readBool: function(value) {
+ return toVal(this.incoming.shift() ? true : false);
+ },
+
+ readByte: function(i8) {
+ return toVal(this.incoming.shift());
+ },
+
+ readI16 : function(i16){
+ return toVal(this.incoming.shift());
+ },
+
+ readI32 : function(i32){
+ return toVal(this.incoming.shift());
+ },
+
+ readI64 : function(i64){
+ return toVal(this.incoming.shift());
+ },
+
+ readDouble : function(dbl){
+ return toVal(this.incoming.shift());
+ },
+
+ readString: function(x) {
+ return toVal(this.incoming.shift());
+ },
+
+ readBinary: function(x) {
+ // TODO: decode base64
+ return toVal(this.incoming.shift());
+ }
+});

0 comments on commit 25609f9

Please sign in to comment.
Something went wrong with that request. Please try again.