Opera works! Fix message event drops/reorders.

Instead of relying on FABridge AS -> JS event delivery, we just use
the events to notify JS of pending data. The message handler then
calls the AS readSocketData routine which sends back an array of
the pending WebSocket frames.

There is still a minor bug somewhere that happens after the first
connect where the web-socket-js throws an "INVALID_STATE_ERR: Web
Socket connection has not been established". But, Opera is now usable
and we should be able to drop the packet sequence numbering and
re-ordering code.

Another minor issue to better support Opera is to move JS script
includes to the <head> of the page instead of after the body.
This commit is contained in:
Joel Martin 2010-07-01 09:53:38 -05:00
parent 1eba7b4279
commit a93c955538
6 changed files with 48 additions and 46 deletions

View File

@ -90,9 +90,9 @@ I only currently test under Linux. Here are the current results:
full-color images are slow.
* Arora 0.50: Works. Broken putImageData so large full-color images
are slow.
* Opera 10.60: Works. Uses flash WebSockets emulator. Large full-color
images are slow.
* Opera 10.10: Unusable: drops web-socket-js events.
* Opera 10.60: Broken: throws "WRONG_ARGUMENTS_ERR" on connect.
* Konqueror 4.2.2: Broken: flash WebSockets emulator never connects.
@ -105,11 +105,13 @@ structure and style.
At a minimum you must include the `vnc.js` and `default_controls.js`
scripts and call their load() functions. For example:
<head>
<script src='include/vnc.js'></script>
<script src="include/default_controls.js"></script>
</head>
<body>
<div id='vnc'>Loading</div>
</body>
<script src='include/vnc.js'></script>
<script src="include/default_controls.js"></script>
<script>
window.onload = function () {
DefaultControls.load('vnc');

View File

@ -2,7 +2,8 @@ Short Term:
- Test on IE 9 preview 3.
- Support Opera 10.60 (WebSocket frames dropped).
- Track down "INVALID_STATE_ERR" when reconnecting using
web-socket-js.
- Possibly support IE <= 8.0 using excanvas or fxcanvas:
http://excanvas.sourceforge.net/

View File

@ -48,6 +48,7 @@ public class WebSocket extends EventDispatcher {
private var origin:String;
private var protocol:String;
private var buffer:ByteArray = new ByteArray();
private var dataQueue:Array;
private var headerState:int = 0;
private var readyState:int = CONNECTING;
private var bufferedAmount:int = 0;
@ -61,6 +62,7 @@ public class WebSocket extends EventDispatcher {
headers:String = null) {
this.main = main;
initNoiseChars();
dataQueue = [];
this.url = url;
var m:Array = url.match(/^(\w+):\/\/([^\/:]+)(:(\d+))?(\/.*)?$/);
if (!m) main.fatal("SYNTAX_ERR: invalid url: " + url);
@ -270,30 +272,10 @@ public class WebSocket extends EventDispatcher {
onError("data must start with \\x00");
return;
}
/*
var data:String = "", byte:uint;
while (buffer.bytesAvailable > 1) {
byte = buffer[buffer.position];
if (byte === 0x00) {
// readUTFBytes mishandles 0x00
data = data + "\x00";
buffer.position++;
} else if (byte === 0xff) {
// End of WebSocket frame
//ExternalInterface.call("console.log", "[WebSocket] early 0xff found");
break;
} else if ((byte & 0x80) === 0x00) {
// One UTF-8 input byte to one output byte
data = data + buffer.readUTFBytes(1);
} else {
// Assume two UTF-8 input bytes to one output byte
data = data + buffer.readUTFBytes(2);
}
}
*/
var data:String = buffer.readUTFBytes(pos - 1);
main.log("received: " + data);
dispatchEvent(new WebSocketMessageEvent("message", encodeURIComponent(data)));
dataQueue.push(encodeURIComponent(data));
dispatchEvent(new WebSocketMessageEvent("message", data.length.toString()));
buffer.readByte();
makeBufferCompact();
pos = -1;
@ -301,6 +283,15 @@ public class WebSocket extends EventDispatcher {
}
}
}
public function readSocketData():Array {
var q:Array = dataQueue;
if (dataQueue.length > 0) {
// Reset to empty
dataQueue = [];
}
return q;
}
private function validateHeader(headerStr:String):Boolean {
var lines:Array = headerStr.split(/\r\n/);

View File

@ -52,20 +52,24 @@
});
self.__flash.addEventListener("message", function(fe) {
var data = decodeURIComponent(fe.getData());
try {
if (self.onmessage) {
var e;
if (window.MessageEvent) {
e = document.createEvent("MessageEvent");
e.initMessageEvent("message", false, false, data, null, null, window, null);
} else { // IE
e = {data: data};
var i, arr, data;
arr = self.__flash.readSocketData();
for (i=0; i < arr.length; i++) {
data = decodeURIComponent(arr[i]);
try {
if (self.onmessage) {
var e;
if (window.MessageEvent) {
e = document.createEvent("MessageEvent");
e.initMessageEvent("message", false, false, data, null, null, window, null);
} else { // IE
e = {data: data};
}
self.onmessage(e);
}
self.onmessage(e);
} catch (e) {
console.error(e.toString());
}
} catch (e) {
console.error(e.toString());
}
});

View File

@ -5,18 +5,18 @@ noVNC example: simple example using default controls
<head>
<title>VNC Client</title>
<link rel="stylesheet" href="include/plain.css">
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="include/vnc.js"></script>
<script src="include/default_controls.js"></script>
</head>
<body>
<div id='vnc'>Loading</div>
</body>
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="include/vnc.js"></script>
<script src="include/default_controls.js"></script>
<script>
window.onload = function () {
DefaultControls.load('vnc');

View File

@ -8,6 +8,11 @@ Connect parameters are provided in query string:
<head>
<title>VNC Client</title>
<link rel="stylesheet" href="include/plain.css">
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="include/vnc.js"></script>
</head>
<body style="margin: 0px;">
@ -27,7 +32,6 @@ Connect parameters are provided in query string:
</div>
</body>
<script src="include/vnc.js"></script>
<script>
function setPassword() {
RFB.sendPassword($('password_input').value);