Mercurial > hg > rlgwebd
comparison rlgwebd.js @ 47:27b7f0c8b9f0
RLG-Web: make login sessions time out.
After enough inactivity, log the user out automatically.
| author | John "Elwin" Edwards <elwin@sdf.org> |
|---|---|
| date | Sat, 09 Jun 2012 21:20:14 -0700 |
| parents | c4efc7522e7b |
| children | 423ef87ddc9b |
comparison
equal
deleted
inserted
replaced
| 46:59ecd99845eb | 47:27b7f0c8b9f0 |
|---|---|
| 57 /* Constructor for TermSessions. Note that it opens the terminal and | 57 /* Constructor for TermSessions. Note that it opens the terminal and |
| 58 * adds itself to the sessions dict. It currently assumes the user has | 58 * adds itself to the sessions dict. It currently assumes the user has |
| 59 * been authenticated. | 59 * been authenticated. |
| 60 */ | 60 */ |
| 61 /* TODO take a callback, or emit success/err events. */ | 61 /* TODO take a callback, or emit success/err events. */ |
| 62 function TermSession(game, user, dims) { | 62 function TermSession(game, user, dims, lkey) { |
| 63 /* First make sure starting the game will work. */ | 63 /* First make sure starting the game will work. */ |
| 64 if (game in games) { | 64 if (game in games) { |
| 65 this.game = games[game]; | 65 this.game = games[game]; |
| 66 } | 66 } |
| 67 else { | 67 else { |
| 68 // TODO: throw an exception instead | 68 // TODO: throw an exception instead |
| 69 return null; | 69 return null; |
| 70 } | 70 } |
| 71 this.player = String(user); | 71 this.player = String(user); |
| 72 this.key = lkey; | |
| 72 /* This order seems to best avoid race conditions... */ | 73 /* This order seems to best avoid race conditions... */ |
| 73 this.alive = false; | 74 this.alive = false; |
| 74 this.sessid = randkey(2); | 75 this.sessid = randkey(2); |
| 75 while (this.sessid in sessions) { | 76 while (this.sessid in sessions) { |
| 76 this.sessid = randkey(2); | 77 this.sessid = randkey(2); |
| 359 if (!session.alive) | 360 if (!session.alive) |
| 360 return; | 361 return; |
| 361 fs.fstat(session.record.fd, function (err, stats) { | 362 fs.fstat(session.record.fd, function (err, stats) { |
| 362 if (!err && now - stats.mtime > playtimeout) { | 363 if (!err && now - stats.mtime > playtimeout) { |
| 363 tslog("Reaping %s", session.sessid); | 364 tslog("Reaping %s", session.sessid); |
| 365 /* Dissociate it with its login name. */ | |
| 366 var sn = logins[session.key].sessions.indexOf(session.sessid); | |
| 367 if (sn >= 0) { | |
| 368 logins[session.key].sessions.splice(sn, 1); | |
| 369 if (now - logins[session.key].ts > playtimeout) | |
| 370 logins[session.key].ts = new Date(now - playtimeout); | |
| 371 } | |
| 372 /* Shut it down. */ | |
| 364 session.close(); | 373 session.close(); |
| 365 } | 374 } |
| 366 }); | 375 }); |
| 367 } | 376 } |
| 368 for (var sessid in sessions) { | 377 for (var sessid in sessions) { |
| 369 reapcheck(sessions[sessid]); | 378 reapcheck(sessions[sessid]); |
| 379 } | |
| 380 /* HELPME this is about as clever as I can code, so I can't tell whether | |
| 381 * there are any bugs. */ | |
| 382 for (var lkey in logins) { | |
| 383 if (logins[lkey].sessions.length == 0) { | |
| 384 /* A login with no current games can be killed for inactivity. */ | |
| 385 if (now - logins[lkey].ts > playtimeout * 4) { | |
| 386 tslog("Login for %s (key %s) timed out", logins[lkey].name, lkey); | |
| 387 delete logins[lkey]; | |
| 388 } | |
| 389 } | |
| 390 else { | |
| 391 /* Check for games that have terminated normally, and update | |
| 392 * the timestamp. */ | |
| 393 var expired = []; | |
| 394 var targarray = logins[lkey].sessions; | |
| 395 /* Let's not find out what happens if you modify an array | |
| 396 * you're iterating through. */ | |
| 397 for (var i = 0; i < targarray.length; i++) { | |
| 398 if (!(targarray[i] in sessions)) | |
| 399 expired.push(targarray[i]); | |
| 400 } | |
| 401 if (expired.length > 0) { | |
| 402 logins[lkey].ts = new Date(now); | |
| 403 for (var j = 0; j < expired.length; j++) { | |
| 404 targarray.splice(targarray.indexOf(expired[j], 1)); | |
| 405 } | |
| 406 } | |
| 407 } | |
| 370 } | 408 } |
| 371 } | 409 } |
| 372 | 410 |
| 373 function login(req, res, formdata) { | 411 function login(req, res, formdata) { |
| 374 if (!allowlogin) { | 412 if (!allowlogin) { |
| 398 return; | 436 return; |
| 399 } | 437 } |
| 400 var lkey = randkey(2); | 438 var lkey = randkey(2); |
| 401 while (lkey in logins) | 439 while (lkey in logins) |
| 402 lkey = randkey(2); | 440 lkey = randkey(2); |
| 403 logins[lkey] = {"name": username, "ts": new Date()}; | 441 logins[lkey] = {"name": username, "ts": new Date(), "sessions": []}; |
| 404 res.writeHead(200, {'Content-Type': 'application/json'}); | 442 res.writeHead(200, {'Content-Type': 'application/json'}); |
| 405 var reply = {"t": "l", "k": lkey, "u": username}; | 443 var reply = {"t": "l", "k": lkey, "u": username}; |
| 406 res.write(JSON.stringify(reply)); | 444 res.write(JSON.stringify(reply)); |
| 407 res.end(); | 445 res.end(); |
| 408 tslog("%s has logged in (key %s)", username, lkey); | 446 tslog("%s has logged in (key %s)", username, lkey); |
| 450 sendError(res, 4, null); | 488 sendError(res, 4, null); |
| 451 tslog("%s is already playing %s", username, gname); | 489 tslog("%s is already playing %s", username, gname); |
| 452 return; | 490 return; |
| 453 } | 491 } |
| 454 // Game starting has been approved. | 492 // Game starting has been approved. |
| 455 var nsession = new TermSession(gname, username, dims); | 493 var nsession = new TermSession(gname, username, dims, lkey); |
| 456 if (nsession) { | 494 if (nsession) { |
| 457 res.writeHead(200, {'Content-Type': 'application/json'}); | 495 res.writeHead(200, {'Content-Type': 'application/json'}); |
| 458 var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h": | 496 var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h": |
| 459 nsession.h}; | 497 nsession.h}; |
| 460 res.write(JSON.stringify(reply)); | 498 res.write(JSON.stringify(reply)); |
| 461 res.end(); | 499 res.end(); |
| 462 tslog("%s playing %s (key %s, pid %d)", username, gname, | 500 tslog("%s playing %s (key %s, pid %d)", username, gname, |
| 463 nsession.sessid, nsession.child.pid); | 501 nsession.sessid, nsession.child.pid); |
| 502 logins[lkey].sessions.push(nsession.sessid); | |
| 464 } | 503 } |
| 465 else { | 504 else { |
| 466 sendError(res, 5, "Failed to open TTY"); | 505 sendError(res, 5, "Failed to open TTY"); |
| 467 tslog("Unable to allocate TTY for %s", gname); | 506 tslog("Unable to allocate TTY for %s", gname); |
| 468 } | 507 } |
| 504 function checkreg(code, signal) { | 543 function checkreg(code, signal) { |
| 505 if (code === 0) { | 544 if (code === 0) { |
| 506 var lkey = randkey(2); | 545 var lkey = randkey(2); |
| 507 while (lkey in logins) | 546 while (lkey in logins) |
| 508 lkey = randkey(2); | 547 lkey = randkey(2); |
| 509 logins[lkey] = {"name": uname, "ts": new Date()}; | 548 logins[lkey] = {"name": uname, "ts": new Date(), "sessions": []}; |
| 510 var reply = {"t": "r", "k": lkey, "u": uname}; | 549 var reply = {"t": "r", "k": lkey, "u": uname}; |
| 511 res.writeHead(200, {'Content-Type': 'application/json'}); | 550 res.writeHead(200, {'Content-Type': 'application/json'}); |
| 512 res.write(JSON.stringify(reply)); | 551 res.write(JSON.stringify(reply)); |
| 513 res.end(); | 552 res.end(); |
| 514 tslog("Added new user: %s", uname); | 553 tslog("Added new user: %s", uname); |
