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