comparison rlgwebd.js @ 175:4dd87508fc96

Add server-side support for watching dgamelaunch games.
author John "Elwin" Edwards
date Tue, 13 Jan 2015 20:30:10 -0500
parents dc12ba30d559
children bf518a00190b
comparison
equal deleted inserted replaced
174:dc12ba30d559 175:4dd87508fc96
295 } 295 }
296 ss.reading = false; 296 ss.reading = false;
297 return; 297 return;
298 } 298 }
299 ss.rpos += 12; 299 ss.rpos += 12;
300 /* Update timestamp, to within 1 second. */
301 ss.lasttime = new Date(1000 * buf.readUInt32LE(0));
300 var datalen = buf.readUInt32LE(8); 302 var datalen = buf.readUInt32LE(8);
301 //tslog("Allocating %d bytes", datalen); 303 //tslog("Allocating %d bytes", datalen);
302 if (datalen > 16384) { 304 if (datalen > 16384) {
303 tslog("DGL %s: looking for %d bytes", ss.tag(), datalen); 305 tslog("DGL %s: looking for %d bytes", ss.tag(), datalen);
304 } 306 }
313 } 315 }
314 ss.rpos += n; 316 ss.rpos += n;
315 ss.reading = false; 317 ss.reading = false;
316 /* Process the data */ 318 /* Process the data */
317 ss.framepush(buf); 319 ss.framepush(buf);
320 var wmsg = JSON.stringify({"t": "d", "d": buf.toString("hex")});
321 for (var i = 0; i < ss.watchers.length; i++) {
322 if (ss.watchers[i].connected)
323 ss.watchers[i].sendUTF(wmsg);
324 }
318 ss.emit("data", buf); 325 ss.emit("data", buf);
319 //tslog("DGL %s: %d bytes", ss.tag(), buf.length); 326 //tslog("DGL %s: %d bytes", ss.tag(), buf.length);
320 /* Recurse. */ 327 /* Recurse. */
321 ss.readchunk(); 328 ss.readchunk();
322 }); 329 });
337 else { 344 else {
338 ss.fd = fd; 345 ss.fd = fd;
339 ss.emit('open', true); 346 ss.emit('open', true);
340 tslog("DGL %s: open", ss.tag()); 347 tslog("DGL %s: open", ss.tag());
341 ss.readchunk(); 348 ss.readchunk();
342 ss.watcher = fs.watch(ss.ttyrec, function (ev, finame) { 349 ss.recwatcher = fs.watch(ss.ttyrec, function (ev, finame) {
343 if (ev == "change") 350 if (ev == "change")
344 ss.readchunk(); 351 ss.readchunk();
345 }); 352 });
346 } 353 }
347 }); 354 });
348 }); 355 });
349 this.tag = function () { 356 this.tag = function () {
350 return this.gname + "/" + this.pname; 357 return this.gname + "/" + this.pname;
351 }; 358 };
352 this.close = function () { 359 this.close = function () {
353 this.watcher.close() 360 this.recwatcher.close()
354 /* Ensure all data is handled before quitting. */ 361 /* Ensure all data is handled before quitting. */
355 this.readchunk(); 362 this.readchunk();
363 var connlist = this.watchers;
364 this.watchers = [];
365 for (var i = 0; i < connlist.length; i++) {
366 if (connlist[i].connected)
367 connlist[i].close();
368 }
356 fs.close(this.fd); 369 fs.close(this.fd);
357 this.emit("close"); 370 this.emit("close");
358 tslog("DGL %s: closed", ss.tag()); 371 tslog("DGL %s: closed", ss.tag());
359 }; 372 };
373 this.watchers = [];
374 /* Attach a watcher. */
375 this.attach = function (wsReq) {
376 var conn = wsReq.accept(null, wsReq.origin);
377 conn.sendUTF(JSON.stringify({
378 "t": "w", "w": this.w, "h": this.h, "p": this.pname,
379 "g": this.gname
380 }));
381 conn.sendUTF(JSON.stringify({"t": "d",
382 "d": this.framebuf.toString("hex", 0, this.frameoff)}));
383 conn.on('close', function () {
384 /* 'this' is the connection when triggered */
385 var n = ss.watchers.indexOf(this);
386 if (n >= 0) {
387 ss.watchers.splice(n, 1);
388 tslog("A WebSocket watcher has left DGL game %s", ss.tag());
389 }
390 });
391 this.watchers.push(conn);
392 };
393 this.lasttime = new Date();
360 } 394 }
361 DglSession.prototype = new events.EventEmitter(); 395 DglSession.prototype = new events.EventEmitter();
362 396
363 function wsStartGame(wsReq) { 397 function wsStartGame(wsReq) {
364 var playmatch = wsReq.resourceURL.pathname.match(/^\/play\/([^\/]*)$/); 398 var playmatch = wsReq.resourceURL.pathname.match(/^\/play\/([^\/]*)$/);
788 for (var tag in sessions) { 822 for (var tag in sessions) {
789 var gamedesc = {}; 823 var gamedesc = {};
790 gamedesc["p"] = sessions[tag].pname; 824 gamedesc["p"] = sessions[tag].pname;
791 gamedesc["g"] = sessions[tag].game.uname; 825 gamedesc["g"] = sessions[tag].game.uname;
792 gamedesc["i"] = now - sessions[tag].lasttime; 826 gamedesc["i"] = now - sessions[tag].lasttime;
827 gamedesc["w"] = sessions[tag].watchers.length;
793 statusinfo["g"].push(gamedesc); 828 statusinfo["g"].push(gamedesc);
794 } 829 }
795 statusinfo["dgl"] = []; 830 statusinfo["dgl"] = [];
796 for (var tag in dglgames) { 831 for (var tag in dglgames) {
797 var dglinfo = {}; 832 var dglinfo = {};
798 var slash = tag.search('/'); 833 var slash = tag.search('/');
799 dglinfo["g"] = tag.slice(0, slash); 834 dglinfo["g"] = tag.slice(0, slash);
800 dglinfo["p"] = tag.slice(slash + 1); 835 dglinfo["p"] = tag.slice(slash + 1);
801 dglinfo["i"] = -1; 836 dglinfo["i"] = now - dglgames[tag].lasttime;
837 dglinfo["w"] = dglgames[tag].watchers.length;
802 statusinfo["dgl"].push(dglinfo); 838 statusinfo["dgl"].push(dglinfo);
803 } 839 }
804 callback(statusinfo); 840 callback(statusinfo);
805 } 841 }
806 842
1020 1056
1021 function wsHandler(wsRequest) { 1057 function wsHandler(wsRequest) {
1022 var watchmatch = wsRequest.resource.match(/^\/watch\/(.*)$/); 1058 var watchmatch = wsRequest.resource.match(/^\/watch\/(.*)$/);
1023 var playmatch = wsRequest.resource.match(/^\/play\//); 1059 var playmatch = wsRequest.resource.match(/^\/play\//);
1024 if (watchmatch !== null) { 1060 if (watchmatch !== null) {
1025 if (!(watchmatch[1] in sessions)) { 1061 if (watchmatch[1] in sessions) {
1062 var tsession = sessions[watchmatch[1]];
1063 tsession.attach(wsRequest);
1064 tslog("Game %s is being watched via WebSockets", tsession.tag());
1065 }
1066 else if (watchmatch[1] in dglgames) {
1067 var dsession = dglgames[watchmatch[1]];
1068 dsession.attach(wsRequest);
1069 tslog("DGL game %s is being watched via WebSockets", dsession.tag());
1070 }
1071 else {
1026 wsRequest.reject(404, errorcodes[7]); 1072 wsRequest.reject(404, errorcodes[7]);
1027 return; 1073 return;
1028 } 1074 }
1029 var tsession = sessions[watchmatch[1]];
1030 tsession.attach(wsRequest);
1031 tslog("Game %s is being watched via WebSockets", tsession.tag());
1032 } 1075 }
1033 else if (playmatch !== null) { 1076 else if (playmatch !== null) {
1034 wsStartGame(wsRequest); 1077 wsStartGame(wsRequest);
1035 } 1078 }
1036 else if (wsRequest.resourceURL.pathname == "/status") { 1079 else if (wsRequest.resourceURL.pathname == "/status") {
1075 if (delta < 60000) { 1118 if (delta < 60000) {
1076 var gamedesc = {}; 1119 var gamedesc = {};
1077 gamedesc["p"] = sessions[tag].pname; 1120 gamedesc["p"] = sessions[tag].pname;
1078 gamedesc["g"] = sessions[tag].game.uname; 1121 gamedesc["g"] = sessions[tag].game.uname;
1079 gamedesc["i"] = delta; 1122 gamedesc["i"] = delta;
1123 gamedesc["w"] = sessions[tag].watchers.length;
1080 statusinfo["g"].push(gamedesc); 1124 statusinfo["g"].push(gamedesc);
1081 } 1125 }
1082 } 1126 }
1083 for (var tag in dglgames) { 1127 for (var tag in dglgames) {
1084 var dglinfo = {}; 1128 var delta = now - dglgames[tag].lasttime;
1085 var slash = tag.search('/'); 1129 if (delta < 60000) {
1086 dglinfo["g"] = tag.slice(0, slash); 1130 var dglinfo = {};
1087 dglinfo["p"] = tag.slice(slash + 1); 1131 var slash = tag.search('/');
1088 dglinfo["i"] = -1; 1132 dglinfo["g"] = tag.slice(0, slash);
1089 statusinfo["dgl"].push(dglinfo); 1133 dglinfo["p"] = tag.slice(slash + 1);
1134 dglinfo["i"] = delta;
1135 dglinfo["w"] = dglgames[tag].watchers.length;
1136 statusinfo["dgl"].push(dglinfo);
1137 }
1090 } 1138 }
1091 gamemux.emit('list', statusinfo); 1139 gamemux.emit('list', statusinfo);
1092 } 1140 }
1093 1141
1094 function shutdown () { 1142 function shutdown () {