Node.js C9 backup Ke2therm1

ke2therm1 (was private)

index.js

var server = require("./server");
console.log("index.js");
server.start();

server.js

var http = require("http");
var url = require("url");

// Additional modules
var nodestatic = require('node-static');

/*
var mysql = require('mysql')

var connection = mysql.createConnection({
 host : 'hhhhhh',
 user : 'uuuuuuuuu',
 password : 'ppppppppppp',
 //database : 'dddddddddd'
});

connection.connect(function(err) {
 writeLogWithTimeStamp(err);
});

*/

// Note we are expecting node-static to protect against
// - poison null bytes
// - directory traversal attack..
var staticServer = new nodestatic.Server("./public");

var clientRequestsReceived = 0;
var clientRequestsRespondedTo = 0;
var serverStartedDateTimeFormatted = formatDate(new Date());

var clientStack = {};

/*
Use of seq numbers:
The client sends in a request with a seq no (starts at 0 on a a client restart)

client.request is added into clientStack if doesn't exist, replaces existing if it does
clientStack.client.request.responseSent is set to false

Client request response is setup by a setTimeout call to call response function after x seconds

If an interrupt comes in for a client:
- call the response function immediately

The response function:
- checks clientStack.client.responseSent is set to false and if so:
 - sends the response
- nulls clientStack.client.request & response (will this save ram?)


*/

function start() {
 writeLogWithTimeStamp("Starting");

 function onRequest(request, response) {
 request.url_parts = url.parse(request.url, true);
 request.content = "";

 if ( request.url_parts.pathname == '/client'
 && "mac" in request.url_parts.query
 && "ip" in request.url_parts.query
 && "name" in request.url_parts.query
 && "seq" in request.url_parts.query
 ) {
 
 clientRequestsReceived++;
 // Do we already know this request?
 var id = request.url_parts.query.mac + '|' + request.url_parts.query.ip + '|' + request.url_parts.query.name;
 if (!clientStack[id]) {
 // create a space for it
 clientStack[id] = {};
 clientStack[id].lastServerSeqSent = -1;
 clientStack[id].lastServerRequest = {};
 clientStack[id].mac = request.url_parts.query.mac;
 clientStack[id].ip = request.url_parts.query.ip;
 clientStack[id].name = request.url_parts.query.name;
 } else {
 
 }
 
 // do we need to reset any pending request/response.. that we lost?
 // for now will just overwrite with the new objects
 clientStack[id].request = request;
 clientStack[id].response = response;
 
 clientStack[id].responseSent = false;
 clientStack[id].lastClientSeqReceived = request.url_parts.query.seq;
 clientStack[id].serverSeq = incrementSeq(request.url_parts.query.seq);
 clientStack[id].lastRequestDateTime = new Date();
 
 clientStack[id].responseToSend = 'seq=' + clientStack[id].serverSeq;

 clientStack[id].request.on('data', function (chunk) {
 clientStack[id].request.content += chunk;
 });
 
 clientStack[id].request.on('end', function () {
 acceptRequestBodyChunk(clientStack[id].request);
 setTimeout(
 function () {
 answer(clientStack[id]);
 }, 10000)
 });
 }
 else {
 staticServer.serve(request, response);
 }
 }

 var server = http.createServer(onRequest).listen(process.env.PORT, process.env.IP);
 writeLogServerUpSince();
 setInterval(function () {
 writeLogServerUpSince();
 }, 60000);
 console.log(server.PORT);
}

function answer(client) {
 // Writing a content length header stops the server sending the reply chunked..
 // (Our Microchip TCPIP long polling client isn't written to handle chunked so requires Content-length)
 client.response.writeHead(200, {
 "Content-Type": "text/plain",
 "Content-Length": client.responseToSend.length.toString()
 });
 client.response.write(client.responseToSend);
 client.response.end();
 //request.connection.end(); // force a disconnect?
 clientRequestsRespondedTo++;
}


function acceptRequestBodyChunk(client) {
 // Here we would handle expected data returned from the server
}


function writeLogWithTimeStamp(message) {
 console.log(formatDate(new Date()) + " " + message);
}

function writeLog(message) {
 console.log(message);
}

function writeLogServerUpSince() {
 writeLogWithTimeStamp("Server up since " + serverStartedDateTimeFormatted
 + ', ' + clientRequestsReceived + '/' +clientRequestsRespondedTo );
}

function pad(number, length) {
 var str = '' + number;
 while (str.length < length) {
 str = '0' + str;
 }
 return str;
}

function formatDate(date) {
 var dateStamp = '';
 dateStamp += date.getFullYear();
 dateStamp += '-';
 dateStamp += date.getMonth() + 1;
 dateStamp += '-';
 dateStamp += date.getDate();
 dateStamp += '_';
 dateStamp += pad(date.getHours(), 2);
 dateStamp += ':';
 dateStamp += pad(date.getMinutes(), 2);
 dateStamp += ':';
 dateStamp += pad(date.getSeconds(), 2);
 dateStamp += ':';
 dateStamp += pad(date.getMilliseconds(), 3);

 return dateStamp;
}

function is_int(value) {
 if ((parseFloat(value) == parseInt(value)) && !isNaN(value)) {
 return true;
 } else {
 return false;
 }
}

function incrementSeq(seq) {
 if (seq++ > 65535) {
 seq = 1;
 }
 return seq;
}

process.on('uncaughtException', function (err) {
 console.log((new Date()).toUTCString() + ' uncaughtException:', err.message);
 console.error(err.stack);
 //process.exit(1);
});

exports.start = start;