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;