Mercurial > hg > rlgwebd
comparison rlgterm.js @ 16:ef6127ed6da3
RLGWeb: switch to JSON protocol.
Port the JSON communication from WebTTY to RLGWeb. Fixing out-of-order
messages is still not implemented on the server side. Terminal size is
still hard-coded. Unused code is still lying around.
| author | John "Elwin" Edwards <elwin@sdf.org> |
|---|---|
| date | Thu, 17 May 2012 09:32:19 -0700 |
| parents | 826a7ced69f8 |
| children | 188bbd857124 |
comparison
equal
deleted
inserted
replaced
| 15:7466927c17a5 | 16:ef6127ed6da3 |
|---|---|
| 109 } | 109 } |
| 110 termemu.write(codes); | 110 termemu.write(codes); |
| 111 return; | 111 return; |
| 112 } | 112 } |
| 113 | 113 |
| 114 /* State for sending and receiving messages. */ | |
| 115 var nsend = 0; // The number of the next packet to send. | |
| 116 var nrecv = 0; // The next packet expected. | |
| 117 var msgQ = []; // Queue for out-of-order messages. | |
| 118 | |
| 114 /* Processes a message from the server, returning true or false if it was a | 119 /* Processes a message from the server, returning true or false if it was a |
| 115 * data message with or without data, null if not data. */ | 120 * data message with or without data, null if not data. |
| 121 * All non-special responseTexts should be handed directly to this function. | |
| 122 */ | |
| 116 function processMsg(msg) { | 123 function processMsg(msg) { |
| 117 var msglines = msg.split("\n"); | 124 var msgDict; |
| 118 var havedata = null; | 125 var havedata = null; // eventual return value |
| 119 if (!msglines[0]) | 126 try { |
| 127 msgDict = JSON.parse(msg); | |
| 128 } catch (e) { | |
| 129 if (e instanceof SyntaxError) | |
| 130 return null; | |
| 131 } | |
| 132 if (!msgDict.t) | |
| 120 return null; | 133 return null; |
| 121 if (msglines[0].charAt(0) == 'd') { | 134 else if (msgDict.t == "E") { |
| 122 if (msglines[1]){ | 135 if (msgDict.c == 1) { |
| 123 writeData(msglines[1]); | 136 logout(); |
| 124 havedata = true; | 137 } |
| 138 debug(1, "Server error: " + msgDict.s); | |
| 139 } | |
| 140 else if (msgDict.t == "n") { | |
| 141 havedata = false; | |
| 142 } | |
| 143 // A data message | |
| 144 else if (msgDict.t == "d"){ | |
| 145 if (msgDict.n === nrecv) { | |
| 146 writeData(msgDict.d); | |
| 147 nrecv++; | |
| 148 /* Process anything in the queue that's now ready. */ | |
| 149 var next; | |
| 150 while ((next = msgQ.shift()) !== undefined) { | |
| 151 writeData(next.d); | |
| 152 nrecv++; | |
| 153 } | |
| 154 } | |
| 155 else if (response.n > nrecv) { | |
| 156 /* The current message comes after one still missing. Queue this one | |
| 157 * for later use. */ | |
| 158 debug(1, "Got packet " + msgDict.n + ", expected " + nrecv); | |
| 159 msgQ[msgDict.n - nrecv - 1] = msgDict; | |
| 125 } | 160 } |
| 126 else { | 161 else { |
| 127 havedata = false; | 162 /* This message's number was encountered previously. */ |
| 128 } | 163 debug(1, "Discarding packet " + msgDict.n + ", expected " + nrecv); |
| 129 } | 164 } |
| 130 else if (msglines[0] == "E1") { | 165 havedata = true; |
| 166 } | |
| 167 else if (msgDict.t == "T") { | |
| 168 setTitle(msgDict.d); | |
| 169 } | |
| 170 else if (msgDict.t == "q") { | |
| 131 logout(); | 171 logout(); |
| 132 } | 172 } |
| 133 else if (msglines[0].charAt(0) == "T") { | |
| 134 setTitle(msglines[1]); | |
| 135 } | |
| 136 else if (msglines[0] == "q1") { | |
| 137 logout(); | |
| 138 } | |
| 139 else { | 173 else { |
| 140 debug(1, "Unrecognized server message " + msglines[0]); | 174 debug(1, "Unrecognized server message " + msg); |
| 141 } | 175 } |
| 142 return havedata; | 176 return havedata; |
| 143 } | 177 } |
| 144 | 178 |
| 145 function getData() { | 179 function getData() { |
| 146 if (termemu.sessid == null) | 180 if (termemu.sessid == null) |
| 147 return; | 181 return; |
| 148 var datareq = new XMLHttpRequest(); | 182 var datareq = new XMLHttpRequest(); |
| 183 var msg = JSON.stringify({"id": termemu.sessid, "t": "n"}); | |
| 149 datareq.onreadystatechange = function () { | 184 datareq.onreadystatechange = function () { |
| 150 if (datareq.readyState == 4 && datareq.status == 200) { | 185 if (datareq.readyState == 4 && datareq.status == 200) { |
| 151 var wasdata = processMsg(datareq.responseText); | 186 var wasdata = processMsg(datareq.responseText); |
| 152 if (wasdata != null) { | 187 if (wasdata != null) { |
| 153 if (wasdata) | 188 if (wasdata) |
| 157 } | 192 } |
| 158 return; | 193 return; |
| 159 } | 194 } |
| 160 }; | 195 }; |
| 161 datareq.open('POST', '/feed', true); | 196 datareq.open('POST', '/feed', true); |
| 162 datareq.send("id=" + termemu.sessid); | 197 datareq.send(msg); |
| 163 return; | 198 return; |
| 164 } | 199 } |
| 165 | 200 |
| 166 function postResponseHandler() { | 201 function postResponseHandler() { |
| 167 if (this.readyState == 4 && this.status == 200) { | 202 if (this.readyState == 4 && this.status == 200) { |
| 172 } | 207 } |
| 173 } | 208 } |
| 174 | 209 |
| 175 function sendback(str) { | 210 function sendback(str) { |
| 176 /* For responding to terminal queries. */ | 211 /* For responding to terminal queries. */ |
| 212 var msgDict = {"id": termemu.sessid, "t": "d", "n": nsend++, "d": str}; | |
| 177 var datareq = new XMLHttpRequest(); | 213 var datareq = new XMLHttpRequest(); |
| 178 datareq.onreadystatechange = postResponseHandler; | 214 datareq.onreadystatechange = postResponseHandler; |
| 179 datareq.open('POST', '/feed', true); | 215 datareq.open('POST', '/feed', true); |
| 180 datareq.send("id=" + termemu.sessid + "&keys=" + str); | 216 datareq.send(JSON.stringify(msgDict)); |
| 181 return; | 217 return; |
| 182 } | 218 } |
| 183 | 219 |
| 184 function sendkey(ev) { | 220 function sendkey(ev) { |
| 185 if (termemu.sessid == null) | 221 if (termemu.sessid == null) |
| 217 } | 253 } |
| 218 else { | 254 else { |
| 219 debug(1, "Ignoring keycode " + keynum); | 255 debug(1, "Ignoring keycode " + keynum); |
| 220 return; | 256 return; |
| 221 } | 257 } |
| 258 // Isn't this check redundant? | |
| 222 if (termemu.sessid != null) | 259 if (termemu.sessid != null) |
| 223 ev.preventDefault(); | 260 ev.preventDefault(); |
| 224 var datareq = new XMLHttpRequest(); | 261 var datareq = new XMLHttpRequest(); |
| 262 var msgDict = {"id": termemu.sessid, "t": "d", "n": nsend++, "d": code}; | |
| 225 datareq.onreadystatechange = postResponseHandler; | 263 datareq.onreadystatechange = postResponseHandler; |
| 226 datareq.open('POST', '/feed', true); | 264 datareq.open('POST', '/feed', true); |
| 227 datareq.send("id=" + termemu.sessid + "&keys=" + code); | 265 datareq.send(JSON.stringify(msgDict)); |
| 228 return; | 266 return; |
| 229 } | 267 } |
| 230 | 268 |
| 231 var charshifts = { '-': "5f", '=': "2b", '[': "7b", ']': "7d", '\\': "7c", | 269 var charshifts = { '-': "5f", '=': "2b", '[': "7b", ']': "7d", '\\': "7c", |
| 232 ';': "3a", '\'': "22", ',': "3c", '.': "3e", '/': "3f", '`': "7e" | 270 ';': "3a", '\'': "22", ',': "3c", '.': "3e", '/': "3f", '`': "7e" |
| 268 else | 306 else |
| 269 keystr = c.charCodeAt(0).toString(16); | 307 keystr = c.charCodeAt(0).toString(16); |
| 270 } | 308 } |
| 271 else | 309 else |
| 272 return; | 310 return; |
| 273 //writeData("Sending " + keystr); | |
| 274 var datareq = new XMLHttpRequest(); | 311 var datareq = new XMLHttpRequest(); |
| 312 var msgDict = {"id": termemu.sessid, "t": "d", "n": nsend++, "d": keystr}; | |
| 275 datareq.onreadystatechange = postResponseHandler; | 313 datareq.onreadystatechange = postResponseHandler; |
| 276 datareq.open('POST', '/feed', true); | 314 datareq.open('POST', '/feed', true); |
| 277 datareq.send("id=" + termemu.sessid + "&keys=" + keystr); | 315 datareq.send(JSON.stringify(msgDict)); |
| 278 return; | 316 return; |
| 279 } | 317 } |
| 280 | 318 |
| 281 function setup() { | 319 function setup() { |
| 282 keyHexCodes.init(); | 320 keyHexCodes.init(); |
| 307 | 345 |
| 308 function formlogin(ev) { | 346 function formlogin(ev) { |
| 309 ev.preventDefault(); | 347 ev.preventDefault(); |
| 310 if (termemu.sessid != null) | 348 if (termemu.sessid != null) |
| 311 return; | 349 return; |
| 312 var formname = document.getElementById("input_name").value; | 350 var loginmsg = {}; |
| 313 var formpass = document.getElementById("input_pw").value; | 351 loginmsg["name"] = document.getElementById("input_name").value; |
| 314 var formgame = document.getElementById("input_game").value; | 352 loginmsg["pw"] = document.getElementById("input_pw").value; |
| 315 var formdata = "game=" + encodeURIComponent(formgame) + "&name=" + encodeURIComponent(formname) + "&pw=" + encodeURIComponent(formpass); | 353 loginmsg["game"] = document.getElementById("input_game").value; |
| 354 loginmsg["h"] = 24; | |
| 355 loginmsg["w"] = 80; | |
| 316 var req = new XMLHttpRequest(); | 356 var req = new XMLHttpRequest(); |
| 317 req.onreadystatechange = function () { | 357 req.onreadystatechange = function () { |
| 318 if (req.readyState == 4 && req.status == 200) { | 358 if (req.readyState != 4 || req.status != 200) |
| 319 var datalines = req.responseText.split("\n"); | 359 return; |
| 320 if (datalines[0] == 'l1') { | 360 var reply = JSON.parse(req.responseText); |
| 321 /* Success */ | 361 if (reply.t == 'l') { |
| 322 termemu.sessid = datalines[1]; | 362 /* Success */ |
| 323 setTitle("Playing as " + formname); | 363 termemu.sessid = reply.id; |
| 324 debug(1, "Logged in with id " + termemu.sessid); | 364 termemu.resize(reply.h, reply.w); |
| 325 document.getElementById("loginform").style.display = "none"; | 365 setTitle("Playing as " + loginmsg["name"]); |
| 326 getData(); | 366 debug(1, "Logged in with id " + termemu.sessid); |
| 327 } | 367 document.getElementById("loginform").style.display = "none"; |
| 328 else { | 368 getData(); |
| 329 debug(1, "Could not start game: " + datalines[1]); | 369 } |
| 330 document.getElementById("input_name").value = ""; | 370 else if (reply.t == 'E') { |
| 331 document.getElementById("input_pw").value = ""; | 371 debug(1, "Could not start game: " + reply.s); |
| 332 } | 372 document.getElementById("input_name").value = ""; |
| 373 document.getElementById("input_pw").value = ""; | |
| 333 } | 374 } |
| 334 }; | 375 }; |
| 335 req.open('POST', '/login', true); | 376 req.open('POST', '/login', true); |
| 336 req.send(formdata); | 377 req.send(JSON.stringify(loginmsg)); |
| 337 return; | 378 return; |
| 338 } | 379 } |
| 339 | 380 |
| 340 function logout() { | 381 function logout() { |
| 341 if (termemu.sessid == null) | 382 if (termemu.sessid == null) |
| 342 return; | 383 return; |
| 343 termemu.sessid = null; | 384 termemu.sessid = null; |
| 344 setTitle("Game over."); | 385 setTitle("Game over."); |
| 386 nsend = 0; | |
| 387 nrecv = 0; | |
| 388 msgQ = []; | |
| 345 document.getElementById("loginform").style.display = "block"; | 389 document.getElementById("loginform").style.display = "block"; |
| 346 return; | 390 return; |
| 347 } | 391 } |
| 348 | 392 |
| 349 function stop() { | 393 function stop() { |
| 353 processMsg(req.responseText); | 397 processMsg(req.responseText); |
| 354 return; | 398 return; |
| 355 } | 399 } |
| 356 }; | 400 }; |
| 357 req.open('POST', '/feed', true); | 401 req.open('POST', '/feed', true); |
| 358 req.send("id=" + termemu.sessid + "&quit=quit"); | 402 req.send(JSON.stringify({"id": termemu.sessid, "t": "q"})); |
| 359 return; | 403 return; |
| 360 } | 404 } |
| 361 | 405 |
| 362 function debug(level, msg) { | 406 function debug(level, msg) { |
| 363 if (level < debugSuppress) | 407 if (level < debugSuppress) |
