summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSolly Ross <sross@redhat.com>2017-03-01 21:10:09 -0500
committerSolly Ross <sross@redhat.com>2017-03-07 11:11:29 -0500
commit3af44ff67f89621886935fb5d151181900b8c751 (patch)
tree31977376bd9f8677efb4b9719c48dcad7f22dd64
parent38a57e4d79288dd9f1f2fba4585e9a2d362f73c3 (diff)
downloadnovnc-refactor/es6-module-loader.tar.gz
Make vnc_playback.html functional once morerefactor/es6-module-loader
This commit makes vnc_playback.html functional once more, and completely refactors tests/playback.js to make it usable in other scenarios. In order for vnc_playback.js to properly load playback files now, they must `export` their variables.
-rw-r--r--tests/playback-ui.js174
-rw-r--r--tests/playback.js279
-rw-r--r--tests/vnc_playback.html100
-rw-r--r--vendor/browser-es-module-loader/dist/browser-es-module-loader.js8
-rw-r--r--vendor/browser-es-module-loader/src/browser-es-module-loader.js8
5 files changed, 330 insertions, 239 deletions
diff --git a/tests/playback-ui.js b/tests/playback-ui.js
new file mode 100644
index 0000000..f47b9d8
--- /dev/null
+++ b/tests/playback-ui.js
@@ -0,0 +1,174 @@
+import * as WebUtil from '../app/webutil.js';
+import RecordingPlayer from './playback.js';
+
+var frames = null;
+var encoding = null;
+
+function message(str) {
+ console.log(str);
+ var cell = document.getElementById('messages');
+ cell.textContent += str + "\n";
+ cell.scrollTop = cell.scrollHeight;
+}
+
+function loadFile() {
+ const fname = WebUtil.getQueryVar('data', null);
+
+ if (!fname) {
+ return Promise.reject("Must specify data=FOO in query string.");
+ }
+
+ message("Loading " + fname);
+ return import(`../recordings/${fname}#nocache`);
+}
+
+function enableUI(recording) {
+ var iterations = WebUtil.getQueryVar('iterations', 3);
+ document.getElementById('iterations').value = iterations;
+
+ var mode = WebUtil.getQueryVar('mode', 3);
+ if (mode === 'realtime') {
+ document.getElementById('mode2').checked = true;
+ } else {
+ document.getElementById('mode1').checked = true;
+ }
+
+ message("VNC_frame_data.length: " + recording.VNC_frame_data.length);
+
+ const startButton = document.getElementById('startButton');
+ startButton.disabled = false
+ startButton.addEventListener('click', start);
+
+ frames = recording.VNC_frame_data;
+ encoding = recording.VNC_frame_encoding;
+}
+
+const notification = function (rfb, mesg, level, options) {
+ document.getElementById('VNC_status').textContent = mesg;
+}
+
+function IterationPlayer (iterations, frames, encoding) {
+ this._iterations = iterations;
+
+ this._iteration = undefined;
+ this._player = undefined;
+
+ this._start_time = undefined;
+
+ this._frames = frames;
+ this._encoding = encoding;
+
+ this._state = 'running';
+
+ this.onfinish = function() {};
+ this.oniterationfinish = function() {};
+ this.rfbdisconnected = function() {};
+ this.rfbnotification = function() {};
+}
+
+IterationPlayer.prototype = {
+ start: function (mode) {
+ this._iteration = 0;
+ this._start_time = (new Date()).getTime();
+
+ this._realtime = mode.startsWith('realtime');
+ this._trafficMgmt = !mode.endsWith('-no-mgmt');
+
+ this._nextIteration();
+ },
+
+ _nextIteration: function () {
+ const player = new RecordingPlayer(this._frames, this._encoding, this._disconnected.bind(this), this._notification.bind(this));
+ player.onfinish = this._iterationFinish.bind(this);
+
+ if (this._state !== 'running') { return; }
+
+ this._iteration++;
+ if (this._iteration > this._iterations) {
+ this._finish();
+ return;
+ }
+
+ player.run(this._realtime, this._trafficMgmt);
+ },
+
+ _finish: function () {
+ const endTime = (new Date()).getTime();
+ const totalDuration = endTime - this._start_time;
+
+ const evt = new Event('finish');
+ evt.duration = totalDuration;
+ evt.iterations = this._iterations;
+ this.onfinish(evt);
+ },
+
+ _iterationFinish: function (duration) {
+ const evt = new Event('iterationfinish');
+ evt.duration = duration;
+ evt.number = this._iteration;
+ this.oniterationfinish(evt);
+
+ this._nextIteration();
+ },
+
+ _disconnected: function (rfb, reason, frame) {
+ if (reason) {
+ this._state = 'failed';
+ }
+
+ var evt = new Event('rfbdisconnected');
+ evt.reason = reason;
+ evt.frame = frame;
+
+ this.onrfbdisconnected(evt);
+ },
+
+ _notification: function (rfb, msg, level, options) {
+ var evt = new Event('rfbnotification');
+ evt.message = msg;
+ evt.level = level;
+ evt.options = options;
+
+ this.onrfbnotification(evt);
+ },
+};
+
+function start() {
+ document.getElementById('startButton').value = "Running";
+ document.getElementById('startButton').disabled = true;
+
+ const iterations = document.getElementById('iterations').value;
+
+ var mode;
+
+ if (document.getElementById('mode1').checked) {
+ message(`Starting performance playback (fullspeed) [${iterations} iteration(s)]`);
+ mode = 'perftest';
+ } else {
+ message(`Starting realtime playback [${iterations} iteration(s)]`);
+ mode = 'realtime';
+ }
+
+ const player = new IterationPlayer(iterations, frames, encoding);
+ player.oniterationfinish = function (evt) {
+ message(`Iteration ${evt.number} took ${evt.duration}ms`);
+ };
+ player.onrfbdisconnected = function (evt) {
+ if (evt.reason) {
+ message(`noVNC sent disconnected during iteration ${evt.iteration} frame ${evt.frame}`);
+ }
+ };
+ player.onrfbnotification = function (evt) {
+ document.getElementById('VNC_status').textContent = evt.message;
+ };
+ player.onfinish = function (evt) {
+ const iterTime = parseInt(evt.duration / evt.iterations, 10);
+ message(`${evt.iterations} iterations took ${evt.duration}ms (average ${iterTime}ms / iteration)`);
+
+ document.getElementById('startButton').disabled = false;
+ document.getElementById('startButton').value = "Start";
+ };
+ player.start(mode);
+}
+
+loadFile().then(enableUI).catch(message);
diff --git a/tests/playback.js b/tests/playback.js
index a25fac4..b39c981 100644
--- a/tests/playback.js
+++ b/tests/playback.js
@@ -4,29 +4,17 @@
* Licensed under MPL 2.0 (see LICENSE.txt)
*/
-"use strict";
-/*jslint browser: true, white: false */
-/*global Util, VNC_frame_data, finish */
-
-var rfb, mode, test_state, frame_idx, frame_length,
- iteration, iterations, istart_time, encoding,
-
- // Pre-declarations for jslint
- send_array, next_iteration, end_iteration, queue_next_packet,
- do_packet, enable_test_mode;
-
-// Override send_array
-send_array = function (arr) {
- // Stub out send_array
-};
+import RFB from '../core/rfb.js';
+import * as Log from '../core/util/logging.js';
+import Base64 from '../core/base64.js';
// Immediate polyfill
-if (window.setImmediate === undefined) {
+if (setImmediate === undefined) {
var _immediateIdCounter = 1;
var _immediateFuncs = {};
- window.setImmediate = function (func) {
- var index = Util._immediateIdCounter++;
+ var setImmediate = function (func) {
+ var index = _immediateIdCounter++;
_immediateFuncs[index] = func;
window.postMessage("noVNC immediate trigger:" + index, "*");
return index;
@@ -56,143 +44,160 @@ if (window.setImmediate === undefined) {
window.addEventListener("message", _onMessage);
}
-enable_test_mode = function () {
- rfb._sock.send = send_array;
- rfb._sock.close = function () {};
- rfb._sock.flush = function () {};
- rfb._checkEvents = function () {};
- rfb.connect = function (host, port, password, path) {
- this._rfb_host = host;
- this._rfb_port = port;
- this._rfb_password = (password !== undefined) ? password : "";
- this._rfb_path = (path !== undefined) ? path : "";
- this._sock.init('binary', 'ws');
- this._rfb_connection_state = 'connecting';
- this._rfb_init_state = 'ProtocolVersion';
- };
-};
+export default function RecordingPlayer (frames, encoding, disconnected, notification) {
+ this._frames = frames;
+ this._encoding = encoding;
-next_iteration = function () {
- rfb = new RFB({'target': document.getElementById('VNC_canvas'),
- 'view_only': true,
- 'onDisconnected': disconnected,
- 'onNotification': notification});
- enable_test_mode();
+ this._disconnected = disconnected;
+ this._notification = notification;
- // Missing in older recordings
- if (typeof VNC_frame_encoding === 'undefined') {
- var frame = VNC_frame_data[0];
- var start = frame.indexOf('{', 1) + 1;
+ if (this._encoding === undefined) {
+ let frame = this._frames[0];
+ let start = frame.indexOf('{', 1) + 1;
if (frame.slice(start).startsWith('UkZC')) {
- encoding = 'base64';
+ this._encoding = 'base64';
} else {
- encoding = 'binary';
+ this._encoding = 'binary';
}
- } else {
- encoding = VNC_frame_encoding;
}
- if (iteration === 0) {
- frame_length = VNC_frame_data.length;
- test_state = 'running';
- }
-
- if (test_state !== 'running') { return; }
-
- iteration += 1;
- if (iteration > iterations) {
- finish();
- return;
- }
+ this._rfb = undefined;
+ this._frame_length = this._frames.length;
- frame_idx = 0;
- istart_time = (new Date()).getTime();
- rfb.connect('test', 0, "bogus");
+ this._frame_index = 0;
+ this._start_time = undefined;
+ this._realtime = true;
+ this._trafficManagement = true;
- queue_next_packet();
+ this._running = false;
-};
+ this.onfinish = function () {};
+}
-end_iteration = function () {
- if (rfb._display.pending()) {
- rfb._display.set_onFlush(function () {
- if (rfb._flushing) {
- rfb._onFlush();
- }
- end_iteration();
- });
- rfb._display.flush();
- } else {
- next_iteration();
- }
-};
+RecordingPlayer.prototype = {
+ run: function (realtime, trafficManagement) {
+ // initialize a new RFB
+ this._rfb = new RFB({'target': document.getElementById('VNC_canvas'),
+ 'view_only': true,
+ 'onDisconnected': this._handleDisconnect.bind(this),
+ 'onNotification': this._notification});
+ this._enablePlaybackMode();
+
+ // reset the frame index and timer
+ this._frame_index = 0;
+ this._start_time = (new Date()).getTime();
+
+ this._realtime = realtime;
+ this._trafficManagement = (trafficManagement === undefined) ? !realtime : trafficManagement;
+
+ this._running = true;
+
+ // launch the tests
+ this._rfb.connect('test', 0, 'bogus');
+
+ this._queueNextPacket();
+ },
+
+ // _enablePlaybackMode mocks out things not required for running playback
+ _enablePlaybackMode: function () {
+ this._rfb._sock.send = function (arr) {};
+ this._rfb._sock.close = function () {};
+ this._rfb._sock.flush = function () {};
+ this._rfb._checkEvents = function () {};
+ this._rfb.connect = function (host, port, password, path) {
+ this._rfb_host = host;
+ this._rfb_port = port;
+ this._rfb_password = (password !== undefined) ? password : "";
+ this._rfb_path = (path !== undefined) ? path : "";
+ this._sock.init('binary', 'ws');
+ this._rfb_connection_state = 'connecting';
+ this._rfb_init_state = 'ProtocolVersion';
+ };
+ },
+
+ _queueNextPacket: function () {
+ if (!this._running) { return; }
+
+ var frame = this._frames[this._frame_index];
+
+ // skip send frames
+ while (this._frame_index < this._frame_length && frame.charAt(0) === "}") {
+ this._frame_index++;
+ frame = this._frames[this._frame_index];
+ }
-queue_next_packet = function () {
- var frame, foffset, toffset, delay;
- if (test_state !== 'running') { return; }
+ if (frame === 'EOF') {
+ Log.Debug('Finished, found EOF');
+ this._finish();
+ return;
+ }
- frame = VNC_frame_data[frame_idx];
- while ((frame_idx < frame_length) && (frame.charAt(0) === "}")) {
- //Util.Debug("Send frame " + frame_idx);
- frame_idx += 1;
- frame = VNC_frame_data[frame_idx];
- }
+ if (this._frame_index >= this._frame_length) {
+ Log.Debug('Finished, no more frames');
+ this._finish();
+ return;
+ }
- if (frame === 'EOF') {
- Util.Debug("Finished, found EOF");
- end_iteration();
- return;
- }
- if (frame_idx >= frame_length) {
- Util.Debug("Finished, no more frames");
- end_iteration();
- return;
- }
+ if (this._realtime) {
+ let foffset = frame.slice(1, frame.indexOf('{', 1));
+ let toffset = (new Date()).getTime() - this._start_time;
+ let delay = foffset - toffset;
+ if (delay < 1) delay = 1;
- if (mode === 'realtime') {
- foffset = frame.slice(1, frame.indexOf('{', 1));
- toffset = (new Date()).getTime() - istart_time;
- delay = foffset - toffset;
- if (delay < 1) {
- delay = 1;
+ setTimeout(this._doPacket.bind(this), delay);
+ } else {
+ setImmediate(this._doPacket.bind(this));
+ }
+ },
+
+ _doPacket: function () {
+ // Avoid having excessive queue buildup in non-realtime mode
+ if (!this._trafficManagement && this._rfb._flushing) {
+ let player = this;
+ this._rfb.display.set_onFlush(function () {
+ this._rfb._display.set_onFlush(this._rfb._onFlush.bind(this._rfb));
+ this._rfb._onFlush();
+ player._doPacket();
+ });
+ return;
}
- setTimeout(do_packet, delay);
- } else {
- window.setImmediate(do_packet);
- }
-};
-
-var bytes_processed = 0;
-
-do_packet = function () {
- // Avoid having an excessive queue buildup
- if (rfb._flushing && (mode !== 'realtime')) {
- rfb._display.set_onFlush(function () {
- rfb._display.set_onFlush(rfb._onFlush.bind(rfb));
- rfb._onFlush();
- do_packet();
- });
- return;
- }
+ const frame = this._frames[this._frame_index];
+ var start = frame.indexOf('{', 1) + 1;
+ if (this._encoding === 'base64') {
+ var u8 = Base64.decode(frame.slice(start));
+ start = 0;
+ } else {
+ var u8 = new Uint8Array(frame.length - start);
+ for (let i = 0; i < frame.length - start; i++) {
+ u8[i] = frame.charCodeAt(start + i);
+ }
+ }
- //Util.Debug("Processing frame: " + frame_idx);
- var frame = VNC_frame_data[frame_idx],
- start = frame.indexOf('{', 1) + 1;
- var u8;
- if (encoding === 'base64') {
- u8 = Base64.decode(frame.slice(start));
- start = 0;
- } else {
- u8 = new Uint8Array(frame.length - start);
- for (var i = 0; i < frame.length - start; i++) {
- u8[i] = frame.charCodeAt(start + i);
+ this._rfb._sock._recv_message({'data': u8});
+ this._frame_index++;
+
+ this._queueNextPacket();
+ },
+
+ _finish() {
+ if (this._rfb._display.pending()) {
+ var player = this;
+ this._rfb._display.set_onFlush(function () {
+ if (player._rfb._flushing) {
+ player._rfb._onFlush();
+ }
+ player._finish();
+ });
+ this._rfb._display.flush();
+ } else {
+ this._running = false;
+ this.onfinish((new Date()).getTime() - this._start_time);
}
- }
- bytes_processed += u8.length;
- rfb._sock._recv_message({'data' : u8});
- frame_idx += 1;
+ },
- queue_next_packet();
+ _handleDisconnect(rfb, reason) {
+ this._running = false;
+ this._disconnected(rfb, reason, this._frame_index);
+ }
};
-
diff --git a/tests/vnc_playback.html b/tests/vnc_playback.html
index 65b735e..66f4057 100644
--- a/tests/vnc_playback.html
+++ b/tests/vnc_playback.html
@@ -2,6 +2,8 @@
<html>
<head>
<title>VNC Playback</title>
+ <script src="/vendor/browser-es-module-loader/dist/browser-es-module-loader.js"></script>
+ <script type="module" src="./playback.js"></script>
</head>
<body>
@@ -9,8 +11,7 @@
Perftest:<input type='radio' id='mode1' name='mode' checked>&nbsp;
Realtime:<input type='radio' id='mode2' name='mode'>&nbsp;&nbsp;
- <input id='startButton' type='button' value='Start' style='width:100px'
- onclick="start();" disabled>&nbsp;
+ <input id='startButton' type='button' value='Start' style='width:100px' disabled>&nbsp;
<br><br>
@@ -37,98 +38,5 @@
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
- <script type="text/javascript">
- var INCLUDE_URI= "../";
- </script>
- <script src="../core/util.js"></script>
- <script src="../app/webutil.js"></script>
-
- <script>
- var fname, start_time;
-
- function message(str) {
- console.log(str);
- var cell = document.getElementById('messages');
- cell.textContent += str + "\n";
- cell.scrollTop = cell.scrollHeight;
- }
-
- fname = WebUtil.getQueryVar('data', null);
- if (fname) {
- message("Loading " + fname);
- // Load supporting scripts
- WebUtil.load_scripts({
- 'core': ["base64.js", "websock.js", "des.js", "input/keysym.js",
- "input/keysymdef.js", "input/xtscancodes.js", "input/util.js",
- "input/devices.js", "display.js", "rfb.js", "inflator.js"],
- 'tests': ["playback.js"],
- 'recordings': [fname]});
-
- } else {
- message("Must specify data=FOO in query string.");
- }
-
- disconnected = function (rfb, reason) {
- if (reason) {
- message("noVNC sent '" + state + "' state during iteration " + iteration + " frame " + frame_idx);
- test_state = 'failed';
- }
- }
-
- notification = function (rfb, mesg, level, options) {
- document.getElementById('VNC_status').textContent = mesg;
- }
-
- function start() {
- document.getElementById('startButton').value = "Running";
- document.getElementById('startButton').disabled = true;
-
- iterations = document.getElementById('iterations').value;
- iteration = 0;
- start_time = (new Date()).getTime();
-
- if (document.getElementById('mode1').checked) {
- message("Starting performance playback (fullspeed) [" + iterations + " iteration(s)]");
- mode = 'perftest';
- } else {
- message("Starting realtime playback [" + iterations + " iteration(s)]");
- mode = 'realtime';
- }
-
- //recv_message = rfb.testMode(send_array, VNC_frame_encoding);
-
- next_iteration();
- }
-
- function finish() {
- // Finished with all iterations
- var total_time, end_time = (new Date()).getTime();
- total_time = end_time - start_time;
-
- iter_time = parseInt(total_time / iterations, 10);
- message(iterations + " iterations took " + total_time + "ms, " +
- iter_time + "ms per iteration");
- // Shut-off event interception
- rfb.get_mouse().ungrab();
- rfb.get_keyboard().ungrab();
- document.getElementById('startButton').disabled = false;
- document.getElementById('startButton').value = "Start";
-
- }
-
- window.onscriptsload = function () {
- iterations = WebUtil.getQueryVar('iterations', 3);
- document.getElementById('iterations').value = iterations;
- mode = WebUtil.getQueryVar('mode', 3);
- if (mode === 'realtime') {
- document.getElementById('mode2').checked = true;
- } else {
- document.getElementById('mode1').checked = true;
- }
- if (fname) {
- message("VNC_frame_data.length: " + VNC_frame_data.length);
- }
- document.getElementById('startButton').disabled = false;
- }
- </script>
+ <script type="module" src="./playback-ui.js">
</html>
diff --git a/vendor/browser-es-module-loader/dist/browser-es-module-loader.js b/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
index 8d3a2ee..f191d1a 100644
--- a/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
+++ b/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
@@ -1350,7 +1350,7 @@ WorkerPool.prototype = {
};
var promiseMap = new Map();
-var babelWorker = new WorkerPool('vendor/browser-es-module-loader/dist/babel-worker.js', 3);
+var babelWorker = new WorkerPool('/vendor/browser-es-module-loader/dist/babel-worker.js', 3);
babelWorker.onmessage = function (evt) {
var promFuncs = promiseMap.get(evt.data.key);
promFuncs.resolve(evt.data);
@@ -1391,8 +1391,10 @@ BrowserESModuleLoader.prototype[RegisterLoader$1.instantiate] = function(key, pr
}).then(function (data) {
// evaluate without require, exports and module variables
// we leave module in for now to allow module.require access
- localStorage.setItem(key+'!raw', data.source);
- localStorage.setItem(data.key+'!transpiled', data.code);
+ if (data.key.slice(-8) !== '#nocache') {
+ localStorage.setItem(key+'!raw', data.source);
+ localStorage.setItem(data.key+'!transpiled', data.code);
+ }
(0, eval)(data.code + '\n//# sourceURL=' + data.key + '!transpiled');
processAnonRegister();
});
diff --git a/vendor/browser-es-module-loader/src/browser-es-module-loader.js b/vendor/browser-es-module-loader/src/browser-es-module-loader.js
index 6154e44..4b968eb 100644
--- a/vendor/browser-es-module-loader/src/browser-es-module-loader.js
+++ b/vendor/browser-es-module-loader/src/browser-es-module-loader.js
@@ -190,7 +190,7 @@ WorkerPool.prototype = {
};
var promiseMap = new Map();
-var babelWorker = new WorkerPool('vendor/browser-es-module-loader/dist/babel-worker.js', 3);
+var babelWorker = new WorkerPool('/vendor/browser-es-module-loader/dist/babel-worker.js', 3);
babelWorker.onmessage = function (evt) {
var promFuncs = promiseMap.get(evt.data.key);
promFuncs.resolve(evt.data);
@@ -231,8 +231,10 @@ BrowserESModuleLoader.prototype[RegisterLoader.instantiate] = function(key, proc
}).then(function (data) {
// evaluate without require, exports and module variables
// we leave module in for now to allow module.require access
- localStorage.setItem(key+'!raw', data.source);
- localStorage.setItem(data.key+'!transpiled', data.code);
+ if (data.key.slice(-8) !== '#nocache') {
+ localStorage.setItem(key+'!raw', data.source);
+ localStorage.setItem(data.key+'!transpiled', data.code);
+ }
(0, eval)(data.code + '\n//# sourceURL=' + data.key + '!transpiled');
processAnonRegister();
});