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.
This commit is contained in:
John "Elwin" Edwards 2015-01-06 16:59:12 -05:00
parent 2064d2a9e6
commit 547387846f

View file

@ -191,6 +191,100 @@ function TermSession(game, lkey, dims, handlers) {
}
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 @@ function startProgressWatcher() {
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 {