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); |