blob: 8ddcb9c32c1aae31111fe1e62778257f159a42ed [file] [log] [blame]
Simon Hunta25cdcd2015-01-22 13:11:42 -08001#!/usr/bin/env node
Simon Hunta25cdcd2015-01-22 13:11:42 -08002
Simon Hunt711ee242015-01-22 15:08:02 -08003// === Mock Web Socket Server - for testing the topology view
4
5var fs = require('fs'),
6 readline = require('readline'),
7 http = require('http'),
8 WebSocketServer = require('websocket').server,
Simon Hunt74928302015-01-30 12:42:06 -08009 port = 8123,
10 scenarioRoot = 'ev/';
Simon Hunt711ee242015-01-22 15:08:02 -080011
12var lastcmd, // last command executed
13 lastargs, // arguments to last command
14 connection, // ws connection
15 origin, // origin of connection
Simon Hunt626d2102015-01-29 11:54:50 -080016 scid, // scenario ID
17 scdata, // scenario data
Simon Hunt711ee242015-01-22 15:08:02 -080018 scdone, // shows when scenario is over
Simon Hunt74928302015-01-30 12:42:06 -080019 eventsById, // map of event file names
20 maxEvno, // highest loaded event number
Simon Hunt711ee242015-01-22 15:08:02 -080021 evno, // next event number
22 evdata; // event data
23
24
Simon Hunt74928302015-01-30 12:42:06 -080025var scFiles = fs.readdirSync(scenarioRoot);
26console.log('Mock Server v1.0');
27console.log('================');
Simon Hunt5724fb42015-02-05 16:59:40 -080028listScenarios();
Simon Hunt711ee242015-01-22 15:08:02 -080029
30var rl = readline.createInterface(process.stdin, process.stdout);
31rl.setPrompt('ws> ');
Simon Hunta25cdcd2015-01-22 13:11:42 -080032
33
34var server = http.createServer(function(request, response) {
35 console.log((new Date()) + ' Received request for ' + request.url);
36 response.writeHead(404);
37 response.end();
38});
39
40server.listen(port, function() {
41 console.log((new Date()) + ' Server is listening on port ' + port);
42});
43
44server.on('listening', function () {
Simon Huntb0ec1e52015-01-28 18:13:49 -080045 console.log('OK, server is running');
Simon Hunt626d2102015-01-29 11:54:50 -080046 console.log('(? for help)');
Simon Hunta25cdcd2015-01-22 13:11:42 -080047});
48
49var wsServer = new WebSocketServer({
50 httpServer: server,
51 // You should not use autoAcceptConnections for production
52 // applications, as it defeats all standard cross-origin protection
53 // facilities built into the protocol and the browser. You should
54 // *always* verify the connection's origin and decide whether or not
55 // to accept it.
56 autoAcceptConnections: false
57});
58
59function originIsAllowed(origin) {
60 // put logic here to detect whether the specified origin is allowed.
61 return true;
62}
63
Simon Hunta25cdcd2015-01-22 13:11:42 -080064wsServer.on('request', function(request) {
65 console.log(); // newline after prompt
66 console.log("Origin: ", request.origin);
67
68 if (!originIsAllowed(request.origin)) {
69 // Make sure we only accept requests from an allowed origin
70 request.reject();
71 console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
72 return;
73 }
74
Simon Hunt711ee242015-01-22 15:08:02 -080075 origin = request.origin;
76 connection = request.accept(null, origin);
Simon Hunta25cdcd2015-01-22 13:11:42 -080077
78
79 console.log((new Date()) + ' Connection accepted.');
80 rl.prompt();
81
Simon Hunta25cdcd2015-01-22 13:11:42 -080082 connection.on('message', function(message) {
83 if (message.type === 'utf8') {
84 console.log(); // newline after prompt
85 console.log('Received Message: ' + message.utf8Data);
86 //connection.sendUTF(message.utf8Data);
87 rl.prompt();
88 }
89 else if (message.type === 'binary') {
90 console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
91 //connection.sendBytes(message.binaryData);
92 }
93 });
94 connection.on('close', function(reasonCode, description) {
95 console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
Simon Hunt711ee242015-01-22 15:08:02 -080096 connection = null;
97 origin = null;
Simon Hunta25cdcd2015-01-22 13:11:42 -080098 });
99});
100
101
Simon Hunt711ee242015-01-22 15:08:02 -0800102setTimeout(doCli, 10); // allow async processes to write to stdout first
Simon Hunta25cdcd2015-01-22 13:11:42 -0800103
104function doCli() {
105 rl.prompt();
106 rl.on('line', function (line) {
107 var words = line.trim().split(' '),
Simon Hunt354c8c92015-01-22 15:32:51 -0800108 cmd = words.shift(),
109 str = words.join(' ');
110
111 if (!cmd) {
112 // repeat last command
113 cmd = lastcmd;
114 str = lastargs;
115 }
Simon Hunta25cdcd2015-01-22 13:11:42 -0800116
117 switch(cmd) {
Simon Hunt5724fb42015-02-05 16:59:40 -0800118 case 'l': listScenarios(); break;
Simon Hunt711ee242015-01-22 15:08:02 -0800119 case 'c': connStatus(); break;
120 case 'm': customMessage(str); break;
121 case 's': setScenario(str); break;
122 case 'n': nextEvent(); break;
Simon Huntb0ec1e52015-01-28 18:13:49 -0800123 case 'r': restartScenario(); break;
Simon Hunt711ee242015-01-22 15:08:02 -0800124 case 'q': quit(); break;
125 case '?': showHelp(); break;
126 default: console.log('Say what?! (? for help)'); break;
127 }
128 lastcmd = cmd;
129 lastargs = str;
130 rl.prompt();
Simon Hunta25cdcd2015-01-22 13:11:42 -0800131
Simon Hunt711ee242015-01-22 15:08:02 -0800132 }).on('close', function () {
133 quit();
134 });
135}
Simon Hunta25cdcd2015-01-22 13:11:42 -0800136
Simon Hunt711ee242015-01-22 15:08:02 -0800137var helptext = '\n' +
Simon Hunt5724fb42015-02-05 16:59:40 -0800138 'l - list scenarios\n' +
Simon Hunt711ee242015-01-22 15:08:02 -0800139 'c - show connection status\n' +
140 'm {text} - send custom message to client\n' +
Simon Huntb0ec1e52015-01-28 18:13:49 -0800141 's {id} - load scenario {id}\n' +
Simon Hunt5724fb42015-02-05 16:59:40 -0800142 's - show scenario status\n' +
Simon Hunt711ee242015-01-22 15:08:02 -0800143 //'a - auto-send events\n' +
144 'n - send next event\n' +
Simon Huntb0ec1e52015-01-28 18:13:49 -0800145 'r - restart the scenario\n' +
Simon Hunt711ee242015-01-22 15:08:02 -0800146 'q - exit the server\n' +
147 '? - display this help text\n';
Simon Hunta25cdcd2015-01-22 13:11:42 -0800148
Simon Hunt711ee242015-01-22 15:08:02 -0800149function showHelp() {
150 console.log(helptext);
151}
152
Simon Hunt5724fb42015-02-05 16:59:40 -0800153function listScenarios() {
154 console.log('Scenarios ...');
155 console.log(scFiles.join(', '));
156 console.log();
157}
158
Simon Hunt711ee242015-01-22 15:08:02 -0800159function connStatus() {
160 if (connection) {
161 console.log('Connection from ' + origin + ' established.');
162 } else {
163 console.log('No connection.');
164 }
165}
166
167function quit() {
Simon Huntb0ec1e52015-01-28 18:13:49 -0800168 console.log('Quitting...');
Simon Hunt711ee242015-01-22 15:08:02 -0800169 process.exit(0);
170}
171
172function customMessage(m) {
173 if (connection) {
Simon Huntb0ec1e52015-01-28 18:13:49 -0800174 console.log('Sending message: ' + m);
Simon Hunt711ee242015-01-22 15:08:02 -0800175 connection.sendUTF(m);
176 } else {
177 console.warn('No current connection.');
178 }
179}
180
181function showScenarioStatus() {
182 var msg;
Simon Hunt626d2102015-01-29 11:54:50 -0800183 if (!scid) {
Simon Huntb0ec1e52015-01-28 18:13:49 -0800184 console.log('No scenario loaded.');
Simon Hunt711ee242015-01-22 15:08:02 -0800185 } else {
Simon Hunt626d2102015-01-29 11:54:50 -0800186 msg = 'Scenario: "' + scid + '", ' +
Simon Hunt711ee242015-01-22 15:08:02 -0800187 (scdone ? 'DONE' : 'next event: ' + evno);
188 console.log(msg);
189 }
190}
191
192function scenarioPath(evno) {
Simon Hunt74928302015-01-30 12:42:06 -0800193 var file = evno ? ('/' + eventsById[evno].fname) : '/scenario.json';
194 return scenarioRoot + scid + file;
Simon Hunt626d2102015-01-29 11:54:50 -0800195}
196
197
198function initScenario(verb) {
199 console.log(); // get past prompt
200 console.log(verb + ' scenario "' + scid + '"');
201 console.log(scdata.title);
202 scdata.description.forEach(function (d) {
203 console.log(' ' + d);
204 });
205 evno = 1;
206 scdone = false;
Simon Hunt74928302015-01-30 12:42:06 -0800207 readEventFilenames();
208}
209
210function readEventFilenames() {
211 var files = fs.readdirSync(scenarioRoot + scid),
212 eventCount = 0,
213 match, id, tag;
214
215 maxEvno = 0;
216
217 eventsById = {};
218 files.forEach(function (f) {
219 match = /^ev_(\d+)_(.*)\.json$/.exec(f);
220 if (match) {
221 eventCount++;
222 id = match[1];
223 tag = match[2];
224 eventsById[id] = {
225 fname: f,
226 num: id,
227 tag: tag
228 };
229 if (Number(id) > Number(maxEvno)) {
230 maxEvno = id;
231 }
232 }
233
234 });
235 console.log('[' + eventCount + ' events loaded, (max=' + maxEvno + ')]');
Simon Hunt711ee242015-01-22 15:08:02 -0800236}
237
238function setScenario(id) {
239 if (!id) {
240 return showScenarioStatus();
241 }
242
243 evdata = null;
Simon Hunt626d2102015-01-29 11:54:50 -0800244 scid = id;
Simon Hunt711ee242015-01-22 15:08:02 -0800245 fs.readFile(scenarioPath(), 'utf8', function (err, data) {
246 if (err) {
247 console.warn('No scenario named "' + id + '"', err);
Simon Hunt626d2102015-01-29 11:54:50 -0800248 scid = null;
Simon Hunt711ee242015-01-22 15:08:02 -0800249 } else {
Simon Hunt626d2102015-01-29 11:54:50 -0800250 scdata = JSON.parse(data);
251 initScenario('Loading');
Simon Hunta25cdcd2015-01-22 13:11:42 -0800252 }
253 rl.prompt();
Simon Hunta25cdcd2015-01-22 13:11:42 -0800254 });
Simon Hunt711ee242015-01-22 15:08:02 -0800255}
Simon Hunta25cdcd2015-01-22 13:11:42 -0800256
Simon Huntb0ec1e52015-01-28 18:13:49 -0800257function restartScenario() {
Simon Hunt626d2102015-01-29 11:54:50 -0800258 if (!scid) {
Simon Huntb0ec1e52015-01-28 18:13:49 -0800259 console.log('No scenario loaded.');
260 } else {
Simon Hunt626d2102015-01-29 11:54:50 -0800261 initScenario('Restarting');
Simon Huntb0ec1e52015-01-28 18:13:49 -0800262 }
263 rl.prompt();
264}
265
Simon Hunt711ee242015-01-22 15:08:02 -0800266function nextEvent() {
267 var path;
268
Simon Hunt626d2102015-01-29 11:54:50 -0800269 if (!scid) {
Simon Huntb0ec1e52015-01-28 18:13:49 -0800270 console.log('No scenario loaded.');
Simon Hunt711ee242015-01-22 15:08:02 -0800271 rl.prompt();
272 } else if (!connection) {
273 console.warn('No current connection.');
274 rl.prompt();
275 } else {
Simon Hunt74928302015-01-30 12:42:06 -0800276 if (Number(evno) > Number(maxEvno)) {
277 // done
278 scdone = true;
279 console.log('Scenario DONE.');
280 } else {
281 // fire next event
282 path = scenarioPath(evno);
283 fs.readFile(path, 'utf8', function (err, data) {
284 if (err) {
285 console.log('Oops error: ' + err);
286 } else {
287 evdata = JSON.parse(data);
288 console.log(); // get past prompt
Simon Hunt45c9fe52015-02-02 19:06:29 -0800289 console.log('Sending event #' + evno + ' [' + evdata.event +
290 '] from ' + eventsById[evno].fname);
Simon Hunt74928302015-01-30 12:42:06 -0800291 connection.sendUTF(data);
292 evno++;
293 }
294 rl.prompt();
295 });
296 }
Simon Hunt711ee242015-01-22 15:08:02 -0800297 }
Simon Hunta25cdcd2015-01-22 13:11:42 -0800298}