RLG-Web: make login sessions time out.

After enough inactivity, log the user out automatically.
This commit is contained in:
John "Elwin" Edwards 2012-06-09 21:20:14 -07:00
parent aba0a4b7da
commit 20d72fc066
2 changed files with 55 additions and 4 deletions

View file

@ -164,6 +164,9 @@ function processMsg(msg) {
else if (msgDict.t == "E") { else if (msgDict.t == "E") {
if (msgDict.c == 1 || msgDict.c == 6 || msgDict.c == 7) { if (msgDict.c == 1 || msgDict.c == 6 || msgDict.c == 7) {
gameover(); gameover();
if (msgDict.c == 1) {
logout();
}
} }
debug(1, "Server error: " + msgDict.s); debug(1, "Server error: " + msgDict.s);
} }
@ -496,6 +499,9 @@ function startgame(game) {
} }
else if (reply.t == 'E') { else if (reply.t == 'E') {
debug(1, "Could not start game: " + reply.s); debug(1, "Could not start game: " + reply.s);
if (reply.c == 1) {
logout();
}
} }
}; };
req.open('POST', '/play', true); req.open('POST', '/play', true);
@ -551,6 +557,12 @@ function gameover() {
return; return;
} }
function logout() {
lcred = null;
lname = null;
setmode("login");
}
function stop() { function stop() {
if (!termemu.sessid) if (!termemu.sessid)
return; return;

View file

@ -59,7 +59,7 @@ var allowlogin = true;
* been authenticated. * been authenticated.
*/ */
/* TODO take a callback, or emit success/err events. */ /* TODO take a callback, or emit success/err events. */
function TermSession(game, user, dims) { function TermSession(game, user, dims, lkey) {
/* First make sure starting the game will work. */ /* First make sure starting the game will work. */
if (game in games) { if (game in games) {
this.game = games[game]; this.game = games[game];
@ -69,6 +69,7 @@ function TermSession(game, user, dims) {
return null; return null;
} }
this.player = String(user); this.player = String(user);
this.key = lkey;
/* This order seems to best avoid race conditions... */ /* This order seems to best avoid race conditions... */
this.alive = false; this.alive = false;
this.sessid = randkey(2); this.sessid = randkey(2);
@ -361,6 +362,14 @@ function reaper() {
fs.fstat(session.record.fd, function (err, stats) { fs.fstat(session.record.fd, function (err, stats) {
if (!err && now - stats.mtime > playtimeout) { if (!err && now - stats.mtime > playtimeout) {
tslog("Reaping %s", session.sessid); tslog("Reaping %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);
if (now - logins[session.key].ts > playtimeout)
logins[session.key].ts = new Date(now - playtimeout);
}
/* Shut it down. */
session.close(); session.close();
} }
}); });
@ -368,6 +377,35 @@ function reaper() {
for (var sessid in sessions) { for (var sessid in sessions) {
reapcheck(sessions[sessid]); reapcheck(sessions[sessid]);
} }
/* HELPME this is about as clever as I can code, so I can't tell whether
* there are any bugs. */
for (var lkey in logins) {
if (logins[lkey].sessions.length == 0) {
/* A login with no current games can be killed for inactivity. */
if (now - logins[lkey].ts > playtimeout * 4) {
tslog("Login for %s (key %s) timed out", logins[lkey].name, lkey);
delete logins[lkey];
}
}
else {
/* Check for games that have terminated normally, and update
* the timestamp. */
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) {
logins[lkey].ts = new Date(now);
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) {
@ -400,7 +438,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()}; logins[lkey] = {"name": username, "ts": new Date(), "sessions": []};
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));
@ -452,7 +490,7 @@ function startgame(req, res, formdata) {
return; return;
} }
// Game starting has been approved. // Game starting has been approved.
var nsession = new TermSession(gname, username, dims); var nsession = new TermSession(gname, username, dims, lkey);
if (nsession) { if (nsession) {
res.writeHead(200, {'Content-Type': 'application/json'}); res.writeHead(200, {'Content-Type': 'application/json'});
var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h": var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h":
@ -461,6 +499,7 @@ function startgame(req, res, formdata) {
res.end(); res.end();
tslog("%s playing %s (key %s, pid %d)", username, gname, tslog("%s playing %s (key %s, pid %d)", username, gname,
nsession.sessid, nsession.child.pid); nsession.sessid, nsession.child.pid);
logins[lkey].sessions.push(nsession.sessid);
} }
else { else {
sendError(res, 5, "Failed to open TTY"); sendError(res, 5, "Failed to open TTY");
@ -506,7 +545,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()}; logins[lkey] = {"name": uname, "ts": new Date(), "sessions": []};
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));