comparison shterm.js @ 14:155f3c104759

shterm.js: Client-side message ordering Make sure data from the server is written to the terminal emulator in the correct order. Out-of-order messages are stored in a queue until their turn comes.
author John "Elwin" Edwards <elwin@sdf.org>
date Tue, 15 May 2012 09:30:12 -0700
parents bf7c26d0b66d
children 7a50b4412fea
comparison
equal deleted inserted replaced
13:bf7c26d0b66d 14:155f3c104759
1 /* shterm.js: browser-side JavaScript to handle I/O for termemu.js when it 1 /* shterm.js: browser-side JavaScript to handle I/O for termemu.js when it
2 * is running a shell via the webtty.js server. 2 * is running a shell via the webtty.js server.
3 */ 3 */
4 4
5 /* The number of the next packet to send. */ 5 var nsend = 0; // The number of the next packet to send.
6 var nsend = 0; 6 var nrecv = 0; // The next packet expected.
7 var msgQ = []; // Queue for out-of-order messages.
7 8
8 // A state machine that keeps track of polling the server. 9 // A state machine that keeps track of polling the server.
9 var ajaxstate = { 10 var ajaxstate = {
10 state: 0, 11 state: 0,
11 timerID: null, 12 timerID: null,
114 } 115 }
115 termemu.write(codes); 116 termemu.write(codes);
116 return; 117 return;
117 } 118 }
118 119
120 function processMsg(response) {
121 if (response.t != "d" || typeof(response.d) != "string")
122 return;
123 if (response.n === nrecv) {
124 writeData(response.d);
125 nrecv++;
126 var next;
127 /* msgQ must be shifted every time nrecv is incremented, but the process
128 * stops whenever an empty space, corresponding to an unarrived message,
129 * is encountered.
130 */
131 while ((next = msgQ.shift()) !== undefined) {
132 writeData(next.d);
133 nrecv++;
134 }
135 }
136 else if (response.n > nrecv) {
137 /* The current message comes after one still missing. Queue this one
138 * for later use.
139 */
140 debug(1, "Got packet " + response.n + ", expected " + nrecv);
141 msgQ[response.n - nrecv - 1] = response;
142 }
143 else {
144 /* This message's number was encountered previously. */
145 debug(1, "Discarding packet " + response.n + ", expected " + nrecv);
146 }
147 }
148
119 function getData() { 149 function getData() {
120 if (!termemu.alive) 150 if (!termemu.alive)
121 return; 151 return;
122 var datareq = new XMLHttpRequest(); 152 var datareq = new XMLHttpRequest();
123 datareq.onreadystatechange = function () { 153 datareq.onreadystatechange = function () {
132 } 162 }
133 } 163 }
134 else if (response.t == "n") 164 else if (response.t == "n")
135 ajaxstate.gotnothing(); 165 ajaxstate.gotnothing();
136 else if (response.t == "d") { 166 else if (response.t == "d") {
137 writeData(response.d); 167 processMsg(response);
138 debug(1, "Got packet " + response.n);
139 ajaxstate.gotdata(); 168 ajaxstate.gotdata();
140 } 169 }
141 return; 170 return;
142 } 171 }
143 }; 172 };
160 } 189 }
161 else if (response.t != "d") 190 else if (response.t != "d")
162 return; 191 return;
163 /* It is a data message */ 192 /* It is a data message */
164 if (response.d) { 193 if (response.d) {
165 writeData(response.d); 194 processMsg(response);
166 debug(1, "Got packet " + response.n); 195 //debug(1, "Got packet " + response.n);
167 } 196 }
168 ajaxstate.posted(); 197 ajaxstate.posted();
169 return; 198 return;
170 } 199 }
171 } 200 }
314 if (logindict.login) { 343 if (logindict.login) {
315 /* Success */ 344 /* Success */
316 termemu.resize(logindict.h, logindict.w); 345 termemu.resize(logindict.h, logindict.w);
317 termemu.alive = true; 346 termemu.alive = true;
318 nsend = 0; 347 nsend = 0;
348 nrecv = 0;
319 setTitle("Logged in"); 349 setTitle("Logged in");
320 debug(1, "Logged in with id " + logindict.id); 350 debug(1, "Logged in with id " + logindict.id);
321 getData(); 351 getData();
322 return; 352 return;
323 } 353 }