var express = require('express'); var http = require('http') var io = require('socket.io'); var net = require('net'); var app_debugging = express(); var http_debugging = http.Server(app_debugging) var io_debugging = io(http_debugging); var app_vis = express(); var http_vis = http.Server(app_vis) var io_vis = io(http_vis); var queue = [] // serve GET requests of client for debugging interface app_debugging.get('*', function(req, res) { if ( req.url == '/' ) { res.sendFile(__dirname + '/debugging_environment.html'); } else if ( req.url.match(/\.js$/) || req.url.match(/\.html$/) || req.url.match(/\.css$/) || req.url.match(/\.png$/) ) { res.sendFile(__dirname + req.url); } }); // user connects on the debugging interface: queue all incoming messages and tag them as debug messages io_debugging.on('connection', function(socket){ console.log('A user connected!'); socket.on('message', function(msg) { queue.push('dbg_' + msg); }) }); http_debugging.listen(9595, function() { console.log('Listening for user on port 9595'); }); // serve GET requests of client for visualization interface app_vis.get('*', function(req, res) { if ( req.url == '/' ) { res.sendFile('/visualization_server.html', {root: '../'}); } else if ( req.url.match(/\.js$/) || req.url.match(/\.html$/) || req.url.match(/\.css$/) || req.url.match(/\.png$/) ) { res.sendFile(req.url, {root: '../'}); } }); // user connects on the visualization interface: queue all incoming messages and tag them as visualization messages io_vis.on('connection', function(socket){ console.log('A user connected!'); socket.on('message', function(msg) { queue.push('vis_' + msg); }) }); http_vis.listen(9696, function() { console.log('Listening for user on port 9696'); }); String.prototype.endsWith = function(suffix) { return this.indexOf(suffix, this.length - suffix.length) !== -1; }; /* This is the server that ties debugging UI - visualization UI - debuggable simulator together. It waits for the simulation client to connect on port 9999 and coordinates all message traffic between the three components. */ net.createServer(function(sock) { console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort); buffer = ''; // Protocol: each message ends with a newline. Buffers messages until the buffer ends with a new line, in case a message is only partially sent. sock.on('data', function(data) { buffer += String(data); if (buffer.endsWith('\n')) { String(buffer).split('\n').forEach(function(entry) { if (entry != '') { try { msg = eval(entry); // TODO: probably not a very good idea, msg = JSON.parse(entry); is better but doesn't work with Infinity // console.log(msg); } catch (err) { throw err; } if (msg[0] == "VIS") { // visualization messages are sent to the visualization interface io_vis.emit('msg', JSON.stringify(msg.slice(1))); } else if (msg[0] == "DBG") { // debugging messages (state updates, for example) are sent to the debugging interface io_debugging.emit('msg', JSON.stringify(msg.slice(1))); } } }) buffer = ''; } }); sock.on('close', function(data) { console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort); }); sock.on('error', function(error) { console.log('ERROR: ' + error); }); /* Every 5 milliseconds, check whether any message was sent by the user from the debugging interface and/or the visualization interface. If so, pass it on. In case of a message from the debugging interface: send it to the simulator, although if it's a reset, also forward to the visualization. In case of a message from the visualization interface: only send it to the debugger when it's an interrupt. Send it to the debugging interface if it's a message wanting to select an entity. */ setInterval(function() { while (queue.length) { var msg = queue.pop(); var msg_head = msg.substring(0, 4) if (msg_head == "dbg_") { var parsed_msg = eval('(' + msg.substring(4) + ')'); // forward selected messages to visualization if (parsed_msg["parameters"].length && parsed_msg["parameters"][0] == "reset") { io_vis.emit('msg', msg); } // forward to simulator sock.write(msg + '\n'); } else if (msg_head == "vis_") { if (msg.substring(4).lastIndexOf('INTERRUPT', 0) == 0) { // forward to simulator sock.write(msg + '\n'); } else { var parsed_msg = eval('(' + msg.substring(4) + ')'); // forward selected messages to debugging interface if (parsed_msg["name"] == "select_instance") { io_debugging.emit('msg', msg); } } } } }, 5) }).listen(9999, '127.0.0.1'); console.log('Listening for simulator on localhost:9999');