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