Skip to content

Instantly share code, notes, and snippets.

@MatthaeusHarris
Created October 31, 2012 03:24
Show Gist options
  • Save MatthaeusHarris/3984608 to your computer and use it in GitHub Desktop.
Save MatthaeusHarris/3984608 to your computer and use it in GitHub Desktop.
JSON TCP buffer implementation
var util = require('util');
var events = require('events');
function JSONBuffer(sock) {
if (false === this instanceof JSONBuffer) {
return new JSONBuffer();
}
events.EventEmitter.call(this);
this.sock = sock;
this.sock.on('connect', function() { this.emit('connect') }.bind(this));
this.sock.on('end', function() { this.emit('end') }.bind(this));
this.sock.on('timeout', function() { this.emit('timeout') }.bind(this));
this.sock.on('drain', function() { this.emit('drain') }.bind(this));
this.sock.on('error', function(e) {
console.log("JSONBuffer detected an error: " + e.message);
console.log(e.stack);
if (e.message == "This socket is closed.") {
console.log("The socket was closed prematurely. We should handle this more gracefully, but for now we'll just return.");
this.emit('closed');
} else {
console.log("Some other error happened, so we'll chuck it upstream.");
console.log(this);
console.log("Chucking the error upstream disabled for now, especially since there can be no error handlers in the upstream flow.");
//this.emit('error', e)
}
}.bind(this));
this.sock.on('close', function(e) { this.emit('close', e) }.bind(this));
this.sock.on('data',function(buf) {
this.buffer += buf;
// console.log("\n\n####################################################################");
// console.log("JSONBuffer buffer: ");
// console.log(this.buffer);
// console.log("####################################################################");
var stack = [];
var jsonStartIndex = -1;
var inQuotes = false;
for (var i = 0; i < this.buffer.length; i++) {
// console.log("Starting at character " + i + ": " + stack + " " + this.buffer[i]);
if ((this.buffer[i] == '\'' || this.buffer[i] == '\"') && i >=1 && this.buffer[i-1] != '\\') {
inQuotes = !inQuotes;
}
if (!inQuotes) {
switch(this.buffer[i]) {
case '{':
case '[':
stack.push(this.buffer[i]);
if (jsonStartIndex == -1) {
jsonStartIndex = i;
}
break;
case ']':
if (stack[stack.length-1] == "[") {
stack.pop();
}
break;
case '}':
if (stack[stack.length-1] == "{") {
stack.pop();
}
break;
default:
break;
}
if (stack.length == 0 && jsonStartIndex != -1) {
// console.log("JB: Found JSON, emitting data signal");
// console.log("JB: stack: " + JSON.stringify(stack));
var out = this.buffer.substr(jsonStartIndex,i-jsonStartIndex+1);
this.emit('data', out);
jsonStartIndex = -1;
this.buffer = this.buffer.slice(i);
i = 0;
}
}
}
}.bind(this));
}
util.inherits(JSONBuffer, events.EventEmitter);
JSONBuffer.prototype.__proto__ = events.EventEmitter.prototype;
JSONBuffer.prototype.sock = {};
JSONBuffer.prototype.buffer = "";
JSONBuffer.prototype.write = function(data, callback) {
try {
return(this.sock.write(data, callback));
} catch (e) {
console.log("Error writing to socket: " + e.message);
console.log(e.stack);
return false;
}
}
JSONBuffer.prototype.end = function() {
// var e = new Error("not really an error");
// console.log("JSONBuffer.end() called. ");
// console.log(e.stack);
try {
return(this.sock.end());
} catch (e) {
console.log("Error closing socket: " + e.message);
console.log(e.stack);
return false;
}
}
JSONBuffer.prototype.destroy = function() {
// var e = new Error("not really an error");
// console.log("JSONBuffer.destroy() called.");
// console.log(e.stack);
try {
return(this.sock.destroy());
} catch (e) {
console.log("Error destroying socket: " + e.message);
console.log(e.stack);
return false;
}
}
JSONBuffer.prototype.setTimeout = function(timeout, callback) {
return(this.sock.setTimeout(timeout, callback));
}
module.exports = JSONBuffer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment