debugging_server.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. var express = require('express');
  2. var http = require('http')
  3. var io = require('socket.io');
  4. var net = require('net');
  5. var app_debugging = express();
  6. var http_debugging = http.Server(app_debugging)
  7. var io_debugging = io(http_debugging);
  8. var app_vis = express();
  9. var http_vis = http.Server(app_vis)
  10. var io_vis = io(http_vis);
  11. var queue = []
  12. // serve GET requests of client for debugging interface
  13. app_debugging.get('*', function(req, res) {
  14. if ( req.url == '/' ) {
  15. res.sendFile(__dirname + '/debugging_environment.html');
  16. } else if ( req.url.match(/\.js$/)
  17. || req.url.match(/\.html$/)
  18. || req.url.match(/\.css$/)
  19. || req.url.match(/\.png$/)
  20. ) {
  21. res.sendFile(__dirname + req.url);
  22. }
  23. });
  24. // user connects on the debugging interface: queue all incoming messages and tag them as debug messages
  25. io_debugging.on('connection', function(socket){
  26. console.log('A user connected!');
  27. socket.on('message', function(msg) {
  28. queue.push('dbg_' + msg);
  29. })
  30. });
  31. http_debugging.listen(9595, function() {
  32. console.log('Listening for user on port 9595');
  33. });
  34. // serve GET requests of client for visualization interface
  35. app_vis.get('*', function(req, res) {
  36. if ( req.url == '/' ) {
  37. res.sendFile('/visualization_server.html', {root: '../'});
  38. } else if ( req.url.match(/\.js$/)
  39. || req.url.match(/\.html$/)
  40. || req.url.match(/\.css$/)
  41. || req.url.match(/\.png$/)
  42. ) {
  43. res.sendFile(req.url, {root: '../'});
  44. }
  45. });
  46. // user connects on the visualization interface: queue all incoming messages and tag them as visualization messages
  47. io_vis.on('connection', function(socket){
  48. console.log('A user connected!');
  49. socket.on('message', function(msg) {
  50. queue.push('vis_' + msg);
  51. })
  52. });
  53. http_vis.listen(9696, function() {
  54. console.log('Listening for user on port 9696');
  55. });
  56. String.prototype.endsWith = function(suffix) {
  57. return this.indexOf(suffix, this.length - suffix.length) !== -1;
  58. };
  59. /*
  60. This is the server that ties debugging UI - visualization UI - debuggable simulator together.
  61. It waits for the simulation client to connect on port 9999 and coordinates all message traffic between the three components.
  62. */
  63. net.createServer(function(sock) {
  64. console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort);
  65. buffer = '';
  66. // 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.
  67. sock.on('data', function(data) {
  68. buffer += String(data);
  69. if (buffer.endsWith('\n')) {
  70. String(buffer).split('\n').forEach(function(entry) {
  71. if (entry != '') {
  72. try {
  73. msg = eval(entry); // TODO: probably not a very good idea, msg = JSON.parse(entry); is better but doesn't work with Infinity
  74. } catch (err) {
  75. throw err;
  76. }
  77. if (msg[0] == "VIS") {
  78. // visualization messages are sent to the visualization interface
  79. io_vis.emit('msg', JSON.stringify(msg.slice(1)));
  80. } else if (msg[0] == "DBG") {
  81. // debugging messages (state updates, for example) are sent to the debugging interface
  82. io_debugging.emit('msg', JSON.stringify(msg.slice(1)));
  83. }
  84. }
  85. })
  86. buffer = '';
  87. }
  88. });
  89. sock.on('close', function(data) {
  90. console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort);
  91. });
  92. sock.on('error', function(error) {
  93. console.log('ERROR: ' + error);
  94. });
  95. /*
  96. 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.
  97. 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.
  98. 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.
  99. */
  100. setInterval(function() {
  101. while (queue.length) {
  102. var msg = queue.pop();
  103. var msg_head = msg.substring(0, 4)
  104. if (msg_head == "dbg_") {
  105. var parsed_msg = eval('(' + msg.substring(4) + ')');
  106. // forward selected messages to visualization
  107. if (parsed_msg["parameters"].length && parsed_msg["parameters"][0] == "reset") {
  108. io_vis.emit('msg', msg);
  109. }
  110. // forward to simulator
  111. sock.write(msg + '\n');
  112. } else if (msg_head == "vis_") {
  113. if (msg.substring(4).lastIndexOf('INTERRUPT', 0) == 0) {
  114. // forward to simulator
  115. sock.write(msg + '\n');
  116. } else {
  117. var parsed_msg = eval('(' + msg.substring(4) + ')');
  118. // forward selected messages to debugging interface
  119. if (parsed_msg["name"] == "select_instance") {
  120. io_debugging.emit('msg', msg);
  121. }
  122. }
  123. }
  124. }
  125. }, 5)
  126. }).listen(9999, '127.0.0.1');
  127. console.log('Listening for simulator on localhost:9999');