diff 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
line wrap: on
line diff
--- 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);
 }