2016-01-25 08:01:18 -08:00
|
|
|
var net = require("net");
|
|
|
|
var wire = require("js-wire");
|
|
|
|
var msg = require("./msgs");
|
|
|
|
var types = require("./types");
|
2015-12-18 20:44:48 -05:00
|
|
|
|
2016-01-25 08:01:18 -08:00
|
|
|
var maxWriteBufferLength = 4096; // Any more and flush
|
2015-12-18 20:44:48 -05:00
|
|
|
|
2016-01-25 08:01:18 -08:00
|
|
|
// Takes an application and handles TMSP connection
|
2015-12-18 20:44:48 -05:00
|
|
|
// which invoke methods on the app
|
|
|
|
function AppServer(app){
|
2016-01-25 08:01:18 -08:00
|
|
|
// set the app for the socket handler
|
|
|
|
this.app = app;
|
2015-12-18 20:44:48 -05:00
|
|
|
|
2016-01-25 08:01:18 -08:00
|
|
|
// create a server by providing callback for
|
|
|
|
// accepting new connection and callbacks for
|
|
|
|
// connection events ('data', 'end', etc.)
|
|
|
|
this.createServer();
|
2015-12-18 20:44:48 -05:00
|
|
|
}
|
|
|
|
|
2016-01-25 08:01:18 -08:00
|
|
|
AppServer.prototype.createServer = function() {
|
|
|
|
var app = this.app;
|
|
|
|
|
|
|
|
// Define the socket handler
|
|
|
|
this.server = net.createServer(function(socket) {
|
|
|
|
socket.name = socket.remoteAddress + ":" + socket.remotePort;
|
|
|
|
console.log("new connection from", socket.name);
|
|
|
|
|
|
|
|
var conn = new Connection(socket, function(msgBytes, cb) {
|
|
|
|
var r = new wire.Reader(msgBytes);
|
|
|
|
|
|
|
|
// Now we can decode
|
|
|
|
var typeByte = r.readByte();
|
|
|
|
var reqType = msg.types[typeByte];
|
|
|
|
|
|
|
|
// Special messages.
|
|
|
|
// NOTE: msgs are length prefixed
|
|
|
|
if (reqType == "flush") {
|
|
|
|
var w = new wire.Writer();
|
|
|
|
w.writeByte(types.ResponseTypeFlush);
|
|
|
|
conn.writeMessage(w.getBuffer());
|
|
|
|
conn.flush();
|
|
|
|
return cb();
|
|
|
|
} else if (reqType == "echo") {
|
|
|
|
var message = r.readString();
|
|
|
|
var w = new wire.Writer();
|
|
|
|
w.writeByte(types.ResponseTypeEcho);
|
|
|
|
w.writeString(message);
|
|
|
|
conn.writeMessage(w.getBuffer());
|
|
|
|
return cb();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make callback by wrapping cp
|
|
|
|
var resCb = msg.writerGenerators[reqType](new wire.Writer(), function(w) {
|
|
|
|
conn.writeMessage(w.getBuffer());
|
|
|
|
return cb();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Decode arguments
|
|
|
|
var args = msg.readers[reqType](r);
|
|
|
|
args.unshift(resCb);
|
|
|
|
|
|
|
|
// Call function
|
|
|
|
var res = app[reqType].apply(app, args);
|
|
|
|
if (res != undefined) {
|
|
|
|
console.log("Message handler shouldn't return anything!");
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
function Connection(socket, msgCb) {
|
|
|
|
this.socket = socket;
|
|
|
|
this.recvBuf = new Buffer(0);
|
|
|
|
this.sendBuf = new Buffer(0);
|
|
|
|
this.msgCb = msgCb;
|
|
|
|
this.waitingResult = false;
|
|
|
|
var conn = this;
|
|
|
|
|
|
|
|
// Handle TMSP requests.
|
|
|
|
socket.on('data', function(data) {
|
|
|
|
conn.appendData(data);
|
|
|
|
});
|
|
|
|
socket.on('end', function() {
|
|
|
|
console.log("connection ended");
|
|
|
|
});
|
|
|
|
}
|
2015-12-18 20:44:48 -05:00
|
|
|
|
2016-01-25 08:01:18 -08:00
|
|
|
Connection.prototype.appendData = function(bytes) {
|
|
|
|
var conn = this;
|
|
|
|
if (bytes.length > 0) {
|
|
|
|
this.recvBuf = Buffer.concat([this.recvBuf, new Buffer(bytes)]);
|
|
|
|
}
|
|
|
|
if (this.waitingResult) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var r = new wire.Reader(this.recvBuf);
|
|
|
|
var msg;
|
|
|
|
try {
|
|
|
|
msg = r.readByteArray();
|
|
|
|
} catch(e) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.recvBuf = r.buf.slice(r.offset);
|
|
|
|
this.waitingResult = true;
|
|
|
|
this.socket.pause();
|
|
|
|
//try {
|
|
|
|
this.msgCb(msg, function() {
|
|
|
|
// This gets called after msg handler is finished with response.
|
|
|
|
conn.waitingResult = false;
|
|
|
|
conn.socket.resume();
|
|
|
|
if (conn.recvBuf.length > 0) {
|
|
|
|
conn.appendData("");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
//} catch(e) {
|
|
|
|
// console.log("FATAL ERROR: ", e);
|
|
|
|
//}
|
|
|
|
};
|
|
|
|
|
|
|
|
Connection.prototype.writeMessage = function(msgBytes) {
|
|
|
|
var msgLength = wire.uvarintSize(msgBytes.length);
|
|
|
|
var buf = new Buffer(1+msgLength+msgBytes.length);
|
|
|
|
var w = new wire.Writer(buf);
|
|
|
|
w.writeByteArray(msgBytes); // TODO technically should be writeVarint
|
|
|
|
this.sendBuf = Buffer.concat([this.sendBuf, w.getBuffer()]);
|
|
|
|
if (this.sendBuf.length >= maxWriteBufferLength) {
|
|
|
|
this.flush();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Connection.prototype.flush = function() {
|
|
|
|
var n = this.socket.write(this.sendBuf);
|
|
|
|
this.sendBuf = new Buffer(0);
|
2015-12-18 20:44:48 -05:00
|
|
|
}
|
|
|
|
|
2016-01-25 08:01:18 -08:00
|
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
module.exports = { AppServer: AppServer };
|