]> git.proxmox.com Git - mirror_novnc.git/blame - tests/playback.js
Use fat arrow functions `const foo = () => { ... };` for callbacks
[mirror_novnc.git] / tests / playback.js
CommitLineData
d595e656
JM
1/*
2 * noVNC: HTML5 VNC client
d58f8b51 3 * Copyright (C) 2012 Joel Martin
1d728ace 4 * Licensed under MPL 2.0 (see LICENSE.txt)
d595e656
JM
5 */
6
d6c17390
SR
7import RFB from '../core/rfb.js';
8import * as Log from '../core/util/logging.js';
9import Base64 from '../core/base64.js';
b8bd88d0 10
e12e2759 11// Immediate polyfill
2b5f94fa
JD
12if (window.setImmediate === undefined) {
13 let _immediateIdCounter = 1;
14 const _immediateFuncs = {};
e12e2759 15
651c23ec 16 window.setImmediate = (func) => {
2b5f94fa 17 const index = _immediateIdCounter++;
e12e2759
PO
18 _immediateFuncs[index] = func;
19 window.postMessage("noVNC immediate trigger:" + index, "*");
20 return index;
21 };
22
651c23ec 23 window.clearImmediate = (id) => {
e12e2759
PO
24 _immediateFuncs[id];
25 };
26
651c23ec 27 const _onMessage = (event) => {
e12e2759
PO
28 if ((typeof event.data !== "string") ||
29 (event.data.indexOf("noVNC immediate trigger:") !== 0)) {
30 return;
31 }
32
2b5f94fa 33 const index = event.data.slice("noVNC immediate trigger:".length);
e12e2759 34
2b5f94fa 35 const callback = _immediateFuncs[index];
e12e2759
PO
36 if (callback === undefined) {
37 return;
38 }
39
40 delete _immediateFuncs[index];
41
42 callback();
43 };
44 window.addEventListener("message", _onMessage);
45}
46
0e4808bf
JD
47export default class RecordingPlayer {
48 constructor(frames, encoding, disconnected) {
49 this._frames = frames;
50 this._encoding = encoding;
efed2eea 51
0e4808bf 52 this._disconnected = disconnected;
efed2eea 53
0e4808bf 54 if (this._encoding === undefined) {
2b5f94fa
JD
55 const frame = this._frames[0];
56 const start = frame.indexOf('{', 1) + 1;
0e4808bf
JD
57 if (frame.slice(start).startsWith('UkZC')) {
58 this._encoding = 'base64';
59 } else {
60 this._encoding = 'binary';
61 }
d951b409 62 }
d951b409 63
0e4808bf
JD
64 this._rfb = undefined;
65 this._frame_length = this._frames.length;
b8bd88d0 66
0e4808bf
JD
67 this._frame_index = 0;
68 this._start_time = undefined;
69 this._realtime = true;
70 this._trafficManagement = true;
b8bd88d0 71
0e4808bf 72 this._running = false;
b8bd88d0 73
651c23ec 74 this.onfinish = () => {};
0e4808bf 75 }
b8bd88d0 76
0e4808bf 77 run(realtime, trafficManagement) {
d6c17390 78 // initialize a new RFB
a92c3317 79 this._rfb = new RFB(document.getElementById('VNC_screen'), 'wss://test');
747b4623 80 this._rfb.viewOnly = true;
d472f3f1
SM
81 this._rfb.addEventListener("disconnect",
82 this._handleDisconnect.bind(this));
d6c17390
SR
83 this._enablePlaybackMode();
84
85 // reset the frame index and timer
86 this._frame_index = 0;
87 this._start_time = (new Date()).getTime();
88
89 this._realtime = realtime;
90 this._trafficManagement = (trafficManagement === undefined) ? !realtime : trafficManagement;
91
92 this._running = true;
93
d6c17390 94 this._queueNextPacket();
0e4808bf 95 }
d6c17390
SR
96
97 // _enablePlaybackMode mocks out things not required for running playback
0e4808bf 98 _enablePlaybackMode() {
651c23ec
JD
99 this._rfb._sock.send = () => {};
100 this._rfb._sock.close = () => {};
101 this._rfb._sock.flush = () => {};
a92c3317
PO
102 this._rfb._sock.open = function () {
103 this.init();
104 this._eventHandlers.open();
d6c17390 105 };
0e4808bf 106 }
d6c17390 107
0e4808bf 108 _queueNextPacket() {
d6c17390
SR
109 if (!this._running) { return; }
110
2b5f94fa 111 let frame = this._frames[this._frame_index];
d6c17390
SR
112
113 // skip send frames
114 while (this._frame_index < this._frame_length && frame.charAt(0) === "}") {
115 this._frame_index++;
116 frame = this._frames[this._frame_index];
117 }
18e96092 118
d6c17390
SR
119 if (frame === 'EOF') {
120 Log.Debug('Finished, found EOF');
121 this._finish();
122 return;
123 }
b8bd88d0 124
d6c17390
SR
125 if (this._frame_index >= this._frame_length) {
126 Log.Debug('Finished, no more frames');
127 this._finish();
128 return;
129 }
b8bd88d0 130
d6c17390 131 if (this._realtime) {
2b5f94fa
JD
132 const foffset = frame.slice(1, frame.indexOf('{', 1));
133 const toffset = (new Date()).getTime() - this._start_time;
d6c17390
SR
134 let delay = foffset - toffset;
135 if (delay < 1) delay = 1;
b8bd88d0 136
d6c17390
SR
137 setTimeout(this._doPacket.bind(this), delay);
138 } else {
139 setImmediate(this._doPacket.bind(this));
140 }
0e4808bf 141 }
d6c17390 142
0e4808bf 143 _doPacket() {
d6c17390 144 // Avoid having excessive queue buildup in non-realtime mode
255fbe0c 145 if (this._trafficManagement && this._rfb._flushing) {
2b5f94fa 146 const orig = this._rfb._display.onflush;
651c23ec
JD
147 this._rfb._display.onflush = () => {
148 this._rfb._display.onflush = orig;
149 this._rfb._onFlush();
150 this._doPacket();
747b4623 151 };
d6c17390 152 return;
b8bd88d0
JM
153 }
154
d6c17390 155 const frame = this._frames[this._frame_index];
2b5f94fa
JD
156 let start = frame.indexOf('{', 1) + 1;
157 let u8;
d6c17390 158 if (this._encoding === 'base64') {
8727f598 159 u8 = Base64.decode(frame.slice(start));
d6c17390
SR
160 start = 0;
161 } else {
8727f598 162 u8 = new Uint8Array(frame.length - start);
d6c17390
SR
163 for (let i = 0; i < frame.length - start; i++) {
164 u8[i] = frame.charCodeAt(start + i);
165 }
166 }
18e96092 167
d6c17390
SR
168 this._rfb._sock._recv_message({'data': u8});
169 this._frame_index++;
170
171 this._queueNextPacket();
0e4808bf 172 }
d6c17390
SR
173
174 _finish() {
175 if (this._rfb._display.pending()) {
651c23ec
JD
176 this._rfb._display.onflush = () => {
177 if (this._rfb._flushing) {
178 this._rfb._onFlush();
d6c17390 179 }
651c23ec 180 this._finish();
747b4623 181 };
d6c17390
SR
182 this._rfb._display.flush();
183 } else {
184 this._running = false;
609a3fac
PO
185 this._rfb._sock._eventHandlers.close({code: 1000, reason: ""});
186 delete this._rfb;
d6c17390 187 this.onfinish((new Date()).getTime() - this._start_time);
e7e66602 188 }
0e4808bf 189 }
b8bd88d0 190
a92c3317 191 _handleDisconnect(evt) {
d6c17390 192 this._running = false;
a92c3317 193 this._disconnected(evt.detail.clean, this._frame_index);
d6c17390 194 }
0e4808bf 195}