JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1"use strict";23Object.defineProperty(exports, "__esModule", {4 value: true5});6exports["default"] = void 0;7var Log = _interopRequireWildcard(require("./util/logging.js"));8function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }9function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }10function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }11function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }12function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }13function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }14function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }15function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }16function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }17function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }18function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }19function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }20function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }21function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*22 * Websock: high-performance buffering wrapper23 * Copyright (C) 2019 The noVNC authors24 * Licensed under MPL 2.0 (see LICENSE.txt)25 *26 * Websock is similar to the standard WebSocket / RTCDataChannel object27 * but with extra buffer handling.28 *29 * Websock has built-in receive queue buffering; the message event30 * does not contain actual data but is simply a notification that31 * there is new data available. Several rQ* methods are available to32 * read binary data off of the receive queue.33 */34// this has performance issues in some versions Chromium, and35// doesn't gain a tremendous amount of performance increase in Firefox36// at the moment. It may be valuable to turn it on in the future.37var MAX_RQ_GROW_SIZE = 40 * 1024 * 1024; // 40 MiB3839// Constants pulled from RTCDataChannelState enum40// https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/readyState#RTCDataChannelState_enum41var DataChannel = {42 CONNECTING: "connecting",43 OPEN: "open",44 CLOSING: "closing",45 CLOSED: "closed"46};47var ReadyStates = {48 CONNECTING: [WebSocket.CONNECTING, DataChannel.CONNECTING],49 OPEN: [WebSocket.OPEN, DataChannel.OPEN],50 CLOSING: [WebSocket.CLOSING, DataChannel.CLOSING],51 CLOSED: [WebSocket.CLOSED, DataChannel.CLOSED]52};5354// Properties a raw channel must have, WebSocket and RTCDataChannel are two examples55var rawChannelProps = ["send", "close", "binaryType", "onerror", "onmessage", "onopen", "protocol", "readyState"];56var Websock = exports["default"] = /*#__PURE__*/function () {57 function Websock() {58 _classCallCheck(this, Websock);59 this._websocket = null; // WebSocket or RTCDataChannel object6061 this._rQi = 0; // Receive queue index62 this._rQlen = 0; // Next write position in the receive queue63 this._rQbufferSize = 1024 * 1024 * 4; // Receive queue buffer size (4 MiB)64 // called in init: this._rQ = new Uint8Array(this._rQbufferSize);65 this._rQ = null; // Receive queue6667 this._sQbufferSize = 1024 * 10; // 10 KiB68 // called in init: this._sQ = new Uint8Array(this._sQbufferSize);69 this._sQlen = 0;70 this._sQ = null; // Send queue7172 this._eventHandlers = {73 message: function message() {},74 open: function open() {},75 close: function close() {},76 error: function error() {}77 };78 }7980 // Getters and setters81 return _createClass(Websock, [{82 key: "readyState",83 get: function get() {84 var subState;85 if (this._websocket === null) {86 return "unused";87 }88 subState = this._websocket.readyState;89 if (ReadyStates.CONNECTING.includes(subState)) {90 return "connecting";91 } else if (ReadyStates.OPEN.includes(subState)) {92 return "open";93 } else if (ReadyStates.CLOSING.includes(subState)) {94 return "closing";95 } else if (ReadyStates.CLOSED.includes(subState)) {96 return "closed";97 }98 return "unknown";99 }100101 // Receive queue102 }, {103 key: "rQpeek8",104 value: function rQpeek8() {105 return this._rQ[this._rQi];106 }107 }, {108 key: "rQskipBytes",109 value: function rQskipBytes(bytes) {110 this._rQi += bytes;111 }112 }, {113 key: "rQshift8",114 value: function rQshift8() {115 return this._rQshift(1);116 }117 }, {118 key: "rQshift16",119 value: function rQshift16() {120 return this._rQshift(2);121 }122 }, {123 key: "rQshift32",124 value: function rQshift32() {125 return this._rQshift(4);126 }127128 // TODO(directxman12): test performance with these vs a DataView129 }, {130 key: "_rQshift",131 value: function _rQshift(bytes) {132 var res = 0;133 for (var _byte = bytes - 1; _byte >= 0; _byte--) {134 res += this._rQ[this._rQi++] << _byte * 8;135 }136 return res >>> 0;137 }138 }, {139 key: "rQshiftStr",140 value: function rQshiftStr(len) {141 var str = "";142 // Handle large arrays in steps to avoid long strings on the stack143 for (var i = 0; i < len; i += 4096) {144 var part = this.rQshiftBytes(Math.min(4096, len - i), false);145 str += String.fromCharCode.apply(null, part);146 }147 return str;148 }149 }, {150 key: "rQshiftBytes",151 value: function rQshiftBytes(len) {152 var copy = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;153 this._rQi += len;154 if (copy) {155 return this._rQ.slice(this._rQi - len, this._rQi);156 } else {157 return this._rQ.subarray(this._rQi - len, this._rQi);158 }159 }160 }, {161 key: "rQshiftTo",162 value: function rQshiftTo(target, len) {163 // TODO: make this just use set with views when using a ArrayBuffer to store the rQ164 target.set(new Uint8Array(this._rQ.buffer, this._rQi, len));165 this._rQi += len;166 }167 }, {168 key: "rQpeekBytes",169 value: function rQpeekBytes(len) {170 var copy = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;171 if (copy) {172 return this._rQ.slice(this._rQi, this._rQi + len);173 } else {174 return this._rQ.subarray(this._rQi, this._rQi + len);175 }176 }177178 // Check to see if we must wait for 'num' bytes (default to FBU.bytes)179 // to be available in the receive queue. Return true if we need to180 // wait (and possibly print a debug message), otherwise false.181 }, {182 key: "rQwait",183 value: function rQwait(msg, num, goback) {184 if (this._rQlen - this._rQi < num) {185 if (goback) {186 if (this._rQi < goback) {187 throw new Error("rQwait cannot backup " + goback + " bytes");188 }189 this._rQi -= goback;190 }191 return true; // true means need more data192 }193 return false;194 }195196 // Send queue197 }, {198 key: "sQpush8",199 value: function sQpush8(num) {200 this._sQensureSpace(1);201 this._sQ[this._sQlen++] = num;202 }203 }, {204 key: "sQpush16",205 value: function sQpush16(num) {206 this._sQensureSpace(2);207 this._sQ[this._sQlen++] = num >> 8 & 0xff;208 this._sQ[this._sQlen++] = num >> 0 & 0xff;209 }210 }, {211 key: "sQpush32",212 value: function sQpush32(num) {213 this._sQensureSpace(4);214 this._sQ[this._sQlen++] = num >> 24 & 0xff;215 this._sQ[this._sQlen++] = num >> 16 & 0xff;216 this._sQ[this._sQlen++] = num >> 8 & 0xff;217 this._sQ[this._sQlen++] = num >> 0 & 0xff;218 }219 }, {220 key: "sQpushString",221 value: function sQpushString(str) {222 var bytes = str.split('').map(function (chr) {223 return chr.charCodeAt(0);224 });225 this.sQpushBytes(new Uint8Array(bytes));226 }227 }, {228 key: "sQpushBytes",229 value: function sQpushBytes(bytes) {230 for (var offset = 0; offset < bytes.length;) {231 this._sQensureSpace(1);232 var chunkSize = this._sQbufferSize - this._sQlen;233 if (chunkSize > bytes.length - offset) {234 chunkSize = bytes.length - offset;235 }236 this._sQ.set(bytes.subarray(offset, offset + chunkSize), this._sQlen);237 this._sQlen += chunkSize;238 offset += chunkSize;239 }240 }241 }, {242 key: "flush",243 value: function flush() {244 if (this._sQlen > 0 && this.readyState === 'open') {245 this._websocket.send(new Uint8Array(this._sQ.buffer, 0, this._sQlen));246 this._sQlen = 0;247 }248 }249 }, {250 key: "_sQensureSpace",251 value: function _sQensureSpace(bytes) {252 if (this._sQbufferSize - this._sQlen < bytes) {253 this.flush();254 }255 }256257 // Event handlers258 }, {259 key: "off",260 value: function off(evt) {261 this._eventHandlers[evt] = function () {};262 }263 }, {264 key: "on",265 value: function on(evt, handler) {266 this._eventHandlers[evt] = handler;267 }268 }, {269 key: "_allocateBuffers",270 value: function _allocateBuffers() {271 this._rQ = new Uint8Array(this._rQbufferSize);272 this._sQ = new Uint8Array(this._sQbufferSize);273 }274 }, {275 key: "init",276 value: function init() {277 this._allocateBuffers();278 this._rQi = 0;279 this._websocket = null;280 }281 }, {282 key: "open",283 value: function open(uri, protocols) {284 this.attach(new WebSocket(uri, protocols));285 }286 }, {287 key: "attach",288 value: function attach(rawChannel) {289 var _this = this;290 this.init();291292 // Must get object and class methods to be compatible with the tests.293 var channelProps = [].concat(_toConsumableArray(Object.keys(rawChannel)), _toConsumableArray(Object.getOwnPropertyNames(Object.getPrototypeOf(rawChannel))));294 for (var i = 0; i < rawChannelProps.length; i++) {295 var prop = rawChannelProps[i];296 if (channelProps.indexOf(prop) < 0) {297 throw new Error('Raw channel missing property: ' + prop);298 }299 }300 this._websocket = rawChannel;301 this._websocket.binaryType = "arraybuffer";302 this._websocket.onmessage = this._recvMessage.bind(this);303 this._websocket.onopen = function () {304 Log.Debug('>> WebSock.onopen');305 if (_this._websocket.protocol) {306 Log.Info("Server choose sub-protocol: " + _this._websocket.protocol);307 }308 _this._eventHandlers.open();309 Log.Debug("<< WebSock.onopen");310 };311 this._websocket.onclose = function (e) {312 Log.Debug(">> WebSock.onclose");313 _this._eventHandlers.close(e);314 Log.Debug("<< WebSock.onclose");315 };316 this._websocket.onerror = function (e) {317 Log.Debug(">> WebSock.onerror: " + e);318 _this._eventHandlers.error(e);319 Log.Debug("<< WebSock.onerror: " + e);320 };321 }322 }, {323 key: "close",324 value: function close() {325 if (this._websocket) {326 if (this.readyState === 'connecting' || this.readyState === 'open') {327 Log.Info("Closing WebSocket connection");328 this._websocket.close();329 }330 this._websocket.onmessage = function () {};331 }332 }333334 // private methods335336 // We want to move all the unread data to the start of the queue,337 // e.g. compacting.338 // The function also expands the receive que if needed, and for339 // performance reasons we combine these two actions to avoid340 // unnecessary copying.341 }, {342 key: "_expandCompactRQ",343 value: function _expandCompactRQ(minFit) {344 // if we're using less than 1/8th of the buffer even with the incoming bytes, compact in place345 // instead of resizing346 var requiredBufferSize = (this._rQlen - this._rQi + minFit) * 8;347 var resizeNeeded = this._rQbufferSize < requiredBufferSize;348 if (resizeNeeded) {349 // Make sure we always *at least* double the buffer size, and have at least space for 8x350 // the current amount of data351 this._rQbufferSize = Math.max(this._rQbufferSize * 2, requiredBufferSize);352 }353354 // we don't want to grow unboundedly355 if (this._rQbufferSize > MAX_RQ_GROW_SIZE) {356 this._rQbufferSize = MAX_RQ_GROW_SIZE;357 if (this._rQbufferSize - (this._rQlen - this._rQi) < minFit) {358 throw new Error("Receive queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit");359 }360 }361 if (resizeNeeded) {362 var oldRQbuffer = this._rQ.buffer;363 this._rQ = new Uint8Array(this._rQbufferSize);364 this._rQ.set(new Uint8Array(oldRQbuffer, this._rQi, this._rQlen - this._rQi));365 } else {366 this._rQ.copyWithin(0, this._rQi, this._rQlen);367 }368 this._rQlen = this._rQlen - this._rQi;369 this._rQi = 0;370 }371372 // push arraybuffer values onto the end of the receive que373 }, {374 key: "_recvMessage",375 value: function _recvMessage(e) {376 if (this._rQlen == this._rQi) {377 // All data has now been processed, this means we378 // can reset the receive queue.379 this._rQlen = 0;380 this._rQi = 0;381 }382 var u8 = new Uint8Array(e.data);383 if (u8.length > this._rQbufferSize - this._rQlen) {384 this._expandCompactRQ(u8.length);385 }386 this._rQ.set(u8, this._rQlen);387 this._rQlen += u8.length;388 if (this._rQlen - this._rQi > 0) {389 this._eventHandlers.message();390 } else {391 Log.Debug("Ignoring empty message");392 }393 }394 }]);395}();