diff --git a/rlgterm.js b/rlgterm.js index 95174c8..f385f37 100644 --- a/rlgterm.js +++ b/rlgterm.js @@ -164,6 +164,9 @@ function processMsg(msg) { else if (msgDict.t == "E") { if (msgDict.c == 1 || msgDict.c == 6 || msgDict.c == 7) { gameover(); + if (msgDict.c == 1) { + logout(); + } } debug(1, "Server error: " + msgDict.s); } @@ -496,6 +499,9 @@ function startgame(game) { } else if (reply.t == 'E') { debug(1, "Could not start game: " + reply.s); + if (reply.c == 1) { + logout(); + } } }; req.open('POST', '/play', true); @@ -551,6 +557,12 @@ function gameover() { return; } +function logout() { + lcred = null; + lname = null; + setmode("login"); +} + function stop() { if (!termemu.sessid) return; diff --git a/rlgwebd.js b/rlgwebd.js index bdf6a48..028fda3 100755 --- a/rlgwebd.js +++ b/rlgwebd.js @@ -59,7 +59,7 @@ var allowlogin = true; * been authenticated. */ /* 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. */ if (game in games) { this.game = games[game]; @@ -69,6 +69,7 @@ function TermSession(game, user, dims) { return null; } this.player = String(user); + this.key = lkey; /* This order seems to best avoid race conditions... */ this.alive = false; this.sessid = randkey(2); @@ -361,6 +362,14 @@ function reaper() { fs.fstat(session.record.fd, function (err, stats) { if (!err && now - stats.mtime > playtimeout) { 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(); } }); @@ -368,6 +377,35 @@ function reaper() { for (var sessid in sessions) { 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) { @@ -400,7 +438,7 @@ function login(req, res, formdata) { var lkey = randkey(2); while (lkey in logins) 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'}); var reply = {"t": "l", "k": lkey, "u": username}; res.write(JSON.stringify(reply)); @@ -452,7 +490,7 @@ function startgame(req, res, formdata) { return; } // Game starting has been approved. - var nsession = new TermSession(gname, username, dims); + var nsession = new TermSession(gname, username, dims, lkey); if (nsession) { res.writeHead(200, {'Content-Type': 'application/json'}); var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h": @@ -461,6 +499,7 @@ function startgame(req, res, formdata) { res.end(); tslog("%s playing %s (key %s, pid %d)", username, gname, nsession.sessid, nsession.child.pid); + logins[lkey].sessions.push(nsession.sessid); } else { sendError(res, 5, "Failed to open TTY"); @@ -506,7 +545,7 @@ function register(req, res, formdata) { var lkey = randkey(2); while (lkey in logins) 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}; res.writeHead(200, {'Content-Type': 'application/json'}); res.write(JSON.stringify(reply));