]>
Commit | Line | Data |
---|---|---|
d595e656 JM |
1 | /* |
2 | * noVNC: HTML5 VNC client | |
84586c0f | 3 | * Copyright (C) 2018 The noVNC Authors |
1d728ace | 4 | * Licensed under MPL 2.0 (see LICENSE.txt) |
d595e656 JM |
5 | */ |
6 | ||
d6c17390 SR |
7 | import RFB from '../core/rfb.js'; |
8 | import * as Log from '../core/util/logging.js'; | |
b8bd88d0 | 9 | |
e12e2759 | 10 | // Immediate polyfill |
2b5f94fa JD |
11 | if (window.setImmediate === undefined) { |
12 | let _immediateIdCounter = 1; | |
13 | const _immediateFuncs = {}; | |
e12e2759 | 14 | |
651c23ec | 15 | window.setImmediate = (func) => { |
2b5f94fa | 16 | const index = _immediateIdCounter++; |
e12e2759 PO |
17 | _immediateFuncs[index] = func; |
18 | window.postMessage("noVNC immediate trigger:" + index, "*"); | |
19 | return index; | |
20 | }; | |
21 | ||
651c23ec | 22 | window.clearImmediate = (id) => { |
e12e2759 PO |
23 | _immediateFuncs[id]; |
24 | }; | |
25 | ||
885363a3 | 26 | window.addEventListener("message", (event) => { |
e12e2759 PO |
27 | if ((typeof event.data !== "string") || |
28 | (event.data.indexOf("noVNC immediate trigger:") !== 0)) { | |
29 | return; | |
30 | } | |
31 | ||
2b5f94fa | 32 | const index = event.data.slice("noVNC immediate trigger:".length); |
e12e2759 | 33 | |
2b5f94fa | 34 | const callback = _immediateFuncs[index]; |
e12e2759 PO |
35 | if (callback === undefined) { |
36 | return; | |
37 | } | |
38 | ||
39 | delete _immediateFuncs[index]; | |
40 | ||
41 | callback(); | |
885363a3 | 42 | }); |
e12e2759 PO |
43 | } |
44 | ||
0e4808bf | 45 | export default class RecordingPlayer { |
527a1fd0 | 46 | constructor(frames, disconnected) { |
0e4808bf | 47 | this._frames = frames; |
efed2eea | 48 | |
0e4808bf | 49 | this._disconnected = disconnected; |
efed2eea | 50 | |
0e4808bf | 51 | this._rfb = undefined; |
95632e41 | 52 | this._frameLength = this._frames.length; |
b8bd88d0 | 53 | |
95632e41 SM |
54 | this._frameIndex = 0; |
55 | this._startTime = undefined; | |
0e4808bf JD |
56 | this._realtime = true; |
57 | this._trafficManagement = true; | |
b8bd88d0 | 58 | |
0e4808bf | 59 | this._running = false; |
b8bd88d0 | 60 | |
651c23ec | 61 | this.onfinish = () => {}; |
0e4808bf | 62 | } |
b8bd88d0 | 63 | |
0e4808bf | 64 | run(realtime, trafficManagement) { |
d6c17390 | 65 | // initialize a new RFB |
a92c3317 | 66 | this._rfb = new RFB(document.getElementById('VNC_screen'), 'wss://test'); |
747b4623 | 67 | this._rfb.viewOnly = true; |
d472f3f1 SM |
68 | this._rfb.addEventListener("disconnect", |
69 | this._handleDisconnect.bind(this)); | |
16f08615 PO |
70 | this._rfb.addEventListener("credentialsrequired", |
71 | this._handleCredentials.bind(this)); | |
d6c17390 SR |
72 | this._enablePlaybackMode(); |
73 | ||
74 | // reset the frame index and timer | |
95632e41 SM |
75 | this._frameIndex = 0; |
76 | this._startTime = (new Date()).getTime(); | |
d6c17390 SR |
77 | |
78 | this._realtime = realtime; | |
79 | this._trafficManagement = (trafficManagement === undefined) ? !realtime : trafficManagement; | |
80 | ||
81 | this._running = true; | |
0e4808bf | 82 | } |
d6c17390 SR |
83 | |
84 | // _enablePlaybackMode mocks out things not required for running playback | |
0e4808bf | 85 | _enablePlaybackMode() { |
cccf3b00 | 86 | const self = this; |
651c23ec JD |
87 | this._rfb._sock.send = () => {}; |
88 | this._rfb._sock.close = () => {}; | |
89 | this._rfb._sock.flush = () => {}; | |
a92c3317 PO |
90 | this._rfb._sock.open = function () { |
91 | this.init(); | |
92 | this._eventHandlers.open(); | |
cccf3b00 | 93 | self._queueNextPacket(); |
d6c17390 | 94 | }; |
0e4808bf | 95 | } |
d6c17390 | 96 | |
0e4808bf | 97 | _queueNextPacket() { |
d6c17390 SR |
98 | if (!this._running) { return; } |
99 | ||
95632e41 | 100 | let frame = this._frames[this._frameIndex]; |
d6c17390 SR |
101 | |
102 | // skip send frames | |
95632e41 SM |
103 | while (this._frameIndex < this._frameLength && frame.fromClient) { |
104 | this._frameIndex++; | |
105 | frame = this._frames[this._frameIndex]; | |
d6c17390 | 106 | } |
18e96092 | 107 | |
95632e41 | 108 | if (this._frameIndex >= this._frameLength) { |
d6c17390 SR |
109 | Log.Debug('Finished, no more frames'); |
110 | this._finish(); | |
111 | return; | |
112 | } | |
b8bd88d0 | 113 | |
d6c17390 | 114 | if (this._realtime) { |
95632e41 | 115 | const toffset = (new Date()).getTime() - this._startTime; |
527a1fd0 | 116 | let delay = frame.timestamp - toffset; |
d6c17390 | 117 | if (delay < 1) delay = 1; |
b8bd88d0 | 118 | |
d6c17390 SR |
119 | setTimeout(this._doPacket.bind(this), delay); |
120 | } else { | |
121 | setImmediate(this._doPacket.bind(this)); | |
122 | } | |
0e4808bf | 123 | } |
d6c17390 | 124 | |
0e4808bf | 125 | _doPacket() { |
d6c17390 | 126 | // Avoid having excessive queue buildup in non-realtime mode |
255fbe0c | 127 | if (this._trafficManagement && this._rfb._flushing) { |
2b5f94fa | 128 | const orig = this._rfb._display.onflush; |
651c23ec JD |
129 | this._rfb._display.onflush = () => { |
130 | this._rfb._display.onflush = orig; | |
131 | this._rfb._onFlush(); | |
132 | this._doPacket(); | |
747b4623 | 133 | }; |
d6c17390 | 134 | return; |
b8bd88d0 JM |
135 | } |
136 | ||
95632e41 | 137 | const frame = this._frames[this._frameIndex]; |
18e96092 | 138 | |
7ce1b071 | 139 | this._rfb._sock._recvMessage({'data': frame.data}); |
95632e41 | 140 | this._frameIndex++; |
d6c17390 SR |
141 | |
142 | this._queueNextPacket(); | |
0e4808bf | 143 | } |
d6c17390 SR |
144 | |
145 | _finish() { | |
146 | if (this._rfb._display.pending()) { | |
651c23ec JD |
147 | this._rfb._display.onflush = () => { |
148 | if (this._rfb._flushing) { | |
149 | this._rfb._onFlush(); | |
d6c17390 | 150 | } |
651c23ec | 151 | this._finish(); |
747b4623 | 152 | }; |
d6c17390 SR |
153 | this._rfb._display.flush(); |
154 | } else { | |
155 | this._running = false; | |
609a3fac PO |
156 | this._rfb._sock._eventHandlers.close({code: 1000, reason: ""}); |
157 | delete this._rfb; | |
95632e41 | 158 | this.onfinish((new Date()).getTime() - this._startTime); |
e7e66602 | 159 | } |
0e4808bf | 160 | } |
b8bd88d0 | 161 | |
a92c3317 | 162 | _handleDisconnect(evt) { |
d6c17390 | 163 | this._running = false; |
95632e41 | 164 | this._disconnected(evt.detail.clean, this._frameIndex); |
d6c17390 | 165 | } |
16f08615 PO |
166 | |
167 | _handleCredentials(evt) { | |
168 | this._rfb.sendCredentials({"username": "Foo", | |
169 | "password": "Bar", | |
170 | "target": "Baz"}); | |
171 | } | |
0e4808bf | 172 | } |