UNPKG

@cloudflare/speedtest

Version:

Component to perform network speed tests against Cloudflare's edge network

1,265 lines (1,233 loc) 99.2 kB
import 'isomorphic-fetch'; import memoize from 'lodash.memoize'; import { scaleThreshold } from 'd3-scale'; function _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; } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } 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 _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _classPrivateFieldGet2(s, a) { return s.get(_assertClassBrand(s, a)); } function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); } function _classPrivateFieldSet2(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; } function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", { writable: false }), e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e; } function _get() { return _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) { var p = _superPropBase(e, t); if (p) { var n = Object.getOwnPropertyDescriptor(p, t); return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value; } }, _get.apply(null, arguments); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: true, configurable: true } }), Object.defineProperty(t, "prototype", { writable: false }), e && _setPrototypeOf(t, e); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function () { return !!t; })(); } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = true, o = false; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = true, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } 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 ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } function _possibleConstructorReturn(t, e) { if (e && ("object" == typeof e || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function set(e, r, t, o) { return set = "undefined" != typeof Reflect && Reflect.set ? Reflect.set : function (e, r, t, o) { var f, i = _superPropBase(e, r); if (i) { if ((f = Object.getOwnPropertyDescriptor(i, r)).set) return f.set.call(o, t), true; if (!f.writable) return false; } if (f = Object.getOwnPropertyDescriptor(o, r)) { if (!f.writable) return false; f.value = t, Object.defineProperty(o, r, f); } else _defineProperty(o, r, t); return true; }, set(e, r, t, o); } function _set(e, r, t, o, f) { if (!set(e, r, t, o || e) && f) throw new TypeError("failed to set property"); return t; } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _superPropBase(t, o) { for (; !{}.hasOwnProperty.call(t, o) && null !== (t = _getPrototypeOf(t));); return t; } function _superPropGet(t, o, e, r) { var p = _get(_getPrototypeOf(t.prototype ), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; } function _superPropSet(t, e, o, r, p, f) { return _set(_getPrototypeOf(t.prototype ), e, o, r, p); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } 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); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return (String )(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _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; } } var REL_API_URL = 'https://speed.cloudflare.com'; var defaultConfig = { // Engine autoStart: true, // APIs downloadApiUrl: "".concat(REL_API_URL, "/__down"), uploadApiUrl: "".concat(REL_API_URL, "/__up"), logMeasurementApiUrl: null, logAimApiUrl: 'https://aim.cloudflare.com/__log', turnServerUri: 'turn.speed.cloudflare.com:50000', turnServerCredsApiUrl: "".concat(REL_API_URL, "/turn-creds"), turnServerUser: null, turnServerPass: null, rpkiInvalidHost: 'invalid.rpki.cloudflare.com', cfTraceUrl: "".concat(REL_API_URL, "/cdn-cgi/trace"), includeCredentials: false, sessionId: undefined, // Measurements measurements: [{ type: 'latency', numPackets: 1 }, // initial ttfb estimation { type: 'download', bytes: 1e5, count: 1, bypassMinDuration: true }, // initial download estimation { type: 'latency', numPackets: 20 }, { type: 'download', bytes: 1e5, count: 9 }, { type: 'download', bytes: 1e6, count: 8 }, { type: 'upload', bytes: 1e5, count: 8 }, { type: 'packetLoss', numPackets: 1e3, batchSize: 10, batchWaitTime: 10, // ms (in between batches) responsesWaitTime: 3000 // ms (silent time after last sent msg) }, { type: 'upload', bytes: 1e6, count: 6 }, { type: 'download', bytes: 1e7, count: 6 }, { type: 'upload', bytes: 1e7, count: 4 }, { type: 'download', bytes: 2.5e7, count: 4 }, { type: 'upload', bytes: 2.5e7, count: 4 }, { type: 'download', bytes: 1e8, count: 3 }, { type: 'upload', bytes: 5e7, count: 3 }, { type: 'download', bytes: 2.5e8, count: 2 }], measureDownloadLoadedLatency: true, measureUploadLoadedLatency: true, loadedLatencyThrottle: 400, // ms in between loaded latency requests bandwidthFinishRequestDuration: 1000, // download/upload duration (ms) to reach for stopping further measurements estimatedServerTime: 10, // ms to discount from latency calculation (if not present in response headers) // Result interpretation latencyPercentile: 0.5, // Percentile used to calculate latency from a set of measurements bandwidthPercentile: 0.9, // Percentile used to calculate bandwidth from a set of measurements bandwidthMinRequestDuration: 10, // minimum duration (ms) to consider a measurement good enough to use in bandwidth calculation loadedRequestMinDuration: 250, // minimum duration (ms) of a request to consider it to be loading the connection loadedLatencyMaxPoints: 20 // number of data points to keep for loaded latency }; var internalConfig = { // AIM aimMeasurementScoring: { packetLoss: scaleThreshold([0.01, 0.05, 0.25, 0.5], [10, 5, 0, -10, -20]), latency: scaleThreshold([10, 20, 50, 100, 500], [20, 10, 5, 0, -10, -20]), loadedLatencyIncrease: scaleThreshold([10, 20, 50, 100, 500], [20, 10, 5, 0, -10, -20]), jitter: scaleThreshold([10, 20, 100, 500], [10, 5, 0, -10, -20]), download: scaleThreshold([1e6, 10e6, 50e6, 100e6], [0, 5, 10, 20, 30]), upload: scaleThreshold([1e6, 10e6, 50e6, 100e6], [0, 5, 10, 20, 30]) }, aimExperiencesDefs: { streaming: { input: ['latency', 'packetLoss', 'download', 'loadedLatencyIncrease'], pointThresholds: [15, 20, 40, 60] }, gaming: { input: ['latency', 'packetLoss', 'loadedLatencyIncrease'], pointThresholds: [5, 15, 25, 30] }, rtc: { input: ['latency', 'jitter', 'packetLoss', 'loadedLatencyIncrease'], pointThresholds: [5, 15, 25, 40] } } }; var MAX_RETRIES = 20; var ESTIMATED_HEADER_FRACTION = 0.005; // ~.5% of packet header / payload size. used when transferSize is not available. var cfGetServerTime = function cfGetServerTime(r) { // extract server-timing from headers: server-timing: cfRequestDuration;dur=15.999794 var serverTiming = r.headers.get("server-timing"); if (serverTiming) { var re = serverTiming.match(/dur=([0-9.]+)/); if (re) return +re[1]; } }; var getTtfb = function getTtfb(perf) { return perf.responseStart - perf.requestStart; }; var gePayloadDownload = function gePayloadDownload(perf) { return perf.responseEnd - perf.responseStart; }; // min 1ms var calcDownloadDuration = function calcDownloadDuration(_ref) { var ping = _ref.ping, payloadDownloadTime = _ref.payloadDownloadTime; return ping + payloadDownloadTime; }; // request duration excluding server time var calcUploadDuration = function calcUploadDuration(_ref2) { var ttfb = _ref2.ttfb; return ttfb; }; var calcDownloadSpeed = function calcDownloadSpeed(_ref3, numBytes) { var duration = _ref3.duration, transferSize = _ref3.transferSize; // use transferSize if available. if estimating from numBytes, add ~0.5% of headers. var bits = 8 * (transferSize || +numBytes * (1 + ESTIMATED_HEADER_FRACTION)); var secs = duration / 1000; return !secs ? undefined : bits / secs; }; var calcUploadSpeed = function calcUploadSpeed(_ref4, numBytes) { var duration = _ref4.duration; var bits = 8 * numBytes * (1 + ESTIMATED_HEADER_FRACTION); // take into account estimated packet headers var secs = duration / 1000; // subtract estimated server time return !secs ? undefined : bits / secs; }; var genContent = memoize(function (numBytes) { return '0'.repeat(numBytes); }); // var _qsParams = /*#__PURE__*/new WeakMap(); var _fetchOptions = /*#__PURE__*/new WeakMap(); var _responseHook = /*#__PURE__*/new WeakMap(); var _onRunningChange = /*#__PURE__*/new WeakMap(); var _onNewMeasurementStarted = /*#__PURE__*/new WeakMap(); var _onMeasurementResult = /*#__PURE__*/new WeakMap(); var _onFinished$1 = /*#__PURE__*/new WeakMap(); var _onConnectionError$1 = /*#__PURE__*/new WeakMap(); var _measurements = /*#__PURE__*/new WeakMap(); var _downloadApi = /*#__PURE__*/new WeakMap(); var _uploadApi = /*#__PURE__*/new WeakMap(); var _running$2 = /*#__PURE__*/new WeakMap(); var _finished$1 = /*#__PURE__*/new WeakMap(); var _results$1 = /*#__PURE__*/new WeakMap(); var _measIdx = /*#__PURE__*/new WeakMap(); var _counter = /*#__PURE__*/new WeakMap(); var _retries = /*#__PURE__*/new WeakMap(); var _minDuration = /*#__PURE__*/new WeakMap(); var _throttleMs = /*#__PURE__*/new WeakMap(); var _estimatedServerTime = /*#__PURE__*/new WeakMap(); var _currentFetchPromise = /*#__PURE__*/new WeakMap(); var _currentNextMsmTimeoutId = /*#__PURE__*/new WeakMap(); var _BandwidthMeasurementEngine_brand = /*#__PURE__*/new WeakSet(); var BandwidthMeasurementEngine = /*#__PURE__*/function () { function BandwidthMeasurementEngine(_measurements2) { var _ref5 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, downloadApiUrl = _ref5.downloadApiUrl, uploadApiUrl = _ref5.uploadApiUrl, _ref5$throttleMs = _ref5.throttleMs, throttleMs = _ref5$throttleMs === void 0 ? 0 : _ref5$throttleMs, _ref5$estimatedServer = _ref5.estimatedServerTime, estimatedServerTime = _ref5$estimatedServer === void 0 ? 0 : _ref5$estimatedServer; _classCallCheck(this, BandwidthMeasurementEngine); // Internal methods _classPrivateMethodInitSpec(this, _BandwidthMeasurementEngine_brand); _classPrivateFieldInitSpec(this, _qsParams, {}); _classPrivateFieldInitSpec(this, _fetchOptions, {}); _defineProperty(this, "finishRequestDuration", 1000); // download/upload duration (ms) to reach for stopping further measurements _defineProperty(this, "getServerTime", cfGetServerTime); // method to extract server time from response _classPrivateFieldInitSpec(this, _responseHook, function (r) { return r; }); _classPrivateFieldInitSpec(this, _onRunningChange, function () {}); _classPrivateFieldInitSpec(this, _onNewMeasurementStarted, function () {}); _classPrivateFieldInitSpec(this, _onMeasurementResult, function () {}); _classPrivateFieldInitSpec(this, _onFinished$1, function () {}); _classPrivateFieldInitSpec(this, _onConnectionError$1, function () {}); // Internal state _classPrivateFieldInitSpec(this, _measurements, void 0); _classPrivateFieldInitSpec(this, _downloadApi, void 0); _classPrivateFieldInitSpec(this, _uploadApi, void 0); _classPrivateFieldInitSpec(this, _running$2, false); _classPrivateFieldInitSpec(this, _finished$1, { down: false, up: false }); _classPrivateFieldInitSpec(this, _results$1, { down: {}, up: {} }); _classPrivateFieldInitSpec(this, _measIdx, 0); _classPrivateFieldInitSpec(this, _counter, 0); _classPrivateFieldInitSpec(this, _retries, 0); _classPrivateFieldInitSpec(this, _minDuration, -Infinity); // of current measurement _classPrivateFieldInitSpec(this, _throttleMs, 0); _classPrivateFieldInitSpec(this, _estimatedServerTime, 0); _classPrivateFieldInitSpec(this, _currentFetchPromise, undefined); _classPrivateFieldInitSpec(this, _currentNextMsmTimeoutId, undefined); if (!_measurements2) throw new Error('Missing measurements argument'); if (!downloadApiUrl) throw new Error('Missing downloadApiUrl argument'); if (!uploadApiUrl) throw new Error('Missing uploadApiUrl argument'); _classPrivateFieldSet2(_measurements, this, _measurements2); _classPrivateFieldSet2(_downloadApi, this, downloadApiUrl); _classPrivateFieldSet2(_uploadApi, this, uploadApiUrl); _classPrivateFieldSet2(_throttleMs, this, throttleMs); _classPrivateFieldSet2(_estimatedServerTime, this, Math.max(0, estimatedServerTime)); } // Public attributes return _createClass(BandwidthMeasurementEngine, [{ key: "results", get: function get() { // read access to results return _classPrivateFieldGet2(_results$1, this); } }, { key: "qsParams", get: // additional query string params to include in the requests function get() { return _classPrivateFieldGet2(_qsParams, this); }, set: function set(v) { _classPrivateFieldSet2(_qsParams, this, v); } }, { key: "fetchOptions", get: // additional options included in the requests function get() { return _classPrivateFieldGet2(_fetchOptions, this); }, set: function set(v) { _classPrivateFieldSet2(_fetchOptions, this, v); } }, { key: "responseHook", set: // pipe-through of response objects function set(f) { _classPrivateFieldSet2(_responseHook, this, f); } }, { key: "onRunningChange", set: // callback invoked when engine starts/stops function set(f) { _classPrivateFieldSet2(_onRunningChange, this, f); } }, { key: "onNewMeasurementStarted", set: // callback invoked when a new item in the measurement list is started function set(f) { _classPrivateFieldSet2(_onNewMeasurementStarted, this, f); } }, { key: "onMeasurementResult", set: // callback invoked when a new measurement result arrives function set(f) { _classPrivateFieldSet2(_onMeasurementResult, this, f); } }, { key: "onFinished", set: // callback invoked when all the measurements are finished function set(f) { _classPrivateFieldSet2(_onFinished$1, this, f); } }, { key: "onConnectionError", set: // Invoked when unable to get a response from the API function set(f) { _classPrivateFieldSet2(_onConnectionError$1, this, f); } // Public methods }, { key: "pause", value: function pause() { clearTimeout(_classPrivateFieldGet2(_currentNextMsmTimeoutId, this)); _assertClassBrand(_BandwidthMeasurementEngine_brand, this, _cancelCurrentMeasurement).call(this); _assertClassBrand(_BandwidthMeasurementEngine_brand, this, _setRunning$2).call(this, false); } }, { key: "play", value: function play() { if (!_classPrivateFieldGet2(_running$2, this)) { _assertClassBrand(_BandwidthMeasurementEngine_brand, this, _setRunning$2).call(this, true); _assertClassBrand(_BandwidthMeasurementEngine_brand, this, _nextMeasurement).call(this); } } }]); }(); function _setRunning$2(running) { var _this = this; if (running !== _classPrivateFieldGet2(_running$2, this)) { _classPrivateFieldSet2(_running$2, this, running); setTimeout(function () { return _classPrivateFieldGet2(_onRunningChange, _this).call(_this, _classPrivateFieldGet2(_running$2, _this)); }); } } function _saveMeasurementResults(measIdx, measTiming) { var _this2 = this; var _classPrivateFieldGet2$1 = _classPrivateFieldGet2(_measurements, this)[measIdx], bytes = _classPrivateFieldGet2$1.bytes, dir = _classPrivateFieldGet2$1.dir; var results = _classPrivateFieldGet2(_results$1, this); var bytesResult = results[dir].hasOwnProperty(bytes) ? results[dir][bytes] : { timings: [], // count all measurements with same bytes and direction numMeasurements: _classPrivateFieldGet2(_measurements, this).filter(function (_ref6) { var b = _ref6.bytes, d = _ref6.dir; return bytes === b && dir === d; }).map(function (m) { return m.count; }).reduce(function (agg, cnt) { return agg + cnt; }, 0) }; !!measTiming && bytesResult.timings.push(measTiming); bytesResult.timings = bytesResult.timings.slice(-bytesResult.numMeasurements); results[dir][bytes] = bytesResult; if (measTiming) { setTimeout(function () { _classPrivateFieldGet2(_onMeasurementResult, _this2).call(_this2, _objectSpread2({ type: dir, bytes: bytes }, measTiming), results); }); } else { _classPrivateFieldGet2(_onNewMeasurementStarted, this).call(this, _classPrivateFieldGet2(_measurements, this)[measIdx], results); } } function _nextMeasurement() { var _this3 = this; var measurements = _classPrivateFieldGet2(_measurements, this); var meas = measurements[_classPrivateFieldGet2(_measIdx, this)]; if (_classPrivateFieldGet2(_counter, this) >= meas.count) { // Finished current measurement var finished = _classPrivateFieldGet2(_finished$1, this); if (_classPrivateFieldGet2(_minDuration, this) > this.finishRequestDuration && !meas.bypassMinDuration) { // mark direction as finished var _dir = meas.dir; _classPrivateFieldGet2(_finished$1, this)[_dir] = true; Object.values(_classPrivateFieldGet2(_finished$1, this)).every(function (finished) { return finished; }) && _classPrivateFieldGet2(_onFinished$1, this).call(this, _classPrivateFieldGet2(_results$1, this)); } // clear settings _classPrivateFieldSet2(_counter, this, 0); _classPrivateFieldSet2(_minDuration, this, -Infinity); performance.clearResourceTimings(); do { _classPrivateFieldSet2(_measIdx, this, _classPrivateFieldGet2(_measIdx, this) + 1); // skip through finished measurements } while (_classPrivateFieldGet2(_measIdx, this) < measurements.length && finished[measurements[_classPrivateFieldGet2(_measIdx, this)].dir]); if (_classPrivateFieldGet2(_measIdx, this) >= measurements.length) { // reached the end: halt further measurements _classPrivateFieldSet2(_finished$1, this, { down: true, up: true }); _assertClassBrand(_BandwidthMeasurementEngine_brand, this, _setRunning$2).call(this, false); _classPrivateFieldGet2(_onFinished$1, this).call(this, _classPrivateFieldGet2(_results$1, this)); return; } meas = measurements[_classPrivateFieldGet2(_measIdx, this)]; } var measIdx = _classPrivateFieldGet2(_measIdx, this); if (_classPrivateFieldGet2(_counter, this) === 0) { _assertClassBrand(_BandwidthMeasurementEngine_brand, this, _saveMeasurementResults).call(this, measIdx); // register measurement start } var _meas = meas, numBytes = _meas.bytes, dir = _meas.dir; var isDown = dir === 'down'; var apiUrl = isDown ? _classPrivateFieldGet2(_downloadApi, this) : _classPrivateFieldGet2(_uploadApi, this); var qsParams = Object.assign({}, _classPrivateFieldGet2(_qsParams, this)); isDown && (qsParams.bytes = "".concat(numBytes)); var url = "".concat(apiUrl.startsWith('http') || apiUrl.startsWith('//') ? '' : window.location.origin // use abs to match perf timing urls ).concat(apiUrl, "?").concat(Object.entries(qsParams).map(function (_ref7) { var _ref8 = _slicedToArray(_ref7, 2), k = _ref8[0], v = _ref8[1]; return "".concat(k, "=").concat(v); }).join('&')); var fetchOpt = Object.assign({}, isDown ? {} : { method: 'POST', body: genContent(numBytes) }, _classPrivateFieldGet2(_fetchOptions, this)); var serverTime; var curPromise = _classPrivateFieldSet2(_currentFetchPromise, this, fetch(url, fetchOpt).then(function (r) { if (r.ok) return r; throw Error(r.statusText); }).then(function (r) { _this3.getServerTime && (serverTime = _this3.getServerTime(r)); return r; }).then(function (r) { return r.text().then(function (body) { _classPrivateFieldGet2(_responseHook, _this3) && _classPrivateFieldGet2(_responseHook, _this3).call(_this3, { url: url, headers: r.headers, body: body }); return body; }); }).then(function (_, reject) { if (curPromise._cancel) { reject('cancelled'); return; } var perf = performance.getEntriesByName(url).slice(-1)[0]; // get latest perf timing var timing = { transferSize: perf.transferSize, ttfb: getTtfb(perf), payloadDownloadTime: gePayloadDownload(perf), serverTime: serverTime || -1, measTime: new Date() }; timing.ping = Math.max(1e-2, timing.ttfb - (serverTime || _classPrivateFieldGet2(_estimatedServerTime, _this3))); // ttfb = network latency + server time timing.duration = (isDown ? calcDownloadDuration : calcUploadDuration)(timing); timing.bps = (isDown ? calcDownloadSpeed : calcUploadSpeed)(timing, numBytes); if (isDown && numBytes) { var reqSize = +numBytes; if (timing.transferSize && (timing.transferSize < reqSize || timing.transferSize / reqSize > 1.05)) { // log if transferSize is too different from requested size console.warn("Requested ".concat(reqSize, "B but received ").concat(timing.transferSize, "B (").concat(Math.round(timing.transferSize / reqSize * 1e4) / 1e2, "%).")); } } _assertClassBrand(_BandwidthMeasurementEngine_brand, _this3, _saveMeasurementResults).call(_this3, measIdx, timing); var requestDuration = timing.duration; _classPrivateFieldSet2(_minDuration, _this3, _classPrivateFieldGet2(_minDuration, _this3) < 0 ? requestDuration : Math.min(_classPrivateFieldGet2(_minDuration, _this3), requestDuration)); // carry minimum request duration _classPrivateFieldSet2(_counter, _this3, _classPrivateFieldGet2(_counter, _this3) + 1); _classPrivateFieldSet2(_retries, _this3, 0); if (_classPrivateFieldGet2(_throttleMs, _this3)) { _classPrivateFieldSet2(_currentNextMsmTimeoutId, _this3, setTimeout(function () { return _assertClassBrand(_BandwidthMeasurementEngine_brand, _this3, _nextMeasurement).call(_this3); }, _classPrivateFieldGet2(_throttleMs, _this3))); } else { _assertClassBrand(_BandwidthMeasurementEngine_brand, _this3, _nextMeasurement).call(_this3); } })["catch"](function (error) { var _this$retries, _this$retries2; if (curPromise._cancel) return; console.warn("Error fetching ".concat(url, ": ").concat(error)); if ((_classPrivateFieldSet2(_retries, _this3, (_this$retries = _classPrivateFieldGet2(_retries, _this3), _this$retries2 = _this$retries++, _this$retries)), _this$retries2) < MAX_RETRIES) { _assertClassBrand(_BandwidthMeasurementEngine_brand, _this3, _nextMeasurement).call(_this3); // keep trying } else { _classPrivateFieldSet2(_retries, _this3, 0); _assertClassBrand(_BandwidthMeasurementEngine_brand, _this3, _setRunning$2).call(_this3, false); _classPrivateFieldGet2(_onConnectionError$1, _this3).call(_this3, "Connection failed to ".concat(url, ". Gave up after ").concat(MAX_RETRIES, " retries.")); } })); } function _cancelCurrentMeasurement() { var curPromise = _classPrivateFieldGet2(_currentFetchPromise, this); curPromise && (curPromise._cancel = true); } var _excluded$5 = ["measureParallelLatency", "parallelLatencyThrottleMs", "downloadApiUrl", "uploadApiUrl", "estimatedServerTime"]; var _latencyEngine = /*#__PURE__*/new WeakMap(); var _latencyTimeout = /*#__PURE__*/new WeakMap(); var _BandwidthWithParallelLatencyEngine_brand = /*#__PURE__*/new WeakSet(); var BandwidthWithParallelLatencyEngine = /*#__PURE__*/function (_BandwidthEngine) { function BandwidthWithParallelLatencyEngine(measurements) { var _this; var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref$measureParallelL = _ref.measureParallelLatency, measureParallelLatency = _ref$measureParallelL === void 0 ? false : _ref$measureParallelL, _ref$parallelLatencyT = _ref.parallelLatencyThrottleMs, parallelLatencyThrottleMs = _ref$parallelLatencyT === void 0 ? 100 : _ref$parallelLatencyT, downloadApiUrl = _ref.downloadApiUrl, uploadApiUrl = _ref.uploadApiUrl, _ref$estimatedServerT = _ref.estimatedServerTime, estimatedServerTime = _ref$estimatedServerT === void 0 ? 0 : _ref$estimatedServerT, ptProps = _objectWithoutProperties(_ref, _excluded$5); _classCallCheck(this, BandwidthWithParallelLatencyEngine); _this = _callSuper(this, BandwidthWithParallelLatencyEngine, [measurements, _objectSpread2({ downloadApiUrl: downloadApiUrl, uploadApiUrl: uploadApiUrl, estimatedServerTime: estimatedServerTime }, ptProps)]); // Internal methods _classPrivateMethodInitSpec(_this, _BandwidthWithParallelLatencyEngine_brand); // Internal state _classPrivateFieldInitSpec(_this, _latencyEngine, void 0); _classPrivateFieldInitSpec(_this, _latencyTimeout, void 0); if (measureParallelLatency) { _classPrivateFieldSet2(_latencyEngine, _this, new BandwidthMeasurementEngine([{ dir: 'down', bytes: 0, count: Infinity, bypassMinDuration: true }], { downloadApiUrl: downloadApiUrl, uploadApiUrl: uploadApiUrl, estimatedServerTime: estimatedServerTime, throttleMs: parallelLatencyThrottleMs })); _classPrivateFieldGet2(_latencyEngine, _this).qsParams = { during: "".concat(measurements[0].dir, "load") }; _superPropSet((BandwidthWithParallelLatencyEngine), "onRunningChange", _assertClassBrand(_BandwidthWithParallelLatencyEngine_brand, _this, _setLatencyRunning), _this, 1); _superPropSet((BandwidthWithParallelLatencyEngine), "onConnectionError", function () { return _classPrivateFieldGet2(_latencyEngine, _this).pause(); }, _this, 1); } return _this; } // Public attributes _inherits(BandwidthWithParallelLatencyEngine, _BandwidthEngine); return _createClass(BandwidthWithParallelLatencyEngine, [{ key: "latencyResults", get: function get() { // read access to latency results return _classPrivateFieldGet2(_latencyEngine, this) && _classPrivateFieldGet2(_latencyEngine, this).results.down[0].timings; } // callback invoked when a new parallel latency result arrives }, { key: "onParallelLatencyResult", set: function set(f) { _classPrivateFieldGet2(_latencyEngine, this) && (_classPrivateFieldGet2(_latencyEngine, this).onMeasurementResult = function (res) { return f(res); }); } // Overridden attributes }, { key: "fetchOptions", get: function get() { return _superPropGet(BandwidthWithParallelLatencyEngine, "fetchOptions", this, 1); }, set: function set(fetchOptions) { _superPropSet(BandwidthWithParallelLatencyEngine, "fetchOptions", fetchOptions, this, 1); _classPrivateFieldGet2(_latencyEngine, this) && (_classPrivateFieldGet2(_latencyEngine, this).fetchOptions = fetchOptions); } }, { key: "onRunningChange", set: function set(onRunningChange) { var _this2 = this; _superPropSet(BandwidthWithParallelLatencyEngine, "onRunningChange", function (running) { _assertClassBrand(_BandwidthWithParallelLatencyEngine_brand, _this2, _setLatencyRunning).call(_this2, running); onRunningChange(running); }, this, 1); } }, { key: "onConnectionError", set: function set(onConnectionError) { var _this3 = this; _superPropSet(BandwidthWithParallelLatencyEngine, "onConnectionError", function () { _classPrivateFieldGet2(_latencyEngine, _this3) && _classPrivateFieldGet2(_latencyEngine, _this3).pause(); onConnectionError.apply(void 0, arguments); }, this, 1); } }]); }(BandwidthMeasurementEngine); function _setLatencyRunning(running) { var _this4 = this; if (_classPrivateFieldGet2(_latencyEngine, this)) { if (!running) { clearTimeout(_classPrivateFieldGet2(_latencyTimeout, this)); _classPrivateFieldGet2(_latencyEngine, this).pause(); } else { // slight delay in starting latency measurements _classPrivateFieldSet2(_latencyTimeout, this, setTimeout(function () { return _classPrivateFieldGet2(_latencyEngine, _this4).play(); }, 20)); } } } var _excluded$4 = ["measurementId", "logApiUrl", "sessionId"]; var _measurementId$1 = /*#__PURE__*/new WeakMap(); var _token = /*#__PURE__*/new WeakMap(); var _requestTime = /*#__PURE__*/new WeakMap(); var _logApiUrl = /*#__PURE__*/new WeakMap(); var _sessionId$1 = /*#__PURE__*/new WeakMap(); var _LoggingBandwidthEngine_brand = /*#__PURE__*/new WeakSet(); var LoggingBandwidthEngine = /*#__PURE__*/function (_BandwidthEngine) { function LoggingBandwidthEngine(measurements) { var _this; var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, measurementId = _ref.measurementId, logApiUrl = _ref.logApiUrl, sessionId = _ref.sessionId, ptProps = _objectWithoutProperties(_ref, _excluded$4); _classCallCheck(this, LoggingBandwidthEngine); _this = _callSuper(this, LoggingBandwidthEngine, [measurements, ptProps]); // Internal methods _classPrivateMethodInitSpec(_this, _LoggingBandwidthEngine_brand); // Internal state _classPrivateFieldInitSpec(_this, _measurementId$1, void 0); _classPrivateFieldInitSpec(_this, _token, void 0); _classPrivateFieldInitSpec(_this, _requestTime, void 0); _classPrivateFieldInitSpec(_this, _logApiUrl, void 0); _classPrivateFieldInitSpec(_this, _sessionId$1, void 0); _classPrivateFieldSet2(_measurementId$1, _this, measurementId); _classPrivateFieldSet2(_logApiUrl, _this, logApiUrl); _classPrivateFieldSet2(_sessionId$1, _this, sessionId); _superPropSet((LoggingBandwidthEngine), "qsParams", logApiUrl ? { measId: _classPrivateFieldGet2(_measurementId$1, _this) } : {}, _this, 1); _superPropSet((LoggingBandwidthEngine), "responseHook", function (r) { return _assertClassBrand(_LoggingBandwidthEngine_brand, _this, _loggingResponseHook).call(_this, r); }, _this, 1); _superPropSet((LoggingBandwidthEngine), "onMeasurementResult", function (meas) { return _assertClassBrand(_LoggingBandwidthEngine_brand, _this, _logMeasurement).call(_this, meas); }, _this, 1); return _this; } // Overridden attributes _inherits(LoggingBandwidthEngine, _BandwidthEngine); return _createClass(LoggingBandwidthEngine, [{ key: "qsParams", set: function set(qsParams) { _superPropSet(LoggingBandwidthEngine, "qsParams", _classPrivateFieldGet2(_logApiUrl, this) ? _objectSpread2({ measId: _classPrivateFieldGet2(_measurementId$1, this) }, qsParams) : qsParams, this, 1); } }, { key: "responseHook", set: function set(responseHook) { var _this2 = this; _superPropSet(LoggingBandwidthEngine, "responseHook", function (r) { responseHook(r); _assertClassBrand(_LoggingBandwidthEngine_brand, _this2, _loggingResponseHook).call(_this2, r); }, this, 1); } }, { key: "onMeasurementResult", set: function set(onMeasurementResult) { var _this3 = this; _superPropSet(LoggingBandwidthEngine, "onMeasurementResult", function (meas) { for (var _len = arguments.length, restArgs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { restArgs[_key - 1] = arguments[_key]; } onMeasurementResult.apply(void 0, [meas].concat(restArgs)); _assertClassBrand(_LoggingBandwidthEngine_brand, _this3, _logMeasurement).call(_this3, meas); }, this, 1); } }]); }(BandwidthWithParallelLatencyEngine); function _loggingResponseHook(r) { if (!_classPrivateFieldGet2(_logApiUrl, this)) return; // get request time _classPrivateFieldSet2(_requestTime, this, +r.headers.get("cf-meta-request-time")); // get token in payload _classPrivateFieldSet2(_token, this, r.body.slice(-300).split('___').pop()); } function _logMeasurement(measData) { if (!_classPrivateFieldGet2(_logApiUrl, this)) return; var logData = { type: measData.type, bytes: measData.bytes, ping: Math.round(measData.ping), // round to ms ttfb: Math.round(measData.ttfb), // round to ms payloadDownloadTime: Math.round(measData.payloadDownloadTime), duration: Math.round(measData.duration), transferSize: Math.round(measData.transferSize), serverTime: Math.round(measData.serverTime), token: _classPrivateFieldGet2(_token, this), requestTime: _classPrivateFieldGet2(_requestTime, this), measId: _classPrivateFieldGet2(_measurementId$1, this), sessionId: _classPrivateFieldGet2(_sessionId$1, this) }; _classPrivateFieldSet2(_token, this, null); _classPrivateFieldSet2(_requestTime, this, null); fetch(_classPrivateFieldGet2(_logApiUrl, this), _objectSpread2({ method: 'POST', body: JSON.stringify(logData) }, this.fetchOptions)); } var _running$1 = /*#__PURE__*/new WeakMap(); var _currentPromise = /*#__PURE__*/new WeakMap(); var _promiseFn = /*#__PURE__*/new WeakMap(); var _PromiseEngine_brand = /*#__PURE__*/new WeakSet(); var PromiseEngine = /*#__PURE__*/function () { function PromiseEngine(promiseFn) { _classCallCheck(this, PromiseEngine); // Internal methods _classPrivateMethodInitSpec(this, _PromiseEngine_brand); // Internal state _classPrivateFieldInitSpec(this, _running$1, false); _classPrivateFieldInitSpec(this, _currentPromise, undefined); _classPrivateFieldInitSpec(this, _promiseFn, void 0); if (!promiseFn) throw new Error("Missing operation to perform"); _classPrivateFieldSet2(_promiseFn, this, promiseFn); this.play(); } // Public methods return _createClass(PromiseEngine, [{ key: "pause", value: function pause() { _assertClassBrand(_PromiseEngine_brand, this, _cancelCurrent).call(this); _assertClassBrand(_PromiseEngine_brand, this, _setRunning$1).call(this, false); } }, { key: "stop", value: function stop() { this.pause(); } }, { key: "play", value: function play() { if (!_classPrivateFieldGet2(_running$1, this)) { _assertClassBrand(_PromiseEngine_brand, this, _setRunning$1).call(this, true); _assertClassBrand(_PromiseEngine_brand, this, _next$1).call(this); } } }]); }(); function _setRunning$1(running) { if (running !== _classPrivateFieldGet2(_running$1, this)) { _classPrivateFieldSet2(_running$1, this, running); } } function _next$1() { var _this2 = this; var curPromise = _classPrivateFieldSet2(_currentPromise, this, _classPrivateFieldGet2(_promiseFn, this).call(this).then(function () { !curPromise._cancel && _assertClassBrand(_PromiseEngine_brand, _this2, _next$1).call(_this2); })); } function _cancelCurrent() { var curPromise = _classPrivateFieldGet2(_currentPromise, this); curPromise && (curPromise._cancel = true); } var _engines = /*#__PURE__*/new WeakMap(); var LoadNetworkEngine = /*#__PURE__*/function () { function LoadNetworkEngine() { var _this = this; var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, download = _ref.download, upload = _ref.upload; _classCallCheck(this, LoadNetworkEngine); // Public attributes _defineProperty(this, "qsParams", {}); // additional query string params to include in the requests _defineProperty(this, "fetchOptions", {}); // Internal state _classPrivateFieldInitSpec(this, _engines, []); // Expected attrs for each: { apiUrl, chunkSize } if (!download && !upload) throw new Error('Missing at least one of download/upload config'); [[download, 'download'], [upload, 'upload']].filter(function (_ref2) { var _ref3 = _slicedToArray(_ref2, 1), cfg = _ref3[0]; return cfg; }).forEach(function (_ref4) { var _ref5 = _slicedToArray(_ref4, 2), cfg = _ref5[0], type = _ref5[1]; var apiUrl = cfg.apiUrl, chunkSize = cfg.chunkSize; if (!apiUrl) throw new Error("Missing ".concat(type, " apiUrl argument")); if (!chunkSize) throw new Error("Missing ".concat(type, " chunkSize argument")); }); var getLoadEngine = function getLoadEngine(_ref6) { var apiUrl = _ref6.apiUrl, _ref6$qsParams = _ref6.qsParams, qsParams = _ref6$qsParams === void 0 ? {} : _ref6$qsParams, _ref6$fetchOptions = _ref6.fetchOptions, fetchOptions = _ref6$fetchOptions === void 0 ? {} : _ref6$fetchOptions; return new PromiseEngine(function () { var fetchQsParams = Object.assign({}, qsParams, _this.qsParams); var url = "".concat(apiUrl.startsWith('http') || apiUrl.startsWith('//') ? '' : window.location.origin // use abs to match perf timing urls ).concat(apiUrl, "?").concat(Object.entries(fetchQsParams).map(function (_ref7) { var _ref8 = _slicedToArray(_ref7, 2), k = _ref8[0], v = _ref8[1]; return "".concat(k, "=").concat(v); }).join('&')); var fetchOpt = Object.assign({}, fetchOptions, _this.fetchOptions); return fetch(url, fetchOpt).then(function (r) { if (r.ok) return r; throw Error(r.statusText); }).then(function (r) { return r.text(); }); }); }; download && _classPrivateFieldGet2(_engines, this).push(getLoadEngine({ apiUrl: download.apiUrl, qsParams: { bytes: "".concat(download.chunkSize) } })); upload && _classPrivateFieldGet2(_engines, this).push(getLoadEngine({ apiUrl: upload.apiUrl, fetchOptions: { method: 'POST', body: '0'.repeat(upload.chunkSize) } })); } return _createClass(LoadNetworkEngine, [{ key: "pause", value: // additional options included in the requests // Public methods function pause() { _classPrivateFieldGet2(_engines, this).forEach(function (engine) { return engine.pause(); }); } }, { key: "stop", value: function stop() { this.pause(); } }, { key: "play", value: function play() { _classPrivateFieldGet2(_engines, this).forEach(function (engine) { return engine.play(); }); } }]); }(); var _excluded$3 = ["iceServers", "acceptIceCandidate", "dataChannelCfg"]; var _established = /*#__PURE__*/new WeakMap(); var _sender = /*#__PURE__*/new WeakMap(); var _receiver = /*#__PURE__*/new WeakMap(); var _senderDc = /*#__PURE__*/new WeakMap(); var _receiverDc = /*#__PURE__*/new WeakMap(); var SelfWebRtcDataConnection = /*#__PURE__*/function () { function SelfWebRtcDataConnection() { var _this = this; var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$iceServers = _ref.iceServers, iceServers = _ref$iceServers === void 0 ? [] : _ref$iceServers, _ref$acceptIceCandida = _ref.acceptIceCandidate, acceptIceCandidate = _ref$acceptIceCandida === void 0 ? function (candidate) { var protocol = candidate.protocol || ''; // parsed webRTC candidate properties not extracted in Firefox: https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate if (!protocol && candidate.candidate) { var sdpAttrs = candidate.candidate.split(' '); sdpAttrs.length >= 3 && (protocol = sdpAttrs[2]); } return protocol.toLowerCase() === 'udp'; } : _ref$acceptIceCandida, _ref$dataChannelCfg = _ref.dataChannelCfg, dataChannelCfg = _ref$dataChannelCfg === void 0 ? { ordered: false, maxRetransmits: 0 } : _ref$dataChannelCfg, rtcPeerConnectionCfg = _objectWithoutProperties(_ref, _excluded$3); _classCallCheck(this, SelfWebRtcDataConnection); // Public attributes _defineProperty(this, "onOpen", function () {}); // callback invoked when WebRTC TURN connection is established _defineProperty(this, "onClose", function () {}); // callback invoked when WebRTC TURN connection is closed _defineProperty(this, "onMessageReceived", function () {}); // Internal state _classPrivateFieldInitSpec(this, _established, false); _classPrivateFieldInitSpec(this, _sender, void 0); _classPrivateFieldInitSpec(this, _receiver, void 0); _classPrivateFieldInitSpec(this, _senderDc, void 0); _classPrivateFieldInitSpec(this, _receiverDc, void 0); var sender = new RTCPeerConnection(_objectSpread2({ iceServers: iceServers }, rtcPeerConnectionCfg)); var receiver = new RTCPeerConnection(_objectSpread2({ iceServers: iceServers }, rtcPeerConnectionCfg)); var senderDc = sender.createDataChannel('channel', dataChannelCfg); senderDc.onopen = function () { _classPrivateFieldSet2(_established, _this, true); _this.onOpen(); }; senderDc.onclose = function () { return _this.close(); }; // senderDc.onmessage = msg => this.#onMessage(msg.data); receiver.ondatachannel = function (e) { var dc = e.channel; dc.onclose = function () { return _this.close(); }; dc.onmessage = function (msg) { return _this.onMessageReceived(msg.data); }; _classPrivateFieldSet2(_receiverDc, _this, dc); }; // sender.onconnectionstatechange = e => console.log('connection state change', e); // sender.oniceconnectionstatechange = e => console.log('ice connection state change', e); // sender.onicecandidateerror = e => console.log('ice error', e); sender.onicecandidate = function (e) { // console.log('sender', e.candidate); e.candidate && acceptIceCandidate(e.candidate) && receiver.addIceCandidate(e.candidate); }; receiver.onicecandidate = function (e) { // console.log('receiver', e.candidate); e.candidate && acceptIceCandidate(e.candidate) && sender.addIceCandidate(e.candidate); }; sender.createOffer().then(function (offer) { return sender.setLocalDescription(offer); }).then(function () { return receiver.setRemoteDescription(sender.localDescription); }).then(function () { return receiver.createAnswer(); }).then(function (answer) { return receiver.setLocalDescription(answer); }).then(function () { return sender.setRemoteDescription(receiver.localDescription); }); _classPrivateFieldSet2(_sender, this, sender); _classPrivateFieldSet2(_receiver, this, receiver); _classPrivateFieldSet2(_senderDc, this, senderDc); _classPrivateFieldSet2(_established, this, false); } return _createClass(SelfWebRtcDataConnection, [{ key: "send", value: // callback invoked when a new message is received from the TURN server // Public methods function send(msg) { return _classPrivateFieldGet2(_senderDc, this).send(msg); } }, { key: "close", value: function close() { _classPrivateFieldGet2(_sender, this) && _classPrivateFieldGet2(_sender, this).close(); _classPrivateFieldGet2(_receiver, this) && _classPrivateFieldGet2(_receiver, this).close(); _classPrivateFieldGet2(_senderDc, this) && _classPrivateFieldGet2(_senderDc, this).close(); _classPrivateFieldGet2(_receiverDc, this) && _classPrivateFieldGet2(_receiverDc, this).close(); _classPrivateFieldGet2(_established, this) && this.onClose(); _classPrivateFieldSet2(_established, this, false); return this; } }]); }(); var _onCredentialsFailure = /*#__PURE__*/new WeakMap(); var _onConnectionError = /*#__PURE__*/new WeakMap(); var _onFinished = /*#__PURE__*/new WeakMap(); var _msgTracker = /*#__PURE__*/new WeakMap(); var _webRtcConnection = /*#__PURE__*/new WeakMap(); var _numMsgs = /*#__PURE__*/new WeakMap(); var PacketLossEngine = /*#__PURE__*/function () { function PacketLossEngine() { var _this = this; var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, turnServerUri = _ref.turnServerUri, turnServerCredsApi = _ref.turnServerCredsApi, _ref$turnServerCredsA = _ref.turnServerCredsApiParser, turnServerCredsApiParser = _ref$turnServerCredsA === void 0 ? func