# HG changeset patch # User John "Elwin" Edwards # Date 1420581552 18000 # Node ID 3a97e4ee50f098987f86d35fe8967552cfc93538 # Parent 0f6da35b27a0c80d211043d9a4b83627ff5c676c 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. diff -r 0f6da35b27a0 -r 3a97e4ee50f0 rlgwebd.js --- 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 {