Mercurial > hg > rlgwebd
comparison rlgwebd.js @ 104:7d444ba4739e
RLG-Web server: send status events over WebSockets.
A WebSocket connection to /status will be sent periodic listings, along
with notifications of the beginning and end of games.
| author | John "Elwin" Edwards <elwin@sdf.org> | 
|---|---|
| date | Fri, 13 Jul 2012 22:26:20 -0700 | 
| parents | f30495f7ede8 | 
| children | b64e31c5ec31 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 103:f30495f7ede8 | 104:7d444ba4739e | 
|---|---|
| 60 var logins = {}; | 60 var logins = {}; | 
| 61 var sessions = {}; | 61 var sessions = {}; | 
| 62 var clients = {}; | 62 var clients = {}; | 
| 63 var allowlogin = true; | 63 var allowlogin = true; | 
| 64 var nextsession = 0; | 64 var nextsession = 0; | 
| 65 var gamemux = new events.EventEmitter(); | |
| 65 | 66 | 
| 66 /* Constructor. A TermSession handles a pty and the game running on it. | 67 /* Constructor. A TermSession handles a pty and the game running on it. | 
| 67 * game: (String) Name of the game to launch. | 68 * game: (String) Name of the game to launch. | 
| 68 * lkey: (String, key) The user's id, a key into logins. | 69 * lkey: (String, key) The user's id, a key into logins. | 
| 69 * dims: (Array [Number, Number]) Height and width of the pty. | 70 * dims: (Array [Number, Number]) Height and width of the pty. | 
| 116 "name": "xterm-256color"}; | 117 "name": "xterm-256color"}; | 
| 117 this.term = pty.spawn(this.game.path, args, spawnopts); | 118 this.term = pty.spawn(this.game.path, args, spawnopts); | 
| 118 tslog("%s playing %s (index %d, pid %d)", this.pname, this.game.uname, | 119 tslog("%s playing %s (index %d, pid %d)", this.pname, this.game.uname, | 
| 119 this.sessid, this.term.pid); | 120 this.sessid, this.term.pid); | 
| 120 this.emit('open', true, this.sessid); | 121 this.emit('open', true, this.sessid); | 
| 122 gamemux.emit('begin', this.sessid, this.pname, this.game.uname); | |
| 121 /* Set up the lockfile and ttyrec */ | 123 /* Set up the lockfile and ttyrec */ | 
| 122 var ts = timestamp(); | 124 var ts = timestamp(); | 
| 123 var progressdir = "/dgldir/inprogress-" + this.game.uname; | 125 var progressdir = "/dgldir/inprogress-" + this.game.uname; | 
| 124 this.lock = path.join(progressdir, this.pname + ":node:" + ts + ".ttyrec"); | 126 this.lock = path.join(progressdir, this.pname + ":node:" + ts + ".ttyrec"); | 
| 125 var lmsg = this.term.pid.toString() + '\n' + this.w + '\n' + this.h + '\n'; | 127 var lmsg = this.term.pid.toString() + '\n' + this.w + '\n' + this.h + '\n'; | 
| 175 ss.record.end(); | 177 ss.record.end(); | 
| 176 ss.emit('exit'); | 178 ss.emit('exit'); | 
| 177 var id = ss.sessid; | 179 var id = ss.sessid; | 
| 178 delete sessions[id]; | 180 delete sessions[id]; | 
| 179 tslog("Game %s ended.", id); | 181 tslog("Game %s ended.", id); | 
| 182 gamemux.emit('end', id); | |
| 180 }); | 183 }); | 
| 181 this.close = function () { | 184 this.close = function () { | 
| 182 this.term.kill('SIGHUP'); | 185 this.term.kill('SIGHUP'); | 
| 183 }; | 186 }; | 
| 184 } | 187 } | 
| 1060 req.on('end', respond); | 1063 req.on('end', respond); | 
| 1061 | 1064 | 
| 1062 } | 1065 } | 
| 1063 | 1066 | 
| 1064 function wsHandler(wsRequest) { | 1067 function wsHandler(wsRequest) { | 
| 1065 var urlmatch = wsRequest.resource.match(/^\/watch\/([0-9]*)$/); | 1068 var watchmatch = wsRequest.resource.match(/^\/watch\/([0-9]*)$/); | 
| 1066 if (urlmatch !== null && urlmatch[1] && Number(urlmatch[1]) in sessions) { | 1069 if (watchmatch !== null) { | 
| 1067 var tsession = sessions[Number(urlmatch[1])]; | 1070 if (watchmatch[1] && Number(watchmatch[1]) in sessions) { | 
| 1071 var tsession = sessions[Number(watchmatch[1])]; | |
| 1072 var conn = wsRequest.accept(null, wsRequest.origin); | |
| 1073 new wsWatcher(conn, tsession); | |
| 1074 tslog("Game %d is being watched via WebSockets", tsession.sessid); | |
| 1075 } | |
| 1076 else | |
| 1077 wsRequest.reject(404, errorcodes[7]); | |
| 1078 } | |
| 1079 else if (wsRequest.resource == "/status") { | |
| 1068 var conn = wsRequest.accept(null, wsRequest.origin); | 1080 var conn = wsRequest.accept(null, wsRequest.origin); | 
| 1069 new wsWatcher(conn, tsession); | 1081 var tell = function () { | 
| 1070 tslog("Game %d is being watched via WebSockets", tsession.sessid); | 1082 getStatus(function (info) { | 
| 1083 info["t"] = "t"; | |
| 1084 conn.sendUTF(JSON.stringify(info)); | |
| 1085 }); | |
| 1086 } | |
| 1087 var beginH = function (n, name, game) { | |
| 1088 conn.sendUTF(JSON.stringify({"t": "b", "n": n, "p": name, "g": game})); | |
| 1089 }; | |
| 1090 var listH = function (list) { | |
| 1091 conn.sendUTF(JSON.stringify(list)); | |
| 1092 }; | |
| 1093 var endH = function (n) { | |
| 1094 conn.sendUTF(JSON.stringify({"t": "e", "n": n})); | |
| 1095 }; | |
| 1096 gamemux.on('begin', beginH); | |
| 1097 gamemux.on('list', listH); | |
| 1098 gamemux.on('end', endH); | |
| 1099 conn.on('message', tell); | |
| 1100 conn.on('close', function () { | |
| 1101 gamemux.removeListener('begin', beginH); | |
| 1102 gamemux.removeListener('list', listH); | |
| 1103 gamemux.removeListener('end', endH); | |
| 1104 }); | |
| 1105 tell(); | |
| 1071 } | 1106 } | 
| 1072 else | 1107 else | 
| 1073 wsRequest.reject(404, errorcodes[7]); | 1108 wsRequest.reject(404, "No such resource."); | 
| 1109 } | |
| 1110 | |
| 1111 function pushStatus() { | |
| 1112 getStatus(function(info) { | |
| 1113 info["t"] = "t"; | |
| 1114 gamemux.emit('list', info); | |
| 1115 }); | |
| 1074 } | 1116 } | 
| 1075 | 1117 | 
| 1076 function shutdown () { | 1118 function shutdown () { | 
| 1077 httpServer.close(); | 1119 httpServer.close(); | 
| 1078 httpServer.removeAllListeners('request'); | 1120 httpServer.removeAllListeners('request'); | 
| 1152 tslog('rlgwebd running on port %d', httpPort); | 1194 tslog('rlgwebd running on port %d', httpPort); | 
| 1153 setInterval(reaper, playtimeout / 4); | 1195 setInterval(reaper, playtimeout / 4); | 
| 1154 wsServer = new WebSocketServer({"httpServer": httpServer}); | 1196 wsServer = new WebSocketServer({"httpServer": httpServer}); | 
| 1155 wsServer.on("request", wsHandler); | 1197 wsServer.on("request", wsHandler); | 
| 1156 tslog('WebSockets are online'); | 1198 tslog('WebSockets are online'); | 
| 1199 setInterval(pushStatus, 4000); | |
| 1157 }); | 1200 }); | 
| 1158 | 1201 | 
