mirror of
https://git.proxmox.com/git/mirror_novnc
synced 2025-04-29 04:21:33 +00:00

Try to be more consistent in how we capitalize things. Both the "Title Case" and "Sentence case" styles are popular, so either would work. Google and Mozilla both prefer "Sentence case", so let's follow them.
172 lines
4.5 KiB
JavaScript
172 lines
4.5 KiB
JavaScript
/*
|
|
* noVNC: HTML5 VNC client
|
|
* Copyright (C) 2018 The noVNC authors
|
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
|
*/
|
|
|
|
import RFB from '../core/rfb.js';
|
|
import * as Log from '../core/util/logging.js';
|
|
|
|
// Immediate polyfill
|
|
if (window.setImmediate === undefined) {
|
|
let _immediateIdCounter = 1;
|
|
const _immediateFuncs = {};
|
|
|
|
window.setImmediate = (func) => {
|
|
const index = _immediateIdCounter++;
|
|
_immediateFuncs[index] = func;
|
|
window.postMessage("noVNC immediate trigger:" + index, "*");
|
|
return index;
|
|
};
|
|
|
|
window.clearImmediate = (id) => {
|
|
_immediateFuncs[id];
|
|
};
|
|
|
|
window.addEventListener("message", (event) => {
|
|
if ((typeof event.data !== "string") ||
|
|
(event.data.indexOf("noVNC immediate trigger:") !== 0)) {
|
|
return;
|
|
}
|
|
|
|
const index = event.data.slice("noVNC immediate trigger:".length);
|
|
|
|
const callback = _immediateFuncs[index];
|
|
if (callback === undefined) {
|
|
return;
|
|
}
|
|
|
|
delete _immediateFuncs[index];
|
|
|
|
callback();
|
|
});
|
|
}
|
|
|
|
class FakeWebSocket {
|
|
constructor() {
|
|
this.binaryType = "arraybuffer";
|
|
this.protocol = "";
|
|
this.readyState = "open";
|
|
|
|
this.onerror = () => {};
|
|
this.onmessage = () => {};
|
|
this.onopen = () => {};
|
|
}
|
|
|
|
send() {
|
|
}
|
|
|
|
close() {
|
|
}
|
|
}
|
|
|
|
export default class RecordingPlayer {
|
|
constructor(frames, disconnected) {
|
|
this._frames = frames;
|
|
|
|
this._disconnected = disconnected;
|
|
|
|
this._rfb = undefined;
|
|
this._frameLength = this._frames.length;
|
|
|
|
this._frameIndex = 0;
|
|
this._startTime = undefined;
|
|
this._realtime = true;
|
|
this._trafficManagement = true;
|
|
|
|
this._running = false;
|
|
|
|
this.onfinish = () => {};
|
|
}
|
|
|
|
run(realtime, trafficManagement) {
|
|
// initialize a new RFB
|
|
this._ws = new FakeWebSocket();
|
|
this._rfb = new RFB(document.getElementById('VNC_screen'), this._ws);
|
|
this._rfb.viewOnly = true;
|
|
this._rfb.addEventListener("disconnect",
|
|
this._handleDisconnect.bind(this));
|
|
this._rfb.addEventListener("credentialsrequired",
|
|
this._handleCredentials.bind(this));
|
|
|
|
// reset the frame index and timer
|
|
this._frameIndex = 0;
|
|
this._startTime = (new Date()).getTime();
|
|
|
|
this._realtime = realtime;
|
|
this._trafficManagement = (trafficManagement === undefined) ? !realtime : trafficManagement;
|
|
|
|
this._running = true;
|
|
this._queueNextPacket();
|
|
}
|
|
|
|
_queueNextPacket() {
|
|
if (!this._running) { return; }
|
|
|
|
let frame = this._frames[this._frameIndex];
|
|
|
|
// skip send frames
|
|
while (this._frameIndex < this._frameLength && frame.fromClient) {
|
|
this._frameIndex++;
|
|
frame = this._frames[this._frameIndex];
|
|
}
|
|
|
|
if (this._frameIndex >= this._frameLength) {
|
|
Log.Debug('Finished, no more frames');
|
|
this._finish();
|
|
return;
|
|
}
|
|
|
|
if (this._realtime) {
|
|
const toffset = (new Date()).getTime() - this._startTime;
|
|
let delay = frame.timestamp - toffset;
|
|
if (delay < 1) delay = 1;
|
|
|
|
setTimeout(this._doPacket.bind(this), delay);
|
|
} else {
|
|
setImmediate(this._doPacket.bind(this));
|
|
}
|
|
}
|
|
|
|
_doPacket() {
|
|
// Avoid having excessive queue buildup in non-realtime mode
|
|
if (this._trafficManagement && this._rfb._flushing) {
|
|
this._rfb.flush()
|
|
.then(() => {
|
|
this._doPacket();
|
|
});
|
|
return;
|
|
}
|
|
|
|
const frame = this._frames[this._frameIndex];
|
|
|
|
this._ws.onmessage({'data': frame.data});
|
|
this._frameIndex++;
|
|
|
|
this._queueNextPacket();
|
|
}
|
|
|
|
_finish() {
|
|
if (this._rfb._display.pending()) {
|
|
this._rfb._display.flush()
|
|
.then(() => { this._finish(); });
|
|
} else {
|
|
this._running = false;
|
|
this._ws.onclose({code: 1000, reason: ""});
|
|
delete this._rfb;
|
|
this.onfinish((new Date()).getTime() - this._startTime);
|
|
}
|
|
}
|
|
|
|
_handleDisconnect(evt) {
|
|
this._running = false;
|
|
this._disconnected(evt.detail.clean, this._frameIndex);
|
|
}
|
|
|
|
_handleCredentials(evt) {
|
|
this._rfb.sendCredentials({"username": "Foo",
|
|
"password": "Bar",
|
|
"target": "Baz"});
|
|
}
|
|
}
|