changeset 164:3a97e4ee50f0

rlgwebd.js: read ttyrecs created by dgamelaunch. TTYREC files created by dgamelaunch are tracked by DglSession objects, as a first step toward making them watchable.
author John "Elwin" Edwards
date Tue, 06 Jan 2015 16:59:12 -0500
parents 0f6da35b27a0
children 59e62710cbb5
files rlgwebd.js
diffstat 1 files changed, 97 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/rlgwebd.js	Sun Jan 04 16:55:57 2015 -0500
+++ b/rlgwebd.js	Tue Jan 06 16:59:12 2015 -0500
@@ -191,6 +191,100 @@
 }
 TermSession.prototype = new events.EventEmitter();
 
+function DglSession(filename) {
+  var ss = this;
+  events.EventEmitter.call(this);
+  var pathcoms = filename.split('/');
+  this.gname = pathcoms[pathcoms.length - 2];
+  if (!(this.gname in games)) {
+    ss.emit('open', false);
+    return;
+  }
+  var basename = pathcoms[pathcoms.length - 1];
+  var firstsep = basename.indexOf(':');
+  this.pname = basename.slice(0, firstsep);
+  var fname = basename.slice(firstsep + 1);
+  this.ttyrec = path.join("/dgldir/ttyrec", this.pname, this.gname, fname);
+  this.framebuf = new Buffer(1024);
+  this.frameoff = 0;
+  this.framepush = function(chunk) {
+    /* If this chunk resets the screen, discard what preceded it. */
+    var cgame = games[this.gname];
+    if (bufncmp(chunk, cgame.clear, cgame.clear.length)) {
+      tslog("DGL %s: clearing frame", ss.tag());
+      this.framebuf = new Buffer(1024);
+      this.frameoff = 0;
+    }
+    /* Make sure there's space. */
+    while (this.framebuf.length < chunk.length + this.frameoff) {
+      var nbuf = new Buffer(this.framebuf.length * 2);
+      this.framebuf.copy(nbuf, 0, 0, this.frameoff);
+      this.framebuf = nbuf;
+      if (this.framebuf.length > 65536) {
+        tslog("Warning: DGL %s frame buffer at %d bytes", this.tag(), 
+                this.framebuf.length);
+      }
+    }
+    chunk.copy(this.framebuf, this.frameoff);
+    this.frameoff += chunk.length;
+  };
+  this.readchunk = function () {
+    var header = new Buffer(12);
+    fs.read(ss.fd, header, 0, 12, null, function (err, n, buf) {
+      /* Stop recursion if end of file has been reached. */
+      if (err || n < 12)
+        return;
+      var datalen = buf.readUInt32LE(8);
+      //tslog("Allocating %d bytes", datalen);
+      var databuf = new Buffer(datalen);
+      fs.read(ss.fd, databuf, 0, datalen, null, function (err, n, buf) {
+        if (err || n < datalen)
+          return;
+        /* Process the data */
+        ss.framepush(buf);
+        ss.emit("data", buf);
+        tslog("DGL %s: %d bytes", ss.tag(), buf.length);
+        /* Recurse. */
+        ss.readchunk();
+      });
+    });
+  };
+  fs.readFile(filename, {encoding: "utf8"}, function (err, data) {
+    if (err) {
+      ss.emit('open', false);
+      return;
+    }
+    var lines = data.split('\n');
+    ss.h = Number(lines[1]);
+    ss.w = Number(lines[2]);
+    fs.open(ss.ttyrec, "r", function(err, fd) {
+      if (err) {
+        ss.emit('open', false);
+      }
+      else {
+        ss.fd = fd;
+        ss.emit('open', true);
+        tslog("DGL %s: open", ss.tag());
+        ss.readchunk();
+        ss.watcher = fs.watch(ss.ttyrec, function (ev, finame) {
+          if (ev == "change")
+            ss.readchunk();
+        });
+      }
+    });
+  });
+  this.tag = function () {
+    return this.gname + "/" + this.pname;
+  };
+  this.close = function () {
+    this.watcher.close()
+    fs.close(this.fd);
+    this.emit("close");
+    tslog("DGL %s: closed", ss.tag());
+  };
+}
+DglSession.prototype = new events.EventEmitter();
+
 // Also known as WebSocketAndTermSessionClosureGlueFactory
 function wsWatcher(conn, session) {
   var ss = this; // is this even needed?
@@ -631,14 +725,15 @@
     var tag = gname + "/" + pname;
     if (chunk[0] == "E") {
       tslog("DGL: %s is playing %s: %s", pname, gname, fname)
-      dglgames[tag] = fname;
+      dglgames[tag] = new DglSession(fname);
     }
     else if (chunk[0] == "C") {
       tslog("DGL: %s started playing %s: %s", pname, gname, fname)
-      dglgames[tag] = fname;
+      dglgames[tag] = new DglSession(fname);
     }
     else if (chunk[0] == "D") {
       tslog("DGL: %s finished playing %s: %s", pname, gname, fname)
+      dglgames[tag].close();
       delete dglgames[tag];
     }
     else {