# HG changeset patch # User John "Elwin" Edwards # Date 1421199010 18000 # Node ID 4dd87508fc9649caa7eb651f20e63a3e696f88a6 # Parent dc12ba30d55963ff25238a839b54916dfa103c0a Add server-side support for watching dgamelaunch games. diff -r dc12ba30d559 -r 4dd87508fc96 rlgwebd.js --- a/rlgwebd.js Mon Jan 12 17:10:35 2015 +0000 +++ b/rlgwebd.js Tue Jan 13 20:30:10 2015 -0500 @@ -297,6 +297,8 @@ return; } ss.rpos += 12; + /* Update timestamp, to within 1 second. */ + ss.lasttime = new Date(1000 * buf.readUInt32LE(0)); var datalen = buf.readUInt32LE(8); //tslog("Allocating %d bytes", datalen); if (datalen > 16384) { @@ -315,6 +317,11 @@ ss.reading = false; /* Process the data */ ss.framepush(buf); + var wmsg = JSON.stringify({"t": "d", "d": buf.toString("hex")}); + for (var i = 0; i < ss.watchers.length; i++) { + if (ss.watchers[i].connected) + ss.watchers[i].sendUTF(wmsg); + } ss.emit("data", buf); //tslog("DGL %s: %d bytes", ss.tag(), buf.length); /* Recurse. */ @@ -339,7 +346,7 @@ ss.emit('open', true); tslog("DGL %s: open", ss.tag()); ss.readchunk(); - ss.watcher = fs.watch(ss.ttyrec, function (ev, finame) { + ss.recwatcher = fs.watch(ss.ttyrec, function (ev, finame) { if (ev == "change") ss.readchunk(); }); @@ -350,13 +357,40 @@ return this.gname + "/" + this.pname; }; this.close = function () { - this.watcher.close() + this.recwatcher.close() /* Ensure all data is handled before quitting. */ this.readchunk(); + var connlist = this.watchers; + this.watchers = []; + for (var i = 0; i < connlist.length; i++) { + if (connlist[i].connected) + connlist[i].close(); + } fs.close(this.fd); this.emit("close"); tslog("DGL %s: closed", ss.tag()); }; + this.watchers = []; + /* Attach a watcher. */ + this.attach = function (wsReq) { + var conn = wsReq.accept(null, wsReq.origin); + conn.sendUTF(JSON.stringify({ + "t": "w", "w": this.w, "h": this.h, "p": this.pname, + "g": this.gname + })); + conn.sendUTF(JSON.stringify({"t": "d", + "d": this.framebuf.toString("hex", 0, this.frameoff)})); + conn.on('close', function () { + /* 'this' is the connection when triggered */ + var n = ss.watchers.indexOf(this); + if (n >= 0) { + ss.watchers.splice(n, 1); + tslog("A WebSocket watcher has left DGL game %s", ss.tag()); + } + }); + this.watchers.push(conn); + }; + this.lasttime = new Date(); } DglSession.prototype = new events.EventEmitter(); @@ -790,6 +824,7 @@ gamedesc["p"] = sessions[tag].pname; gamedesc["g"] = sessions[tag].game.uname; gamedesc["i"] = now - sessions[tag].lasttime; + gamedesc["w"] = sessions[tag].watchers.length; statusinfo["g"].push(gamedesc); } statusinfo["dgl"] = []; @@ -798,7 +833,8 @@ var slash = tag.search('/'); dglinfo["g"] = tag.slice(0, slash); dglinfo["p"] = tag.slice(slash + 1); - dglinfo["i"] = -1; + dglinfo["i"] = now - dglgames[tag].lasttime; + dglinfo["w"] = dglgames[tag].watchers.length; statusinfo["dgl"].push(dglinfo); } callback(statusinfo); @@ -1022,13 +1058,20 @@ var watchmatch = wsRequest.resource.match(/^\/watch\/(.*)$/); var playmatch = wsRequest.resource.match(/^\/play\//); if (watchmatch !== null) { - if (!(watchmatch[1] in sessions)) { + if (watchmatch[1] in sessions) { + var tsession = sessions[watchmatch[1]]; + tsession.attach(wsRequest); + tslog("Game %s is being watched via WebSockets", tsession.tag()); + } + else if (watchmatch[1] in dglgames) { + var dsession = dglgames[watchmatch[1]]; + dsession.attach(wsRequest); + tslog("DGL game %s is being watched via WebSockets", dsession.tag()); + } + else { wsRequest.reject(404, errorcodes[7]); return; } - var tsession = sessions[watchmatch[1]]; - tsession.attach(wsRequest); - tslog("Game %s is being watched via WebSockets", tsession.tag()); } else if (playmatch !== null) { wsStartGame(wsRequest); @@ -1077,16 +1120,21 @@ gamedesc["p"] = sessions[tag].pname; gamedesc["g"] = sessions[tag].game.uname; gamedesc["i"] = delta; + gamedesc["w"] = sessions[tag].watchers.length; statusinfo["g"].push(gamedesc); } } for (var tag in dglgames) { - var dglinfo = {}; - var slash = tag.search('/'); - dglinfo["g"] = tag.slice(0, slash); - dglinfo["p"] = tag.slice(slash + 1); - dglinfo["i"] = -1; - statusinfo["dgl"].push(dglinfo); + var delta = now - dglgames[tag].lasttime; + if (delta < 60000) { + var dglinfo = {}; + var slash = tag.search('/'); + dglinfo["g"] = tag.slice(0, slash); + dglinfo["p"] = tag.slice(slash + 1); + dglinfo["i"] = delta; + dglinfo["w"] = dglgames[tag].watchers.length; + statusinfo["dgl"].push(dglinfo); + } } gamemux.emit('list', statusinfo); }