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)