RLGWebD: Clean up code related to session timestamps.

TermSessions now store the timestamp of the latest data.  This removes
the need to use fstat() to calculate idle times.

The reaper() function is removed.  It may be useful to find another way
to remove old login keys.
This commit is contained in:
John "Elwin" Edwards 2015-01-03 17:39:15 -05:00
parent c7fc6418ff
commit abb4ba8f31

View file

@ -19,7 +19,6 @@ var httpPort = 8080;
var chrootDir = "/var/dgl/"; var chrootDir = "/var/dgl/";
var dropToUser = "rodney"; var dropToUser = "rodney";
var serveStaticRoot = "/var/www/"; // inside the chroot var serveStaticRoot = "/var/www/"; // inside the chroot
var playtimeout = 3600000; // Idle time before games are autosaved, in ms
/* Data on the games available. */ /* Data on the games available. */
var games = { var games = {
@ -122,7 +121,8 @@ function TermSession(game, lkey, dims, handlers) {
this.emit('open', true, this.game.uname, this.pname); this.emit('open', true, this.game.uname, this.pname);
gamemux.emit('begin', this.game.uname, this.pname); gamemux.emit('begin', this.game.uname, this.pname);
/* Set up the lockfile and ttyrec */ /* Set up the lockfile and ttyrec */
var ts = timestamp(); this.lasttime = new Date();
var ts = timestamp(this.lasttime);
var progressdir = path.join("/dgldir/inprogress", this.game.uname); var progressdir = path.join("/dgldir/inprogress", this.game.uname);
this.lock = path.join(progressdir, this.pname + ":node:" + ts + ".ttyrec"); this.lock = path.join(progressdir, this.pname + ":node:" + ts + ".ttyrec");
var lmsg = this.term.pid.toString() + '\n' + this.h + '\n' + this.w + '\n'; var lmsg = this.term.pid.toString() + '\n' + this.h + '\n' + this.w + '\n';
@ -134,15 +134,14 @@ function TermSession(game, lkey, dims, handlers) {
* with a complete screen. */ * with a complete screen. */
this.framebuf = new Buffer(1024); this.framebuf = new Buffer(1024);
this.frameoff = 0; this.frameoff = 0;
logins[lkey].sessions.push(this.game.uname + "/" + this.pname);
/* END setup */ /* END setup */
function ttyrec_chunk(datastr) { function ttyrec_chunk(datastr) {
var ts = new Date(); ss.lasttime = new Date();
var buf = new Buffer(datastr); var buf = new Buffer(datastr);
var chunk = new Buffer(buf.length + 12); var chunk = new Buffer(buf.length + 12);
/* TTYREC headers */ /* TTYREC headers */
chunk.writeUInt32LE(Math.floor(ts.getTime() / 1000), 0); chunk.writeUInt32LE(Math.floor(ss.lasttime.getTime() / 1000), 0);
chunk.writeUInt32LE(1000 * (ts.getTime() % 1000), 4); chunk.writeUInt32LE(1000 * (ss.lasttime.getTime() % 1000), 4);
chunk.writeUInt32LE(buf.length, 8); chunk.writeUInt32LE(buf.length, 8);
buf.copy(chunk, 12); buf.copy(chunk, 12);
ss.record.write(chunk); ss.record.write(chunk);
@ -373,8 +372,10 @@ function playerstatus(user, callback) {
} }
/* A few utility functions */ /* A few utility functions */
function timestamp() { function timestamp(dd) {
dd = new Date(); if (!(dd instanceof Date)) {
dd = new Date();
}
sd = dd.toISOString(); sd = dd.toISOString();
sd = sd.slice(0, sd.indexOf(".")); sd = sd.slice(0, sd.indexOf("."));
return sd.replace("T", "."); return sd.replace("T", ".");
@ -457,47 +458,6 @@ function getMsgWS(msgObj) {
return getMsg(msgObj.utf8Data); return getMsg(msgObj.utf8Data);
} }
/* FIXME sessid removal */
function reaper() {
return; // TODO figure out if this function is useful
var now = new Date();
function reapcheck(session) {
fs.fstat(session.record.fd, function (err, stats) {
if (!err && now - stats.mtime > playtimeout) {
tslog("Reaping session %s", session.sessid);
/* Dissociate it with its login name. */
var sn = logins[session.key].sessions.indexOf(session.sessid);
if (sn >= 0) {
logins[session.key].sessions.splice(sn, 1);
}
/* Shut it down. */
session.close();
}
});
}
for (var sessid in sessions) {
reapcheck(sessions[sessid]);
}
for (var lkey in logins) {
if (logins[lkey].sessions.length > 0) {
/* Check for games that have terminated normally, and remove them. */
var expired = [];
var targarray = logins[lkey].sessions;
/* Let's not find out what happens if you modify an array
* you're iterating through. */
for (var i = 0; i < targarray.length; i++) {
if (!(targarray[i] in sessions))
expired.push(targarray[i]);
}
if (expired.length > 0) {
for (var j = 0; j < expired.length; j++) {
targarray.splice(targarray.indexOf(expired[j]), 1);
}
}
}
}
}
function login(req, res, formdata) { function login(req, res, formdata) {
if (!allowlogin) { if (!allowlogin) {
sendError(res, 6, null, false); sendError(res, 6, null, false);
@ -528,7 +488,7 @@ function login(req, res, formdata) {
var lkey = randkey(2); var lkey = randkey(2);
while (lkey in logins) while (lkey in logins)
lkey = randkey(2); lkey = randkey(2);
logins[lkey] = {"name": username, "ts": new Date(), "sessions": []}; logins[lkey] = {"name": username, "ts": new Date()};
res.writeHead(200, {'Content-Type': 'application/json'}); res.writeHead(200, {'Content-Type': 'application/json'});
var reply = {"t": "l", "k": lkey, "u": username}; var reply = {"t": "l", "k": lkey, "u": username};
res.write(JSON.stringify(reply)); res.write(JSON.stringify(reply));
@ -579,7 +539,7 @@ function register(req, res, formdata) {
var lkey = randkey(2); var lkey = randkey(2);
while (lkey in logins) while (lkey in logins)
lkey = randkey(2); lkey = randkey(2);
logins[lkey] = {"name": uname, "ts": new Date(), "sessions": []}; logins[lkey] = {"name": uname, "ts": new Date()};
var reply = {"t": "r", "k": lkey, "u": uname}; var reply = {"t": "r", "k": lkey, "u": uname};
res.writeHead(200, {'Content-Type': 'application/json'}); res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify(reply)); res.write(JSON.stringify(reply));
@ -732,54 +692,23 @@ function serveStatic(req, res, fname) {
return; return;
} }
/* TODO simplify by storing timestamps instead of callin stat() */ /* Currently, this doesn't do anything blocking, but keep the callback */
function getStatus(callback) { function getStatus(callback) {
var now = new Date(); var now = new Date();
var statusinfo = {"s": allowlogin, "g": []}; var statusinfo = {"s": allowlogin, "g": []};
function idleset(n, idletime) {
if (n >= 0 && n < statusinfo.g.length) {
statusinfo.g[n].i = idletime;
}
for (var j = 0; j < statusinfo.g.length; j++) {
if (!("i" in statusinfo.g[j]))
return;
}
callback(statusinfo);
}
for (var tag in sessions) { for (var tag in sessions) {
var gamedesc = {}; var gamedesc = {};
gamedesc["tag"] = tag; gamedesc["tag"] = tag;
gamedesc["p"] = sessions[tag].pname; gamedesc["p"] = sessions[tag].pname;
gamedesc["g"] = sessions[tag].game.uname; gamedesc["g"] = sessions[tag].game.uname;
gamedesc["i"] = now - sessions[tag].lasttime;
statusinfo["g"].push(gamedesc); statusinfo["g"].push(gamedesc);
} }
statusinfo["dgl"] = []; statusinfo["dgl"] = [];
for (var tag in dglgames) { for (var tag in dglgames) {
statusinfo["dgl"].push(tag); statusinfo["dgl"].push(tag);
} }
if (statusinfo.g.length == 0) { callback(statusinfo);
callback(statusinfo);
return;
}
function makecallback(i) {
return function (err, stats) {
if (err)
idleset(i, null);
else
idleset(i, now - stats.mtime);
}
}
for (var i = 0; i < statusinfo.g.length; i++) {
/* fd sometimes isn't a number, presumably when the file isn't open yet. */
/* FIXME sessid -> tag */
var tag = statusinfo.g[i].tag;
if (tag in sessions && typeof(sessions[tag].record.fd) == 'number') {
fs.fstat(sessions[tag].record.fd, makecallback(i));
}
else {
idleset(i, null);
}
}
} }
function statusmsg(req, res) { function statusmsg(req, res) {
@ -1134,7 +1063,6 @@ ctlServer.listen(ctlsocket, function () {
httpServer = http.createServer(webHandler); httpServer = http.createServer(webHandler);
httpServer.listen(httpPort); httpServer.listen(httpPort);
tslog('rlgwebd running on port %d', httpPort); tslog('rlgwebd running on port %d', httpPort);
setInterval(reaper, playtimeout / 4);
wsServer = new WebSocketServer({"httpServer": httpServer}); wsServer = new WebSocketServer({"httpServer": httpServer});
wsServer.on("request", wsHandler); wsServer.on("request", wsHandler);
tslog('WebSockets are online'); tslog('WebSockets are online');