UNPKG

@zoom/probesdk

Version:

Zoom ProbeSDK tests the end user device and network capabilities, and the Zoom server connection.

1,322 lines (1,297 loc) 219 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var uaParserJs = require('ua-parser-js'); function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } function _classPrivateFieldGet2(s, a) { return s.get(_assertClassBrand(s, a)); } function _classPrivateFieldSet2(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; } function _regeneratorRuntime() { _regeneratorRuntime = function () { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function (t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == typeof h && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function (t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(typeof e + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function (e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function () { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function (e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function (t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function (t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function (t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function (t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function (e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; } function _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); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _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); } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _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."); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function () {}; return { s: F, n: function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (e) { throw e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function () { it = it.call(o); }, n: function () { var step = it.next(); normalCompletion = step.done; return step; }, e: function (e) { didErr = true; err = e; }, f: function () { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } /** * Enumeration of a collection of customized error codes defined and used by ProberSDK. * @enum {number} * @property {number} OK Indicates a successful operation. Default value is 0. * @property {number} INVALID_ARGS Indicates invalid arguments passed to a function. Default value is -1. * @property {number} API_NOT_SUPPORTED Indicates that a specific API is not supported. Default value is -2. * @constant */ var ERR_CODE = { OK: 0, INVALID_ARGS: -1, API_NOT_SUPPORTED: -2 }; /** * Enumeration of the rendering types supported by ProbeSDK. * * @enum {number} * @property {number} VIDEO_TAG a video stream will be rendered on the {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video|video} tag. Default value is 1. * @property {number} WEBGL a video stream will be rendered on a canvas with a {@link https://developer.mozilla.org/en-US/docs/Glossary/WebGL|WebGL} renderer. Default value is 2. * @property {number} WEBGL_2 a video stream will be rendered on a canvas with a {@link https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API#webgl_2|WebGL2} renderer. Default value is 3. * @property {number} WEBGPU a video stream will be rendered on a canvas with a {@link https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API|WebGPU} renderer. Default value is 4. * @constant */ var RENDERER_TYPE = { VIDEO_TAG: 1, WEBGL: 2, WEBGL_2: 3, WEBGPU: 4 }; /** * Enumeration of the data type of the network diagnostic. * It will be used to determine the type of data you received and how to handle them. * * @enum {number} * @property {number} STATS indicates the realtime statistics of the network diagnostic. Default value is 1. * @property {number} REPORT indicates the final report of diagnostic, basic information and supported features. Default value is 2. * @constant */ var NET_PROBING_DATA_TYPE = { STATS: 1, REPORT: 2 }; /** * Enumeration of the protocol type that ProbeSDK checks in a network diagnostic. * * @enum {number} * @property {number} HTTPS https(https://) protocol. Default value is 1. * @property {number} WEB_SOCKET WebSocket(wss:// ws://) protocol. Default value is 2. * @property {number} DATA_CHANNEL the data channel which is used for media communication. Default value is 3. * @property {number} WEB_TRANSPORT WebTransport protocol(not supported now). Default value is 4. * @constant */ var PROTOCOL_TYPE = { HTTPS: 1, WEB_SOCKET: 2, DATA_CHANNEL: 3, WEB_TRANSPORT: 4 }; /** * Enumeration of the network quality level. * * @enum {number} * @property {number} VERY_BAD network quality is very bad. Default value is 0. * @property {number} BAD network quality is bad. Default value is 1. * @property {number} NOT_GOOD network quality is not good enough. Default value is 2. * @property {number} FAIR network quality is fine. Default value is 3. * @property {number} GOOD network quality is good. Default value is 4. * @property {number} EXCELLENT network quality is excellent. Default value is 5. * @property {number} UNDEFINED network quality is unknown. If get this value, means the network diagnostic is not started yet or gets some exceptions. Default value is 255. * @constant */ var NETWORK_QUALITY_LEVEL = { VERY_BAD: 0, BAD: 1, NOT_GOOD: 2, FAIR: 3, GOOD: 4, EXCELLENT: 5, UNDEFINED: 255 }; /** * Enumeration of the bandwidth quality level. * * @enum {number} * @property {number} VERY_LOW bandwidth quality is very low. Default value is 0. * @property {number} LOW bandwidth quality is low. Default value is 1. * @property {number} NORMAL bandwidth quality is normal. Default value is 2. * @property {number} UNDEFINED bandwidth quality is unknown. If get this value, means the network diagnostic is not started yet or gets some exceptions. Default value is 255. * @constant */ var BANDWIDTH_QUALITY_LEVEL = { VERY_LOW: 0, LOW: 1, NORMAL: 2, UNDEFINED: 255 }; /** * Enumeration of attribute index of the basic information. * * @enum {number} * @property {number} BROWSER_NAME represents the name of the browser. Default value is 0. * @property {number} BROWSER_VERSION represents the version of the browser. Default value is 1. * @property {number} OS_NAME represents the name of the OS. Default value is 2. * @property {number} USER_AGENT represents the user agent. Default value is 3. * @property {number} HW_CONCURRENCY represents the hardware concurrency. Default value is 4. * @property {number} GPU_VENDOR represents the GPU vendor. Default value is 5. * @property {number} GPU_RENDERER represents the GPU renderer information. Default value is 6. * @property {number} VIDEOFRAME represents the VideoFrame API. Default value is 7. * @property {number} OFFSCREENCANVAS represents the OffscreenCanvas API. Default value is 8. * @property {number} SIMD represents the SIMD feature. Default value is 9. * @property {number} WEB_CODEC represents the web codec feature. Default value is 10. * @property {number} HW_ACC represents the hardware acceleration. Default value is 11. * @property {number} GRAPHICS_ACC represents the graphics acceleration in chromium system settings. Default value is 12. * @property {number} MIN_BROWSER_VERSION represents the minimum browser version. Default value is 13. * @property {number} SHARED_ARRAY_BUFFER represents the SharedArrayBuffer. Default value is 14. * @property {number} BUILD_BITNESS represents the build bitness(32bit or 64bit). Default value is 15. * @constant */ var BASIC_INFO_ATTR_INDEX = { BROWSER_NAME: 0, BROWSER_VERSION: 1, OS_NAME: 2, OS_VERSION: 3, USER_AGENT: 4, HW_CONCURRENCY: 5, GPU_VENDOR: 6, GPU_RENDERER: 7, VIDEOFRAME: 8, OFFSCREENCANVAS: 9, SIMD: 10, WEB_CODEC: 11, HW_ACC: 12, GRAPHICS_ACC: 13, MIN_BROWSER_VERSION: 14, SHARED_ARRAY_BUFFER: 15, BUILD_BITNESS: 16 }; /** * Enumeration of index of the supported features. * * @enum {number} * @property {number} AUDIO_DENOISE feature index of audio denoise. Default value is 0. * @property {number} AEC feature index of audio echo cancellation. Default value is 1. * @property {number} AUDIO_STEREO feature index of audio stereo. Default value is 2. * @property {number} VIRTUAL_BACKGROUND feature index of video virtual background. Default value is 3. * @property {number} VIDEO_MASK feature index of video mask. Default value is 4. * @property {number} WEBGPU feature index of video WebGPU rendering. Default value is 5. * @property {number} VIDEO_SEND_HD feature index of video sending HD. Default value is 6. * @property {number} VIDEO_SEND_FULL_HD feature index of video sending full HD. Default value is 7. * @property {number} DT_GALLERY_VIEW_3x3 feature index of desktop supporting 3x3 gallery view. Default value is 8. * @property {number} DT_GALLERY_VIEW_5x5 feature index of desktop supporting 5x5 gallery view. Default value is 9. * @property {number} SCREEN_SHARING feature index of screen sharing. Default value is 10. * @constant */ var SUPPORTED_FEATURE_INDEX = { AUDIO_DENOISE: 0, AEC: 1, AUDIO_STEREO: 2, VIRTUAL_BACKGROUND: 3, VIDEO_MASK: 4, WEBGPU: 5, VIDEO_SEND_HD: 6, VIDEO_SEND_FULL_HD: 7, DT_GALLERY_VIEW_3x3: 8, DT_GALLERY_VIEW_5x5: 9, SCREEN_SHARING: 10 }; /** * The default probing duration, 120 seconds. */ var DEF_PROBE_DURATION = 2 * 60 * 1000; /** * The default connection timeout, 20 seconds. */ var DEF_CONNECT_TIMEOUT = 2 * 10 * 1000; var JWT_DOMAINS = { PROD: "zoom.us", GO: "go.zoom.us", DEV: "zoomdev.us", DEV_EP: "devep.zoomdev.us", DEV_INT: "dev-integration.zoomdev.us" }; function checkType(obj, targetType) { return !!(obj instanceof targetType); } function isDebugMode() { return process.env.NODE_ENV === "development"; } function getJWTPayload(token) { var base64Url = token.split(".")[1]; var base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/"); var jsonPayload = decodeURIComponent(window.atob(base64).split("").map(function (c) { return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); }).join("")); return JSON.parse(jsonPayload); } function isInUserAgent(userAgent) { for (var _len = arguments.length, tags = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { tags[_key - 1] = arguments[_key]; } if (!userAgent || userAgent === "") { console.error("isInUserAgent() userAgent is invalid! userAgent: ".concat(userAgent)); return false; } if (!tags || tags.length <= 0) { console.error("isInUserAgent() tag is invalid! tags: ".concat(tags)); return false; } return tags.some(function (tag) { return userAgent.includes(tag); }); } function saveKvToLocalStorage(key, value) { if (isDebugMode()) { console.log("saveKvToLocalStorage() key: ".concat(key, ", val:").concat(value)); } localStorage.setItem(key, value); } function readValueFromLocalStorage(key) { return localStorage.getItem(key); } /** * Test whether can allocate a string of a given length. * @param {Number} len a length of string to be allocated. * @returns {boolean} true if the string can be allocated, false otherwise. */ function canSupportStringLength(len) { try { return new Array(len + 1).join('x').length === len; } catch (e) { return false; } } var GLOBAL_SEQ = 1; var KEY_RID = "probing_rid"; function base64ToBytes(base64) { var binString = atob(base64); return Uint8Array.from(binString, function (m) { return m.codePointAt(0); }); } function bytesToBase64(bytes) { var binString = String.fromCodePoint.apply(String, _toConsumableArray(bytes)); return btoa(binString); } function getCommandMessage(evt, body) { var msg = {}; msg["evt"] = evt; msg["seq"] = GLOBAL_SEQ; GLOBAL_SEQ += 1; msg["body"] = body; return JSON.stringify(msg); } function connectWebSocket(_x) { return _connectWebSocket.apply(this, arguments); } function _connectWebSocket() { _connectWebSocket = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee11(url) { return _regeneratorRuntime().wrap(function _callee11$(_context11) { while (1) switch (_context11.prev = _context11.next) { case 0: if (isDebugMode()) { console.log("connectWebSocket() url=".concat(url)); } return _context11.abrupt("return", new Promise(function (resolve, reject) { var socket = new WebSocket(url); socket.onopen = function () { resolve({ socket: socket, result: true, error: undefined }); }; socket.onerror = function (error) { resolve({ socket: socket, result: false, error: error }); }; })); case 2: case "end": return _context11.stop(); } }, _callee11); })); return _connectWebSocket.apply(this, arguments); } function js_send_data(prober_instance, buffer, len, send_by_data) { if (prober_instance) { var data = new Uint8Array(Module.HEAP8.buffer, buffer, len); if (send_by_data) { if (prober_instance.writer !== null && prober_instance.writer !== undefined) { prober_instance.writer.write(data); } else if (prober_instance.dataChannelOpened) { if (prober_instance.videoDataChannel) { prober_instance.videoDataChannel.send(data); } } else if (prober_instance.mediaSocket !== null && prober_instance.mediaSocket !== undefined) { prober_instance.mediaSocket.send(data); } } else { var binString = bytesToBase64(data); var body = {}; body["data"] = binString; if (prober_instance.socket) { prober_instance.socket.send(getCommandMessage(4106, body)); } } } } function js_report_qos_info(prober_instance, bandwidth, rate, loss_rate, max_continuous_loss_num, rtt, max_owdelay, jitter, app_score, bw_level) { // uplink var uplink_bandwidth = bandwidth / 1024 / 1024; var uplink_rtt = rtt; var uplink_lossratio = loss_rate / 10; var uplink_max_continuous_loss_num = max_continuous_loss_num; var uplink_rate = rate / 1024 / 1024; var uplink_owdelay = max_owdelay; var uplink_jitter = jitter; if (isDebugMode()) { console.log("js_report_qos_info: uplink_bandwidth=".concat(uplink_bandwidth, ", uplink_rtt=").concat(uplink_rtt, ", count=").concat(prober_instance === null || prober_instance === void 0 ? void 0 : prober_instance.uplink_count)); } if (prober_instance) { prober_instance.on_uplink_report({ bandwidth: uplink_bandwidth, rtt: uplink_rtt, loss_rate: uplink_lossratio, max_continuous_loss_num: uplink_max_continuous_loss_num, rate: uplink_rate, max_owdelay: uplink_owdelay, jitter: uplink_jitter, network_level: app_score, bw_level: bw_level }); prober_instance.uplink_count += 1; prober_instance.total_ul_rtt += uplink_rtt; prober_instance.total_ul_loss += uplink_lossratio; prober_instance.total_ul_jitter += uplink_jitter; prober_instance.last_ul_bw = uplink_bandwidth; prober_instance.last_ul_bw_level = bw_level; prober_instance.last_ul_network_level = app_score; } else { console.error("js_report_qos_info: prober_instance is null or undefined!"); } } function wcl_trace_log(a, b) { var n = new Uint8Array(b + 1); var s = Module.HEAP8.subarray(a + 0, a + b); n.set(s, 0, b); n[b] = 10; } var _NetworkProberInst_brand = /*#__PURE__*/new WeakSet(); var NetworkProberInst = /*#__PURE__*/function () { function NetworkProberInst(params) { var _this = this; _classCallCheck(this, NetworkProberInst); _classPrivateMethodInitSpec(this, _NetworkProberInst_brand); this.dc = "No available service zone."; this.jwtDomain = params.domain; this.probeServerDomain = ""; this.geoProbeConnectionList = []; this.on_uplink_report = params.on_uplink_report; this.on_downlink_report = params.on_downlink_report; this.socket = null; this.connectionId = ""; this.index = -1; this.worker = null; this.rid = null; var Module = params.Module; this.api = { create_prober: Module.cwrap("create_prober", "number", []), destroy_prober: Module.cwrap("destroy_prober", "", ["number"]), on_prober_timer: Module.cwrap("on_prober_timer", "", ["number"]), prober_start_send: Module.cwrap("prober_start_send", "", ["number"]), prober_stop_send: Module.cwrap("prober_stop_send", "", ["number"]), readPackets: Module.cwrap("readPackets", "number", ["number", "array", "number", "number"]) }; this.prober = null; this.mediaSocket = null; this.keepAliveTimer = null; this.videoPeer = new RTCPeerConnection({ iceCandidatePoolSize: 1 }); this.videoPeer.addEventListener("iceconnectionstatechange", function () { if (_this.videoPeer.iceConnectionState === "disconnected" || _this.videoPeer.iceConnectionState === "failed" || _this.videoPeer.iceConnectionState === "closed") { console.log("PeerConnection disconnected, closing DataChannel."); _this.cleanupDataChannel(); } }); this.videoDataChannel = this.videoPeer.createDataChannel("prober_datachannel", { ordered: false, maxRetransmits: 0, reliable: false }); this.dataChannelOpened = false; this.dc_recv_packets = 0; this.transport = null; this.writer = null; var prober_instance = this; window.wcl_trace_log = wcl_trace_log; window.js_send_data = function (buffer, len, send_by_data) { js_send_data(prober_instance, buffer, len, send_by_data); }; window.js_report_qos_info = function (bandwidth, rate, loss_rate, max_continuous_loss_num, rtt, max_owdelay, jitter, app_score, bw_level) { if (isDebugMode()) { console.log("js_report_qos_info called: bandwidth=".concat(bandwidth, ", app_score=").concat(app_score, ", bw_level=").concat(bw_level)); } js_report_qos_info(prober_instance, bandwidth, rate, loss_rate, max_continuous_loss_num, rtt, max_owdelay, jitter, app_score, bw_level); }; this.downlink_count = 0; this.total_dl_rtt = 0; this.total_dl_loss = 0; this.total_dl_jitter = 0; this.last_dl_bw = 0; this.last_dl_bw_level = 255; this.last_dl_network_level = 255; this.uplink_count = 0; this.total_ul_rtt = 0; this.total_ul_loss = 0; this.total_ul_jitter = 0; this.last_ul_bw = 0; this.last_ul_bw_level = 255; this.last_ul_network_level = 255; this.httpsProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.HTTPS, false); this.wssProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.WEB_SOCKET, true, "", "unchecked"); this.dataChannelProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.DATA_CHANNEL, true, "", "unchecked"); } return _createClass(NetworkProberInst, [{ key: "connect", value: function () { var _connect = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(timeout) { var _this2 = this; var _data$result, jwtTokenUrl, tokenRsp, ridPart, rid, data, token, payload, hasGeoProbeConnected, geoProbeList, cmdChannelResult, _iterator, _step, geoProbe, cmdChannelUrl, _yield$this$getConnec, connectionId, index, mediaUrl, mediaChannelResult, isDataChannelEstablished; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: _context.prev = 0; jwtTokenUrl = "https://".concat(this.jwtDomain, "/probe/network/monitor/auth/info"); _context.next = 4; return fetch(jwtTokenUrl, { method: "POST", mode: "cors", headers: {} }); case 4: tokenRsp = _context.sent; if (tokenRsp.ok) { _context.next = 8; break; } this.wssProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.HTTPS, true); return _context.abrupt("return", false); case 8: // get rsp headers ridPart = ""; if (tokenRsp.headers.has("X-Zm-Trackingid")) { rid = _assertClassBrand(_NetworkProberInst_brand, this, _extractRid).call(this, tokenRsp.headers.get("X-Zm-Trackingid")); if (rid !== "") { this.rid = rid.slice(4, rid.length); saveKvToLocalStorage(KEY_RID, this.rid); ridPart = "&".concat(rid); } if (isDebugMode()) { console.log("trackingId: ".concat(tokenRsp.headers.get("X-Zm-Trackingid"), ", finalRid:").concat(ridPart)); } } else { console.log("connect() no tid header."); } _context.next = 12; return tokenRsp.json(); case 12: data = _context.sent; token = data === null || data === void 0 || (_data$result = data.result) === null || _data$result === void 0 ? void 0 : _data$result.probeToken; if (token) { _context.next = 17; break; } this.wssProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.HTTPS, true, "", "", { message: "cannot retrieve token from server response!" }); return _context.abrupt("return", false); case 17: payload = getJWTPayload(token); if (isDebugMode()) { console.log("jwtToken payload:".concat(JSON.stringify(payload))); } hasGeoProbeConnected = false; geoProbeList = JSON.parse(payload.geoProbeList); cmdChannelResult = null; _iterator = _createForOfIteratorHelper(geoProbeList); _context.prev = 23; _iterator.s(); case 25: if ((_step = _iterator.n()).done) { _context.next = 48; break; } geoProbe = _step.value; if (isDebugMode()) { console.log("geoProbeEntry: dc=".concat(geoProbe.dc, ", probe=").concat(geoProbe.probe)); } this.dc = geoProbe.dc; this.probeServerDomain = geoProbe.probe; // this.domain = '10.100.212.157:810'; // 1. Check the command channel whether the connection is established or not. cmdChannelUrl = "wss://".concat(this.probeServerDomain, "/probe/?token=").concat(token).concat(ridPart); _context.next = 33; return connectWebSocket(cmdChannelUrl); case 33: cmdChannelResult = _context.sent; if (cmdChannelResult.result) { _context.next = 42; break; } if (isDebugMode()) { console.warn("failed to connect! geoProbeEntry: dc=".concat(geoProbe.dc, ", probe=").concat(geoProbe.probe)); } // record the failed connection this.geoProbeConnectionList.push({ dc: geoProbe.dc, probe: geoProbe.probe, connected: false }); if (cmdChannelResult.socket) { cmdChannelResult.socket.close(); } this.wssProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.WEB_SOCKET, true, "", "", cmdChannelResult.error); return _context.abrupt("continue", 46); case 42: hasGeoProbeConnected = true; // record the successful connection this.geoProbeConnectionList.push({ dc: geoProbe.dc, probe: geoProbe.probe, connected: true }); this.wssProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.WEB_SOCKET, false); return _context.abrupt("break", 48); case 46: _context.next = 25; break; case 48: _context.next = 53; break; case 50: _context.prev = 50; _context.t0 = _context["catch"](23); _iterator.e(_context.t0); case 53: _context.prev = 53; _iterator.f(); return _context.finish(53); case 56: if (!(!hasGeoProbeConnected || !cmdChannelResult)) { _context.next = 61; break; } if (isDebugMode()) { console.error("no available geolocation connected!"); } this.dc = "No available service zone."; this.killKeepAliveTimer(); return _context.abrupt("return", false); case 61: // if goes here, means the command channel is connected // we need to start a timer with 5 seconds interval to send keep alive message to server if (!this.keepAliveTimer) { this.keepAliveTimer = setInterval(function () { _this2.sendKeepAliveMessage(); }, 5000); } this.socket = cmdChannelResult.socket; _context.next = 65; return this.getConnectionId(); case 65: _yield$this$getConnec = _context.sent; connectionId = _yield$this$getConnec.connectionId; index = _yield$this$getConnec.index; this.connectionId = connectionId; this.index = index; this.cmdMessageRegister(); // Always create a new prober instance to ensure clean state if (this.prober) { this.api.destroy_prober(this.prober); } this.prober = this.api.create_prober(); // 2. Media websocket works as the backup of the data channel if fails mediaUrl = "wss://".concat(this.probeServerDomain, "/media/?cid=").concat(this.connectionId, "&index=").concat(this.index); _context.next = 76; return connectWebSocket(mediaUrl); case 76: mediaChannelResult = _context.sent; if (mediaChannelResult.result) { _context.next = 83; break; } if (mediaChannelResult.socket) { mediaChannelResult.socket.close(); } this.wssProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.WEB_SOCKET, true, "", "", mediaChannelResult.error); return _context.abrupt("return", false); case 83: if (this.wssProtocol == undefined || this.wssProtocol.isBlocked) { this.wssProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.WEB_SOCKET, false); } case 84: this.mediaSocket = mediaChannelResult.socket; this.mediaMessageRegister(); // 3. Try to connect data channel _context.next = 88; return this.connectDataChannel(timeout); case 88: isDataChannelEstablished = _context.sent; if (!isDataChannelEstablished) { this.dataChannelProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.DATA_CHANNEL, true, "8801", "Please check the network connectivity and the port which might be blocked", cmdChannelResult.error); } else { if (this.dataChannelProtocol == undefined || this.dataChannelProtocol.isBlocked) { this.dataChannelProtocol = this.assembleProtocolResult(PROTOCOL_TYPE.DATA_CHANNEL, false, "8801"); } } return _context.abrupt("return", true); case 93: _context.prev = 93; _context.t1 = _context["catch"](0); console.error("Error connecting:", _context.t1); return _context.abrupt("return", false); case 97: case "end": return _context.stop(); } }, _callee, this, [[0, 93], [23, 50, 53, 56]]); })); function connect(_x2) { return _connect.apply(this, arguments); } return connect; }() }, { key: "startUplinkProbe", value: function () { var _startUplinkProbe = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() { var workerScript, blob, count, interval, probeTime, maxCount, prober_instance; return _regeneratorRuntime().wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: if (this.prober) { _context2.next = 3; break; } console.error("startUplinkProbe: prober instance is null!"); return _context2.abrupt("return"); case 3: if (!this.worker) { workerScript = "\n var worker_active = false;\n\n setInterval(() => {\n if (worker_active) {\n postMessage(worker_active);\n }\n }, 10);\n\n onmessage = (e) => {\n worker_active = e.data;\n };\n "; blob = new Blob([workerScript], { type: "application/javascript" }); this.worker = new Worker(URL.createObjectURL(blob), { type: "module" }); } this.worker.postMessage(true); this.api.prober_start_send(this.prober); count = 0; interval = 10; // Worker sends message every 10ms probeTime = 300 * 1000; // 300 seconds maxCount = probeTime / interval; // 30000 prober_instance = this; // console.log(`Worker will send ${maxCount} timer calls over ${probeTime}ms`); this.worker.onmessage = function (event) { if (count < maxCount) { prober_instance.api.on_prober_timer(prober_instance.prober); count += 1; // Log progress every 1000 calls if (count % 1000 === 0) { console.log("Uplink probe timer called ".concat(count, "/").concat(maxCount, " times")); } } }; case 12: case "end": return _context2.stop(); } }, _callee2, this); })); function startUplinkProbe() { return _startUplinkProbe.apply(this, arguments); } return startUplinkProbe; }() }, { key: "stopUplinkProbe", value: function () { var _stopUplinkProbe = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() { return _regeneratorRuntime().wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: this.api.prober_stop_send(this.prober); if (this.worker) { this.worker.postMessage(false); this.worker.terminate(); this.worker = null; } case 2: case "end": return _context3.stop(); } }, _callee3, this); })); function stopUplinkProbe() { return _stopUplinkProbe.apply(this, arguments); } return stopUplinkProbe; }() }, { key: "startDownlinkProbe", value: function () { var _startDownlinkProbe = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4() { return _regeneratorRuntime().wrap(function _callee4$(_context4) { while (1) switch (_context4.prev = _context4.next) { case 0: console.log("startDownlinkProbe"); _context4.next = 3; return this.socket.send(getCommandMessage(4107, {})); case 3: case "end": return _context4.stop(); } }, _callee4, this); })); function startDownlinkProbe() { return _startDownlinkProbe.apply(this, arguments); } return startDownlinkProbe; }() }, { key: "stopDownlinkProbe", value: function () { var _stopDownlinkProbe = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5() { var commandMessage; return _regeneratorRuntime().wrap(function _callee5$(_context5) { while (1) switch (_context5.prev = _context5.next) { case 0: commandMessage = getCommandMessage(4108, {}); _context5.next = 3; return this.socket.send(commandMessage); case 3: case "end": return _context5.stop(); } }, _callee5, this); })); function stopDownlinkProbe() { return _stopDownlinkProbe.apply(this, arguments); } return stopDownlinkProbe; }() }, { key: "connectWebTransport", value: function () { var _connectWebTransport = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() { var url, transport, writer, reader; return _regeneratorRuntime().wrap(function _callee6$(_context6) { while (1) switch (_context6.prev = _context6.next) { case 0: url = "https://" + this.probeServerDomain + ":8802?cid=" + this.connectionId; transport = new WebTransport(url); this.transport = transport; _context6.next = 5; return transport.ready; case 5: transport.datagrams.incomingMaxAge = 30000; transport.datagrams.outgoingMaxAge = 30000; transport.datagrams.incomingHighWaterMark = 10000; transport.datagrams.outgoingHighWaterMark = 10000; transport.datagrams.writable.maxAge = 30000; transport.datagrams.readable.maxAge = 30000; writer = transport.datagrams.writable.getWriter(); reader = transport.datagrams.readable.getReader(); _context6.next = 15; return writer.ready; case 15: this.writer = writer; this.webTransportRead(reader); case 17: case "end": return _context6.stop(); } }, _callee6, this); })); function connectWebTransport() { return _connectWebTransport.apply(this, arguments); } return connectWebTransport; }() }, { key: "webTransportRead", value: function () { var _webTransportRead = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(reader) { var _yield$reader$read, value, done, probeData; return _regeneratorRuntime().wrap(function _callee7$(_context7) { while (1) switch (_context7.prev = _context7.next) { case 0: _context7.next = 3; return reader.read();