UNPKG

p2p-media-loader-core

Version:
1,537 lines 108 kB
//#region \0rolldown/runtime.js var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), s = (e, n) => { let r = {}; for (var i in e) t(r, i, { get: e[i], enumerable: !0 }); return n || t(r, Symbol.toStringTag, { value: "Module" }), r; }, c = (e, i, o, s) => { if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, { get: ((e) => i[e]).bind(null, d), enumerable: !(s = n(i, d)) || s.enumerable }); return e; }, l = (n, r, a) => (a = n == null ? {} : e(i(n)), c(r || !n || !n.__esModule ? t(a, "default", { value: n, enumerable: !0 }) : a, n)), u = class extends Error { type; cause; constructor(e, t, n) { super(t), this.type = e, this.cause = n; } }, d = class extends u { name = "PeerError"; }, f = class extends u { name = "PeerWarning"; }, p = class extends u { name = "TrackerError"; }, m = class extends u { name = "TrackerWarning"; }, h = class extends u { name = "PeerConnectError"; }, g = class extends u { name = "RequestError"; timestamp; constructor(e, t, n) { super(e, t, n), this.timestamp = performance.now(); } }, _ = class extends u { name = "CoreRequestError"; }, ee = class { aborted = !1; #e = /* @__PURE__ */ new Set(); addEventListener(e, t) { this.#e.add(t); } removeEventListener(e, t) { this.#e.delete(t); } dispatchEvent(e) { this.aborted = !0; for (let e of this.#e) try { e(); } catch {} this.#e.clear(); } }, te = class { signal = new ee(); abort() { this.signal.dispatchEvent("abort"); } }, ne = typeof AbortController < "u", re = ne ? AbortController : te, ie = class { request; httpConfig; abortController = new re(); expectedBytesLength; requestByteRange; onChunkDownloaded; isAborted() { return this.abortController.signal.aborted; } constructor(e, t, n) { this.request = e, this.httpConfig = t, this.onChunkDownloaded = n.getEventDispatcher("onChunkDownloaded"); let { byteRange: r } = this.request.segment; r && (this.requestByteRange = { ...r }); } execute() { let e = { onAbort: () => this.abortController.abort(), notReceivingBytesTimeoutMs: this.httpConfig.httpNotReceivingBytesTimeoutMs }; if (this.request.tryCompleteByLoadedBytes({ downloadSource: "http" }, e, this.httpConfig.validateHTTPSegment, "http-segment-validation-failed")) return; this.request.loadedBytes !== 0 && (this.requestByteRange = this.requestByteRange ?? { start: 0 }, this.requestByteRange.start = this.requestByteRange.start + this.request.loadedBytes), this.request.totalBytes && (this.expectedBytesLength = this.request.totalBytes - this.request.loadedBytes); let t = this.request.start({ downloadSource: "http" }, e); this.fetch(t); } async fetch(e) { let { segment: t } = this.request, n; if (this.isAborted()) return; let r = () => { try { n?.cancel().catch(() => {}); } catch {} }; this.abortController.signal.addEventListener("abort", r); let i = ne ? this.abortController.signal : void 0; try { let r = await this.httpConfig.httpRequestSetup?.(t.url, t.byteRange, i, this.requestByteRange); if (this.isAborted()) throw new DOMException("Request aborted", "AbortError"); if (!r) { let e = new Headers(); this.requestByteRange && e.set("Range", `bytes=${this.requestByteRange.start}-${this.requestByteRange.end ?? ""}`); let n = { headers: e }; i && (n.signal = i), r = new Request(t.url, n); } if (this.isAborted()) throw new DOMException("Request aborted before request fetch", "AbortError"); let a = await window.fetch(r); if (this.isAborted()) throw new DOMException("Request aborted", "AbortError"); if (this.handleResponseHeaders(a), e.firstBytesReceived(), !a.body || typeof a.body.getReader != "function") { let n = await a.arrayBuffer(); if (this.isAborted()) throw new DOMException("Request aborted", "AbortError"); let r = new Uint8Array(n); e.addLoadedChunk(r), this.onChunkDownloaded(r.byteLength, "http", void 0, t.stream.type, this.request.infoHash); } else { let r = a.body.getReader(); for (n = r;;) { if (this.isAborted()) throw new DOMException("Request aborted", "AbortError"); let { done: n, value: i } = await r.read(); if (n) break; if (this.isAborted()) throw new DOMException("Request aborted", "AbortError"); e.addLoadedChunk(i), this.onChunkDownloaded(i.byteLength, "http", void 0, t.stream.type, this.request.infoHash); } } if (this.isAborted()) throw new DOMException("Request aborted", "AbortError"); if (this.request.totalBytes !== void 0 && this.request.loadedBytes !== this.request.totalBytes) throw new g("http-bytes-mismatch", `HTTP response truncated: received ${this.request.loadedBytes} of ${this.request.totalBytes} bytes`); let o = await this.request.validateData(this.httpConfig.validateHTTPSegment); if (this.isAborted()) throw new DOMException("Request aborted", "AbortError"); if (!o) throw this.request.clearLoadedBytes(), new g("http-segment-validation-failed"); e.completeOnSuccess(); } catch (t) { this.handleError(t, e); } finally { this.abortController.signal.removeEventListener("abort", r); } } handleResponseHeaders(e) { if (!e.ok) throw e.status === 406 || e.status === 416 ? (this.request.clearLoadedBytes(), new g("http-bytes-mismatch", e.statusText)) : new g("http-error", e.statusText); let { requestByteRange: t } = this; if (t) if (e.status === 200) { if (this.request.segment.byteRange) throw new g("http-unexpected-status-code"); this.request.clearLoadedBytes(); } else { if (e.status !== 206) throw new g("http-unexpected-status-code", e.statusText); let n = e.headers.get("Content-Length"); if (n && this.expectedBytesLength !== void 0 && this.expectedBytesLength !== +n) throw this.request.clearLoadedBytes(), new g("http-bytes-mismatch", e.statusText); let r = e.headers.get("Content-Range"), i = r ? oe(r) : void 0; if (i) { let { from: n, to: r } = i, a = r !== void 0 && n !== void 0 ? r - n + 1 : void 0; if (a !== void 0 && this.expectedBytesLength !== a || n !== void 0 && t.start !== n || r !== void 0 && t.end !== void 0 && t.end !== r) throw this.request.clearLoadedBytes(), new g("http-bytes-mismatch", e.statusText); } } if (e.status === 200 && this.request.totalBytes === void 0) { let t = e.headers.get("Content-Length"); t && this.request.setTotalBytes(+t); } } handleError(e, t) { if (!this.isAborted() && e instanceof Error) { let n = e instanceof g ? e : new g("http-error", e.message); t.failWithError(n); } } }, ae = /^bytes (?:(?:(\d+)|)-(?:(\d+)|)|\*)\/(?:(\d+)|\*)$/; function oe(e) { let t = ae.exec(e.trim()); if (!t) return; let [, n, r, i] = t; return { from: n ? parseInt(n) : void 0, to: r ? parseInt(r) : void 0, total: i ? parseInt(i) : void 0 }; } //#endregion //#region ../../node_modules/.pnpm/ms@2.1.3/node_modules/ms/index.js var se = /* @__PURE__ */ o(((e, t) => { var n = 1e3, r = n * 60, i = r * 60, a = i * 24, o = a * 7, s = a * 365.25; t.exports = function(e, t) { t ||= {}; var n = typeof e; if (n === "string" && e.length > 0) return c(e); if (n === "number" && isFinite(e)) return t.long ? u(e) : l(e); throw Error("val is not a non-empty string or a valid number. val=" + JSON.stringify(e)); }; function c(e) { if (e = String(e), !(e.length > 100)) { var t = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e); if (t) { var c = parseFloat(t[1]); switch ((t[2] || "ms").toLowerCase()) { case "years": case "year": case "yrs": case "yr": case "y": return c * s; case "weeks": case "week": case "w": return c * o; case "days": case "day": case "d": return c * a; case "hours": case "hour": case "hrs": case "hr": case "h": return c * i; case "minutes": case "minute": case "mins": case "min": case "m": return c * r; case "seconds": case "second": case "secs": case "sec": case "s": return c * n; case "milliseconds": case "millisecond": case "msecs": case "msec": case "ms": return c; default: return; } } } } function l(e) { var t = Math.abs(e); return t >= a ? Math.round(e / a) + "d" : t >= i ? Math.round(e / i) + "h" : t >= r ? Math.round(e / r) + "m" : t >= n ? Math.round(e / n) + "s" : e + "ms"; } function u(e) { var t = Math.abs(e); return t >= a ? d(e, t, a, "day") : t >= i ? d(e, t, i, "hour") : t >= r ? d(e, t, r, "minute") : t >= n ? d(e, t, n, "second") : e + " ms"; } function d(e, t, n, r) { var i = t >= n * 1.5; return Math.round(e / n) + " " + r + (i ? "s" : ""); } })), ce = /* @__PURE__ */ o(((e, t) => { function n(e) { n.debug = n, n.default = n, n.coerce = c, n.disable = o, n.enable = i, n.enabled = s, n.humanize = se(), n.destroy = l, Object.keys(e).forEach((t) => { n[t] = e[t]; }), n.names = [], n.skips = [], n.formatters = {}; function t(e) { let t = 0; for (let n = 0; n < e.length; n++) t = (t << 5) - t + e.charCodeAt(n), t |= 0; return n.colors[Math.abs(t) % n.colors.length]; } n.selectColor = t; function n(e) { let t, i = null, a, o; function s(...e) { if (!s.enabled) return; let r = s, i = Number(/* @__PURE__ */ new Date()); r.diff = i - (t || i), r.prev = t, r.curr = i, t = i, e[0] = n.coerce(e[0]), typeof e[0] != "string" && e.unshift("%O"); let a = 0; e[0] = e[0].replace(/%([a-zA-Z%])/g, (t, i) => { if (t === "%%") return "%"; a++; let o = n.formatters[i]; if (typeof o == "function") { let n = e[a]; t = o.call(r, n), e.splice(a, 1), a--; } return t; }), n.formatArgs.call(r, e), (r.log || n.log).apply(r, e); } return s.namespace = e, s.useColors = n.useColors(), s.color = n.selectColor(e), s.extend = r, s.destroy = n.destroy, Object.defineProperty(s, "enabled", { enumerable: !0, configurable: !1, get: () => i === null ? (a !== n.namespaces && (a = n.namespaces, o = n.enabled(e)), o) : i, set: (e) => { i = e; } }), typeof n.init == "function" && n.init(s), s; } function r(e, t) { let r = n(this.namespace + (t === void 0 ? ":" : t) + e); return r.log = this.log, r; } function i(e) { n.save(e), n.namespaces = e, n.names = [], n.skips = []; let t = (typeof e == "string" ? e : "").trim().replace(/\s+/g, ",").split(",").filter(Boolean); for (let e of t) e[0] === "-" ? n.skips.push(e.slice(1)) : n.names.push(e); } function a(e, t) { let n = 0, r = 0, i = -1, a = 0; for (; n < e.length;) if (r < t.length && (t[r] === e[n] || t[r] === "*")) t[r] === "*" ? (i = r, a = n, r++) : (n++, r++); else if (i !== -1) r = i + 1, a++, n = a; else return !1; for (; r < t.length && t[r] === "*";) r++; return r === t.length; } function o() { let e = [...n.names, ...n.skips.map((e) => "-" + e)].join(","); return n.enable(""), e; } function s(e) { for (let t of n.skips) if (a(e, t)) return !1; for (let t of n.names) if (a(e, t)) return !0; return !1; } function c(e) { return e instanceof Error ? e.stack || e.message : e; } function l() { console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."); } return n.enable(n.load()), n; } t.exports = n; })), v = /* @__PURE__ */ l((/* @__PURE__ */ o(((e, t) => { e.formatArgs = r, e.save = i, e.load = a, e.useColors = n, e.storage = o(), e.destroy = (() => { let e = !1; return () => { e || (e = !0, console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")); }; })(), e.colors = /* @__PURE__ */ "#0000CC.#0000FF.#0033CC.#0033FF.#0066CC.#0066FF.#0099CC.#0099FF.#00CC00.#00CC33.#00CC66.#00CC99.#00CCCC.#00CCFF.#3300CC.#3300FF.#3333CC.#3333FF.#3366CC.#3366FF.#3399CC.#3399FF.#33CC00.#33CC33.#33CC66.#33CC99.#33CCCC.#33CCFF.#6600CC.#6600FF.#6633CC.#6633FF.#66CC00.#66CC33.#9900CC.#9900FF.#9933CC.#9933FF.#99CC00.#99CC33.#CC0000.#CC0033.#CC0066.#CC0099.#CC00CC.#CC00FF.#CC3300.#CC3333.#CC3366.#CC3399.#CC33CC.#CC33FF.#CC6600.#CC6633.#CC9900.#CC9933.#CCCC00.#CCCC33.#FF0000.#FF0033.#FF0066.#FF0099.#FF00CC.#FF00FF.#FF3300.#FF3333.#FF3366.#FF3399.#FF33CC.#FF33FF.#FF6600.#FF6633.#FF9900.#FF9933.#FFCC00.#FFCC33".split("."); function n() { if (typeof window < "u" && window.process && (window.process.type === "renderer" || window.process.__nwjs)) return !0; if (typeof navigator < "u" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) return !1; let e; return typeof document < "u" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || typeof window < "u" && window.console && (window.console.firebug || window.console.exception && window.console.table) || typeof navigator < "u" && navigator.userAgent && (e = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(e[1], 10) >= 31 || typeof navigator < "u" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/); } function r(e) { if (e[0] = (this.useColors ? "%c" : "") + this.namespace + (this.useColors ? " %c" : " ") + e[0] + (this.useColors ? "%c " : " ") + "+" + t.exports.humanize(this.diff), !this.useColors) return; let n = "color: " + this.color; e.splice(1, 0, n, "color: inherit"); let r = 0, i = 0; e[0].replace(/%[a-zA-Z%]/g, (e) => { e !== "%%" && (r++, e === "%c" && (i = r)); }), e.splice(i, 0, n); } e.log = console.debug || console.log || (() => {}); function i(t) { try { t ? e.storage.setItem("debug", t) : e.storage.removeItem("debug"); } catch {} } function a() { let t; try { t = e.storage.getItem("debug") || e.storage.getItem("DEBUG"); } catch {} return !t && typeof process < "u" && "env" in process && (t = process.env.DEBUG), t; } function o() { try { return localStorage; } catch {} } t.exports = ce()(e); var { formatters: s } = t.exports; s.j = function(e) { try { return JSON.stringify(e); } catch (e) { return "[UnexpectedJSONParseError]: " + e.message; } }; })))(), 1), y = /* @__PURE__ */ function(e) { return e[e.SegmentsAnnouncement = 0] = "SegmentsAnnouncement", e[e.SegmentRequest = 1] = "SegmentRequest", e[e.SegmentData = 2] = "SegmentData", e[e.SegmentDataSendingCompleted = 3] = "SegmentDataSendingCompleted", e[e.SegmentAbsent = 4] = "SegmentAbsent", e[e.CancelSegmentRequest = 5] = "CancelSegmentRequest", e; }({}); //#endregion //#region src/utils/utils.ts function le() { let e, t; return { promise: new Promise((n, r) => { e = n, t = r; }), resolve: e, reject: t }; } function ue(e) { Promise.resolve().then(e); } function de(e, t) { t ??= e.reduce((e, t) => e + t.byteLength, 0); let n = new Uint8Array(t), r = 0; for (let t of e) n.set(t, r), r += t.byteLength; return n; } function fe(e) { return e[Math.floor(Math.random() * e.length)]; } function pe(e, t) { if (e.length === 0) throw Error("Cannot get item from empty array"); if (e.length === 1) return e[0]; let n = 0, r = e.map((e) => { let r = t(e); return n += r, r; }), i = Math.random() * n; for (let t = 0; t < e.length; t++) if (i -= r[t], i <= 0) return e[t]; return e[e.length - 1]; } function me(e) { return new TextEncoder().encode(e); } function* he(e) { for (let t = e.length - 1; t >= 0; t--) yield e[t]; } function ge(e) { return !!e && typeof e == "object" && !Array.isArray(e); } function _e(e) { return Array.isArray(e); } function ve(e) { function t(e) { if (ge(e)) { let n = {}; return Object.keys(e).forEach((r) => { if (e[r] !== void 0) { let i = t(e[r]); i !== void 0 && (n[r] = i); } }), n; } else return e; } return t(e); } function b(e) { if (_e(e)) return e.map((e) => b(e)); if (ge(e)) { let t = {}; for (let n of Object.keys(e)) t[n] = b(e[n]); return t; } else return e; } function ye(e) { for (let t = e.length - 1; t > 0; t--) { let n = Math.floor(Math.random() * (t + 1)); [e[t], e[n]] = [e[n], e[t]]; } return e; } function x(e, t, n = {}) { return typeof e != "object" || !e || typeof t != "object" || !t || Object.keys(t).forEach((r) => { let i = typeof r == "symbol" ? r.toString() : String(r); if (r === "__proto__" || r === "constructor" || r === "prototype") throw Error(`Attempt to modify restricted property '${i}'`); let a = t[r], o = n[r]; r in e && (a === void 0 ? e[r] = o === void 0 ? void 0 : o : e[r] = a); }), e; } function S(e) { let { defaultConfig: t, baseConfig: n = {}, specificStreamConfig: r = {} } = e, i = b({ ...t, ...n, ...r }), a = Object.keys(t), o = {}; return a.forEach((e) => { e in i && (o[e] = i[e]); }), o; } //#endregion //#region src/p2p/commands/binary-serialization.ts var be = new TextEncoder(), xe = new TextDecoder("utf8"), C = /* @__PURE__ */ function(e) { return e[e.Min = -1] = "Min", e[e.Int = 0] = "Int", e[e.SimilarIntArray = 1] = "SimilarIntArray", e[e.String = 2] = "String", e[e.Max = 3] = "Max", e; }({}); function Se(e) { if (e === 0) return 1; let t = Math.floor(Math.log2(Math.abs(e))) + 2; return Math.ceil(t / 8); } function Ce(e) { let t = e < 0, n = Se(e), r = new Uint8Array(n); e = Math.abs(e); for (let t = 0; t < n; t++) { let i = 8 * (n - 1 - t); r[t] = Math.floor(e / 2 ** i) & 255; } return t && (r[0] |= 128), r; } function we(e) { let t = e.length, n = (e, n) => e * 2 ** (8 * (t - 1 - n)), r = n(e[0] & 127, 0); for (let i = 1; i < t; i++) r += n(e[i], i); return (e[0] & 128) >> 7 && (r = -r), r; } function Te(e) { let t = Ce(e), n = 0 | t.length; return new Uint8Array([n, ...t]); } function Ee(e) { if (e.length === 0) throw Error("Buffer is too short"); let t = e[0]; if (t >> 4) throw Error("Trying to deserialize integer with invalid serialized item code"); let n = t & 15; if (n === 0) throw Error("Invalid integer: zero byte length"); if (n > 7) throw Error("Invalid integer: byte length exceeds safe integer limit"); let r = 1 + n; if (e.length < r) throw Error("Buffer is too short"); return { number: we(e.subarray(1, r)), byteLength: n + 1 }; } function De(e) { let t = /* @__PURE__ */ new Map(); for (let n of e) { let e = n & 255, r = n - e, i = t.get(r) ?? new w(); i.length || t.set(r, i), i.push(e); } let n = new w(); n.push([16, t.size]); for (let [e, r] of t) { let { length: t } = r, i = e + (t & 255); r.unshift(Te(i)), n.push(r.getBuffer()); } return n.getBuffer(); } function Oe(e) { if (e.length < 2) throw Error("Buffer is too short"); let [t, n] = e; if (t >> 4 != 1) throw Error("Trying to deserialize similar int array with invalid serialized item code"); let r = 2, i = []; for (let t = 0; t < n; t++) { let { number: t, byteLength: n } = Ee(e.subarray(r)); r += n; let a = t & 255, o = a === 0 ? 256 : a, s = t - a; if (r + o > e.length) throw Error("Malformed similar int array: buffer too short"); for (let t = 0; t < o; t++) { let t = e[r]; i.push(s + t), r++; } } return { numbers: i, byteLength: r }; } function ke(e) { let t = be.encode(e), { length: n } = t; if (n > 4095) throw Error("String exceeds maximum length of 4095 bytes"); let r = new w(); return r.push([32 | n >> 8 & 15, n & 255]), r.push(t), r.getBuffer(); } function Ae(e) { if (e.length < 2) throw Error("Buffer is too short"); let [t, n] = e; if (t >> 4 != 2) throw Error("Trying to deserialize bytes (sting) with invalid serialized item code."); let r = (t & 15) << 8 | n; if (e.length < r + 2) throw Error("Malformed string: buffer too short"); let i = e.subarray(2, r + 2); return { string: xe.decode(i), byteLength: r + 2 }; } var w = class { #e = []; #t = 0; push(e) { this.#n(e, "end"); } unshift(e) { this.#n(e, "start"); } #n(e, t) { let n; n = e instanceof Uint8Array ? e : Array.isArray(e) ? new Uint8Array(e) : new Uint8Array([e]), this.#t += n.length, this.#e[t === "start" ? "unshift" : "push"](n); } getBytesChunks() { return this.#e; } getBuffer() { return de(this.#e, this.#t); } get length() { return this.#t; } }, T = 4, E = N("cstr", T), D = N("cend", T), O = N("dstr", T), k = N("dend", T), je = [E, O], Me = [D, k], A = E.length + D.length; function Ne(e) { if (e.length < A) return !1; let { length: t } = E, n = e.subarray(-t); return je.some((t) => F(e, t, T)) && Me.some((e) => F(n, e, T)); } function Pe(e) { return e.length < A ? !1 : F(e, E, T); } function Fe(e) { return e.length < A ? !1 : F(e.subarray(-4), D, T); } var j = class extends Error { type; constructor(e) { super(), this.type = e; } }, Ie = class { #e = new w(); #t = "joining"; #n; constructor(e) { this.#n = e; } addCommandChunk(e) { if (this.#t === "completed") return; let t = Pe(e); if (!this.#e.length && !t) throw new j("no-first-chunk"); if (this.#e.length && t) throw new j("incomplete-joining"); this.#e.push(this.#r(e)), Fe(e) && (this.#t = "completed", this.#n(this.#e.getBuffer())); } #r(e) { if (e.length < A) throw Error("Command chunk is too short to unframe"); return e.subarray(T, e.length - T); } }, M = class { #e = new w(); #t = []; #n = "creating"; #r; constructor(e, t) { this.#r = t, this.#e.push(e); } addInteger(e, t) { this.#e.push(e.charCodeAt(0)); let n = Te(t); this.#e.push(n); } addUniqueSimilarIntArr(e, t) { this.#e.push(e.charCodeAt(0)); let n = De(t); this.#e.push(n); } addString(e, t) { this.#e.push(e.charCodeAt(0)); let n = ke(t); this.#e.push(n); } complete() { if (!this.#e.length) throw Error("Buffer is empty"); if (this.#n === "completed") return; this.#n = "completed"; let e = this.#e.getBuffer(); if (e.length + A <= this.#r) { this.#t.push(P(e, E, D)); return; } let t = Math.ceil(e.length / this.#r); Math.ceil(e.length / t) + A > this.#r && t++; for (let [n, r] of ze(e, t)) n === 0 ? this.#t.push(P(r, E, k)) : n === t - 1 ? this.#t.push(P(r, O, D)) : this.#t.push(P(r, O, k)); } getResultBuffers() { if (this.#n === "creating" || !this.#t.length) throw Error("Command is not complete."); return this.#t; } }; function Le(e) { let [t] = e, n = { c: t }, r = 1; for (; r < e.length;) { if (r + 1 >= e.length) throw Error("Malformed command buffer: truncated name/type header"); let t = String.fromCharCode(e[r]); switch (r++, Re(e[r])) { case C.Int: { let { number: i, byteLength: a } = Ee(e.subarray(r)); n[t] = i, r += a; } break; case C.SimilarIntArray: { let { numbers: i, byteLength: a } = Oe(e.subarray(r)); n[t] = i, r += a; } break; case C.String: { let { string: i, byteLength: a } = Ae(e.subarray(r)); n[t] = i, r += a; } break; } } return Be(n); } function Re(e) { let t = e >> 4; if (t <= C.Min || t >= C.Max) throw Error("Not existing type"); return t; } function N(e, t) { if (t && e.length !== t) throw Error("Wrong string length"); let n = new Uint8Array(t ?? e.length); for (let t = 0; t < e.length; t++) n[t] = e.charCodeAt(t); return n; } function* ze(e, t) { let n = Math.ceil(e.length / t); for (let r = 0; r < t; r++) yield [r, e.subarray(r * n, (r + 1) * n)]; } function P(e, t, n) { let r = new Uint8Array(e.length + t.length + n.length); return r.set(t), r.set(e, t.length), r.set(n, t.length + e.length), r; } function F(e, t, n) { for (let r = 0; r < n; r++) if (e[r] !== t[r]) return !1; return !0; } function Be(e) { switch (e.c) { case y.SegmentsAnnouncement: return e; case y.SegmentRequest: return I(e, "i", "r"), e; case y.SegmentData: return I(e, "i", "r", "s"), e; case y.SegmentAbsent: case y.CancelSegmentRequest: case y.SegmentDataSendingCompleted: return I(e, "i", "r"), e; default: throw Error(`Unknown peer command type: ${String(e.c)}`); } } function I(e, ...t) { for (let n of t) if (typeof e[n] != "number") throw Error(`Expected number field "${n}", got ${typeof e[n]}`); } //#endregion //#region src/p2p/commands/commands.ts function Ve(e, t) { let { c: n, p: r, l: i } = e, a = new M(n, t); return i?.length && a.addUniqueSimilarIntArr("l", i), r?.length && a.addUniqueSimilarIntArr("p", r), a.complete(), a.getResultBuffers(); } function He(e, t) { let n = new M(e.c, t); return n.addInteger("i", e.i), n.addInteger("r", e.r), n.complete(), n.getResultBuffers(); } function Ue(e, t) { let n = new M(e.c, t); return n.addInteger("i", e.i), n.addInteger("s", e.s), n.addInteger("r", e.r), n.complete(), n.getResultBuffers(); } function We(e, t) { let n = new M(e.c, t); return n.addInteger("i", e.i), n.addInteger("r", e.r), e.b && n.addInteger("b", e.b), n.complete(), n.getResultBuffers(); } function Ge(e, t) { switch (e.c) { case y.CancelSegmentRequest: case y.SegmentAbsent: case y.SegmentDataSendingCompleted: return He(e, t); case y.SegmentRequest: return We(e, t); case y.SegmentsAnnouncement: return Ve(e, t); case y.SegmentData: return Ue(e, t); } } //#endregion //#region src/p2p/commands/index.ts var Ke = /* @__PURE__ */ s({ BinaryCommandChunksJoiner: () => Ie, BinaryCommandJoiningError: () => j, PeerCommandType: () => y, deserializeCommand: () => Le, isCommandChunk: () => Ne, serializePeerCommand: () => Ge }); //#endregion //#region src/webtorrent/utils.ts function qe(e, t = "RTC error") { let n = e; if (n.error instanceof Error) return n.error; let r = n.error?.message ?? t; return Error(r); } function Je(e, t = "RTC error") { return qe(e, t).message; } function L(e) { return e === "failed" || e === "closed" || e === "disconnected"; } //#endregion //#region src/webtorrent/data-channel-sender.ts var Ye = 64 * 1024, Xe = class { channel; maxMessageSize; #e; constructor(e, t) { this.channel = e, this.maxMessageSize = t; } async sendData(e, t) { if (this.#e) throw Error("Already sending data"); if (this.channel.readyState !== "open") throw Error("Data channel is not open"); this.channel.bufferedAmountLowThreshold = Ye; let { promise: n, resolve: r, reject: i } = le(), a = 0, o = !1, s = () => o ? !1 : (o = !0, this.#e = void 0, this.channel.removeEventListener("bufferedamountlow", f), this.channel.removeEventListener("closing", c), this.channel.removeEventListener("close", c), this.channel.removeEventListener("error", l), !0); this.#e = { cancel: () => { s() && i(/* @__PURE__ */ Error("Send cancelled")); } }; let c = () => { s() && i(/* @__PURE__ */ Error("Data channel closed")); }, l = (e) => { if (!s()) return; let t = Je(e, "Unknown error"); i(/* @__PURE__ */ Error(`Data channel error: ${t}`)); }, u = ArrayBuffer.isView(e) ? e.buffer : e, d = ArrayBuffer.isView(e) ? e.byteOffset : 0, f = () => { if (!o) { if (this.channel.readyState !== "open") { s() && i(/* @__PURE__ */ Error(`Data channel not open (state: ${this.channel.readyState})`)); return; } try { for (; a < e.byteLength;) { if (this.channel.bufferedAmount > Ye) return; let n = Math.min(this.maxMessageSize, e.byteLength - a), r = new Uint8Array(u, d + a, n); if (this.channel.send(r), a += n, t?.(n), !this.#e) return; } } catch (e) { s() && i(e instanceof Error ? e : Error(String(e))); return; } s() && r(); } }; return this.channel.addEventListener("bufferedamountlow", f), this.channel.addEventListener("closing", c), this.channel.addEventListener("close", c), this.channel.addEventListener("error", l), f(), n; } cancel() { this.#e?.cancel(); } }, R = (0, v.default)("p2pml-core:peer-protocol"), Ze = class { #e; #t; #n; #r; #i; #a; #o; #s; #c; constructor(e, t, n, r, i) { if (this.#a = e, this.#o = t, this.#s = n, this.#c = i, this.#t = new Xe(e, t.webRtcMaxMessageSize), this.#r = r.getEventDispatcher("onChunkDownloaded"), this.#i = r.getEventDispatcher("onChunkUploaded"), e.binaryType !== "arraybuffer") throw Error(`Expected binaryType "arraybuffer", got "${e.binaryType}"`); e.addEventListener("message", this.#l); } #l = (e) => { try { let t = new Uint8Array(e.data); Ne(t) ? this.#u(t) : (this.#s.onSegmentChunkReceived(t), this.#r(t.byteLength, "p2p", this.#c, this.#o.streamType, this.#o.infoHash)); } catch (e) { R("error handling data channel message: %O", e), this.#s.onProtocolError(e); } }; sendCommand(e) { if (this.#a.readyState !== "open") throw Error(`cannot send command ${e.c} (channel state: ${this.#a.readyState})`); let t = Ge(e, this.#o.webRtcMaxMessageSize); for (let e of t) this.#a.send(e); } stopUploadingSegmentData() { this.#t.cancel(), this.#n = void 0; } getUploadingRequestId() { return this.#n; } async splitSegmentDataToChunksAndUploadAsync(e, t) { if (this.#n !== void 0) throw Error("Some segment data is already uploading."); this.#n = t; try { await this.#t.sendData(e, (e) => { this.#i(e, this.#c, this.#o.streamType, this.#o.infoHash); }); } finally { this.#n === t && (this.#n = void 0); } } #u(e) { this.#e ??= new Ie((e) => { this.#e = void 0; let t; try { t = Le(e); } catch (e) { R("error deserializing command: %O", e), this.#s.onProtocolError(e); return; } this.#s.onCommandReceived(t); }); try { this.#e.addCommandChunk(e); } catch (e) { R("error receiving command chunks: %O", e), this.#e = void 0, this.#s.onProtocolError(e); } } destroy() { this.#a.removeEventListener("message", this.#l), this.#t.cancel(), this.#e = void 0, this.#n = void 0; } }, Qe = 1, z = class { clearThresholdMs; loadingsCount = 0; bytes = []; loadingOnlyTimestamps = []; timestamps = []; noLoadingsTime = 0; loadingsStoppedAt = 0; constructor(e = 2e4) { this.clearThresholdMs = e; } addBytes(e, t = performance.now()) { this.bytes.push(e), this.loadingOnlyTimestamps.push(t - this.noLoadingsTime), this.timestamps.push(t); } startLoading(e = performance.now()) { this.clearStale(), this.loadingsCount === 0 && this.loadingsStoppedAt !== 0 && (this.noLoadingsTime += e - this.loadingsStoppedAt), this.loadingsCount++; } stopLoading(e = performance.now()) { this.loadingsCount > 0 && (this.loadingsCount--, this.loadingsCount === 0 && (this.loadingsStoppedAt = e)); } getBandwidthLoadingOnly(e, t = -Infinity) { if (!this.loadingOnlyTimestamps.length) return 0; let n = e * 1e3, r = this.loadingOnlyTimestamps[this.loadingOnlyTimestamps.length - 1], i = r, a = r - n, o = 0; for (let e = this.bytes.length - 1; e >= 0; e--) { let n = this.loadingOnlyTimestamps[e]; if (n < a || this.timestamps[e] < t) break; i = n, o += this.bytes[e]; } let s = Math.max(r - i, Qe); return o * 8e3 / s; } getBandwidth(e, t = -Infinity, n = performance.now()) { if (!this.timestamps.length) return 0; let r = n - e * 1e3, i = n, a = 0; for (let e = this.bytes.length - 1; e >= 0; e--) { let n = this.timestamps[e]; if (n < r || n < t) break; i = n, a += this.bytes[e]; } let o = Math.max(n - i, Qe); return a * 8e3 / o; } clearStale() { if (!this.loadingOnlyTimestamps.length) return; let e = this.loadingOnlyTimestamps[this.loadingOnlyTimestamps.length - 1] - this.clearThresholdMs, t = 0; for (let n of this.loadingOnlyTimestamps) { if (n > e) break; t++; } this.bytes.splice(0, t), this.loadingOnlyTimestamps.splice(0, t), this.timestamps.splice(0, t); } clear() { this.bytes.length = 0, this.loadingOnlyTimestamps.length = 0, this.timestamps.length = 0, this.loadingsCount = 0, this.noLoadingsTime = 0, this.loadingsStoppedAt = 0; } }, { PeerCommandType: B } = Ke, $e = class { id; channel; eventTarget; #e; #t; #n = /* @__PURE__ */ new Set(); #r = /* @__PURE__ */ new Set(); #i = 0; #a = new z(); #o = { value: 0, timestamp: 0 }; #s = (0, v.default)("p2pml-core:peer"); #c = 0; #l; #u = !1; connectedAt = performance.now(); #d; #f; #p; get isDestroyed() { return this.#u; } constructor(e, t, n, r, i, a) { this.id = e, this.channel = t, this.eventTarget = a, this.#d = n, this.#f = r, this.#p = i, this.#e = new Ze(t, i, { onSegmentChunkReceived: this.#h, onCommandReceived: (e) => void this.#m(e).catch((t) => { this.#s("error processing command %O: %O", e, t), this.destroy(!1, new d("protocol-violation", t instanceof Error ? t.message : "Error processing command", t)); }), onProtocolError: (e) => { this.destroy(!1, new d("protocol-violation", e instanceof Error ? e.message : "Protocol error", e)); } }, a, e); } get downloadingSegment() { return this.#t?.request.segment; } get isUploadingSegment() { return this.#e.getUploadingRequestId() !== void 0; } getDownloadBandwidth() { let e = performance.now(); return e - this.#o.timestamp > 1e3 && (this.#o.value = this.#a.getBandwidthLoadingOnly(15), this.#o.timestamp = e), this.#o.value; } getSegmentStatus(e) { let { externalId: t } = e; if (this.#n.has(t)) return "loaded"; if (this.#r.has(t)) return "http-loading"; } #m = async (e) => { switch (e.c) { case B.SegmentsAnnouncement: this.#n = new Set(e.l), this.#r = new Set(e.p), this.#f.onSegmentsAnnouncement(); break; case B.SegmentRequest: this.#l = e.r, this.#e.stopUploadingSegmentData(), this.#f.onSegmentRequested(this, e.i, e.r, e.b); break; case B.SegmentData: { if (!this.#t || this.#t.isSegmentDataCommandReceived) break; let { request: t, controls: n, requestId: r } = this.#t; if (t.segment.externalId !== e.i || r !== e.r) break; this.#t.isSegmentDataCommandReceived = !0, n.firstBytesReceived(), t.totalBytes === void 0 ? t.setTotalBytes(t.loadedBytes + e.s) : t.totalBytes - t.loadedBytes !== e.s && this.#g("bytes-length-mismatch", "Peer response bytes length mismatch"); } break; case B.SegmentDataSendingCompleted: { let t = this.#t; if (!t?.isSegmentDataCommandReceived) return; let { request: n, controls: r, requestId: i } = t; if (n.segment.externalId !== e.i || i !== e.r) { this.#g("protocol-violation", "Peer protocol violation"); return; } if (n.loadedBytes !== n.totalBytes) { this.#g("bytes-length-mismatch", "Peer response bytes length mismatch"); return; } let a = await n.validateData(this.#p.validateP2PSegment); if (this.#u || this.#t !== t) return; if (!a) { this.#g("validation-failed", "P2P segment validation failed"); return; } this.#i = 0, r.completeOnSuccess(), this.#a.stopLoading(), this.#t = void 0; break; } case B.SegmentAbsent: this.#n.delete(e.i), this.#t?.request.segment.externalId === e.i && this.#t.requestId === e.r && this.#_("peer-segment-absent"); break; case B.CancelSegmentRequest: if (this.#l === e.r && (this.#l = void 0), this.#e.getUploadingRequestId() !== e.r) break; this.#e.stopUploadingSegmentData(); break; } }; #h = (e) => { if (!this.#t?.isSegmentDataCommandReceived) return; let { request: t, controls: n } = this.#t; if (t.totalBytes !== void 0 && t.loadedBytes + e.byteLength > t.totalBytes) { this.#g("bytes-length-mismatch", "Peer response bytes length mismatch"); return; } this.#a.addBytes(e.byteLength), this.#o.timestamp = 0, n.addLoadedChunk(e); }; downloadSegment(e) { if (this.#u) return; if (this.#t) throw Error("Some segment already is downloading"); if (e.tryCompleteByLoadedBytes({ downloadSource: "p2p", peerId: this.id }, { notReceivingBytesTimeoutMs: this.#p.p2pNotReceivingBytesTimeoutMs, onAbort: () => void 0 }, this.#p.validateP2PSegment, "p2p-segment-validation-failed")) return; this.#a.startLoading(), this.#c = (this.#c + 1) % 1e9, this.#t = { request: e, requestId: this.#c, isSegmentDataCommandReceived: !1, controls: e.start({ downloadSource: "p2p", peerId: this.id }, { notReceivingBytesTimeoutMs: this.#p.p2pNotReceivingBytesTimeoutMs, onAbort: (t) => { if (!this.#t || this.#t.request !== e) return; let { request: n, requestId: r } = this.#t; this.#v(n.segment, r), this.#a.stopLoading(), t.type !== "abort" && (this.#a.clear(), this.#o.timestamp = 0, this.#s(`cleared bandwidth history due to ${t.type}`)), this.#t = void 0, t.type === "bytes-receiving-timeout" && this.#i++, this.#i >= this.#p.p2pErrorRetries ? this.destroy(!1, new d("timeout", "Too many timeout errors")) : t.type === "bytes-receiving-timeout" && this.#f.onWarning(new f("timeout-strike", `Timeout strike ${this.#i}/${this.#p.p2pErrorRetries}`)); } }) }; let t = { c: B.SegmentRequest, r: this.#t.requestId, i: e.segment.externalId }; e.loadedBytes && (t.b = e.loadedBytes), this.#b(t) || this.#_("peer-closed"); } async uploadSegmentData(e, t, n) { if (this.#u) return; if (t !== this.#l) { this.#s(`discarding obsolete upload request ${t} for segment ${e.externalId}`); return; } let { externalId: r } = e; this.#s(`send segment ${e.externalId} to ${this.id} (byteLength: ${n.byteLength})`); let i = { c: B.SegmentData, i: r, r: t, s: n.byteLength }; if (this.#b(i)) try { if (await this.#e.splitSegmentDataToChunksAndUploadAsync(n, t), this.isDestroyed || t !== this.#l) return; this.#y(e, t), this.#s(`segment ${r} has been sent to ${this.id}`); } catch (e) { this.#s(`cancel segment uploading ${r}: %O`, e); } } #g(e, t) { this.#t?.request.clearLoadedBytes(); let n = new d(e, t); this.#_("peer-closed", n), this.destroy(!1, n); } #_(e, t) { if (!this.#t) return; let { request: n, controls: r } = this.#t, { segment: i } = n; this.#s(`cancel segment request ${i.externalId} (${e})`); let a = new g(e, void 0, t); r.failWithError(a), this.#a.stopLoading(), e !== "peer-segment-absent" && (this.#a.clear(), this.#o.timestamp = 0, this.#s(`cleared bandwidth history due to ${a.type}`)), this.#t = void 0; } sendSegmentsAnnouncementCommand(e, t) { let n = { c: B.SegmentsAnnouncement, p: t, l: e }; this.#b(n); } sendSegmentAbsentCommand(e, t) { this.#b({ c: B.SegmentAbsent, i: e, r: t }); } #v(e, t) { this.#b({ c: B.CancelSegmentRequest, i: e.externalId, r: t }); } #y(e, t) { this.#b({ c: B.SegmentDataSendingCompleted, r: t, i: e.externalId }); } destroy(e = !1, t) { this.#u || (this.#u = !0, this.#_("peer-closed", t), this.#e.destroy(), e || this.#d(t), this.#s(`peer closed ${this.id}`)); } #b(e) { if (this.#u) return !1; try { return this.#e.sendCommand(e), !0; } catch (t) { return this.#s("error sending command %d: %O", e.c, t), !1; } } }, V = class { events = /* @__PURE__ */ new Map(); dispatchEvent(e, t, n, r, i, a) { let o = this.events.get(e); if (o) for (let e of o) try { e(t, n, r, i, a); } catch {} } getEventDispatcher(e) { return (t, n, r, i, a) => { let o = this.events.get(e); if (o) for (let e of o) try { e(t, n, r, i, a); } catch {} }; } addEventListener(e, t) { let n = this.events.get(e); n ? this.events.set(e, [...n, t]) : this.events.set(e, [t]); } removeEventListener(e, t) { let n = this.events.get(e); if (!n) return; let r = n.indexOf(t); if (r === -1) return; if (n.length === 1) { this.events.delete(e); return; } let i = n.slice(); i.splice(r, 1), this.events.set(e, i); } clear() { this.events.clear(); } }, H = typeof window < "u" ? window : {}, U = H.RTCPeerConnection ?? H.webkitRTCPeerConnection ?? H.mozRTCPeerConnection, et = H.RTCSessionDescription ?? H.webkitRTCSessionDescription ?? H.mozRTCSessionDescription, W = (() => { if (!H.RTCPeerConnection && !H.webkitRTCPeerConnection && !H.mozRTCPeerConnection) return !1; let e; try { e = new U(); let t = e.createOffer(); if (typeof t?.then == "function") return t.catch(() => {}), !0; } catch {} finally { try { e?.close(); } catch {} } return !1; })(); function tt(e, t) { return W ? e.createOffer(t) : new Promise((n, r) => { try { e.createOffer(n, r, t); } catch (e) { r(e); } }); } function nt(e, t) { return W ? e.createAnswer(t) : new Promise((n, r) => { try { e.createAnswer(n, r, t); } catch (e) { r(e); } }); } function rt(e, t) { return W ? e.setLocalDescription(t) : new Promise((n, r) => { try { e.setLocalDescription(t, n, r); } catch (e) { r(e); } }); } function it(e, t) { return W ? e.setRemoteDescription(t) : new Promise((n, r) => { try { e.setRemoteDescription(t, n, r); } catch (e) { r(e); } }); } //#endregion //#region src/webtorrent/webtorrent-client/index.ts var at = 5e4, ot = 15e3, st = 5, ct = 5e3; function lt() { let e = ""; for (let t = 0; t < 20; t++) e += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".charAt(Math.floor(Math.random() * 62)); return e; } var ut = new Set([ "offer", "answer", "pranswer", "rollback" ]); function dt(e) { if (typeof e != "object" || !e) return !1; let t = e; return typeof t.type == "string" && ut.has(t.type) && typeof t.sdp == "string"; } var ft = class e { static #e = 120; static #t = 20; #n; #r; #i = new V(); #a = /* @__PURE__ */ new Map(); #o = /* @__PURE__ */ new Set(); #s = new re(); #c = null; #l = null; #u = 0; #d = null; #f = void 0; #p = null; #m = !1; #h() { return this.#s.signal.aborted; } #g() { if (this.#s.signal.aborted) throw Error("Client destroyed"); } constructor(e) { this.#n = { infoHash: e.infoHash, peerId: e.peerId, rtcConfig: e.rtcConfig, channelConfig: e.channelConfig, offerTimeout: e.offerTimeout ?? (() => at), offersCount: e.offersCount ?? (() => st), iceGatheringTimeout: e.iceGatheringTimeout ?? (() => ct), connectionTimeout: e.connectionTimeout ?? (() => ot), claimPeer: e.claimPeer ?? (() => !0), shouldGenerateOffers: e.shouldGenerateOffers ?? (() => !0) }, this.#r = e.wsClient; } addEventListener(e, t) { this.#i.addEventListener(e, t); } removeEventListener(e, t) { this.#i.removeEventListener(e, t); } start() { this.#h() || this.#m || (this.#m = !0, this.#r.addEventListener("connected", this.#_), this.#r.addEventListener("disconnected", this.#v), this.#r.addEventListener("message", this.#y), this.#r.state === "connected" && this.#_()); } destroy() { this.#h() || (this.#s.abort(), this.#x(), this.#w(), this.#j(), this.#M(), this.#m && (this.#r.removeEventListener("connected", this.#_), this.#r.removeEventListener("disconnected", this.#v), this.#r.removeEventListener("message", this.#y)), this.#i.clear()); } #_ = () => { this.#b(e.#e), this.#S("started").catch((e) => { this.#h() || this.#i.dispatchEvent("error", new p("announce-failed", `Initial announce failed: ${e instanceof Error ? e.message : String(e)}`, e)); }); }; #v = () => { this.#x(), this.#l = null; }; #y = (t) => { if (this.#h()) return; let n; try { let e = typeof t == "string" ? t : new TextDecoder().decode(t); n = JSON.parse(e); } catch (e) { this.#i.dispatchEvent("error", new p("parse-error", `Failed to parse tracker message: ${e instanceof Error ? e.message : String(e)}`, e)); return; } if (typeof n != "object" || !n || Array.isArray(n)) return; let r = n, i = r.info_hash; if (typeof i == "string" && i !== this.#n.infoHash) return; let a = r["warning message"]; typeof a == "string" && this.#i.dispatchEvent("warning", new m("tracker-response", a)); let o = r["failure reason"]; if (typeof o == "string") { this.#i.dispatchEvent("error", new p("tracker-response", o)); return; } let { interval: s } = r; if (typeof s == "number" && s > 0) { let t = Math.max(e.#t, s); this.#l !== t && this.#b(t); } let c = r["tracker id"]; typeof c == "string" && (this.#p = c); let l = r.peer_id; if (typeof l == "string" && l === this.#n.peerId) return; let u = r.offer_id; typeof l != "string" || typeof u != "string" || (dt(r.offer) ? this.#E({ sdp: r.offer, peerId: l, offerId: u }).catch((e) => { this.#h() || this.#i.dispatchEvent("error", new p("signaling-failed", `Failed to handle offer: ${e instanceof Error ? e.message : String(e)}`, e)); }) : dt(r.answer) && this.#D({ sdp: r.answer, peerId: l, offerId: u }).catch((e) => { this.#h() || this.#i.dispatchEvent("error", new p("signaling-failed", `Failed to handle answer: ${e instanceof Error ? e.message : String(e)}`, e)); })); }; #b(e) { this.#x(), this.#l = e; let t = ++this.#u, n = async () => { try { await this.#S(); } catch (e) { if (this.#h()) return; this.#i.dispatchEvent("error", new p("announce-failed", `Announce failed: ${e instanceof Error ? e.message : String(e)}`, e)); } !this.#h() && this.#l !== null && this.#u === t && (this.#c = setTimeout(n, this.#l * 1e3)); }; this.#c = setTimeout(n, e * 1e3); } #x() { this.#c !== null && (clearTimeout(this.#c), this.#c = null); } async #S(e) { if (this.#h() || this.#r.state !== "connected") return; if (e && (this.#f = e), this.#d) return this.#d; let t = (async () => { let e = this.#n.shouldGenerateOffers() ? this.#n.offersCount() : 0, t = await Promise.all(Array.from({ length: e }, () => this.#C())); if (this.#h()) { for (let e of t) e && this.#A(e.offer_id); return; } let n = []; for (let e of t) e && n.push(e); let r = this.#f; this.#f = void 0; let i = this.#T({ numwant: n.length, offers: n, event: r }); if (this.#r.state !== "connected") { for (let e of n) this.#A(e.offer_id); return; } try { this.#r.send(JSON.stringify(i)); } catch (e) { for (let e of n) this.#A(e.offer_id); throw e; } })(); this.#d = t; try { await t; } finally { this.#d === t && (this.#d = null); } } async #C() { if (this.#h()) return; let e; try { e = new U(this.#n.rtcConfig?.()), this.#o.add(e); let t = e.createDataChannel("webtorrent", this.#n.channelConfig), n = await tt(e); this.#g(), await rt(e, n), this.#g(), await this.#O(e), this.#g(); let r = e.localDescription; if (!r?.sdp) { e.close(); return; } let i = lt(); return this.#a.set(i, { connection: e, channel: t, timeoutId: setTimeout(() => { this.#A(i); }, this.#n.offerTimeout()) }), { offer: { type: r.type, sdp: r.sdp }, offer_id: i }; } catch (t) { e?.close(), this.#h() || this.#i.dispatchEvent("warning", new m("offer-failed", `Failed to create offer: ${t instanceof Error ? t.message : String(t)}`, t)); } finally { e && this.#o.delete(e); } } #w() { if (this.#r.state !== "connected") return; let e = this.#T({ numwant: 0, offers: [], event: "stopped" }); try { this.#r.send(JSON.stringify(e)); } catch {} } #T({ numwant: e, offers: t, event: n }) { let r = { action: "announce", info_hash: this.#n.infoHash, peer_id: this.#n.peerId, numwant: e, uploaded: 0, downloaded: 0, offers: t }; return n && (r.event = n), this.#p && (r.trackerid = this.#p), r; } async #E({ sdp: e, peerId: t, offerId: n }) { if (this.#h() || !this.#n.claimPeer(t)) return; let r; try { r = new U(this.#n.rtcConfig?.()), this.#o.add(r), await it(r, new et(e)), this.#g(); let i = await nt(r); this.#g(), await rt(r, i), this.#g(), await this.#O(r), this.#g(); let a = r.localDescription; if (!a) throw Error("Failed to get local description after ICE gathering"); let o = { action: "announce", info_hash: this.#n.infoHash, peer_id: this.#n.peerId, to_peer_id: t, offer_id: n, answer: { type: a.type, sdp: a.sdp } }; this.#r.send(JSON.stringify(o)); let s = await this.#k(r); this.#g(), this.#i.dispatchEvent("peerConnected", { peerId: t, connection: r, channel: s }); } catch (e) { r?.close(), this.#i.dispatchEvent("peerConnectFailed", { peerId: t, error: new h("connection-failed", e instanceof Error ? e.message : String(e), e) }); } finally { r && this.#o.delete(r); } } async #D({ sdp: e, peerId: t, offerId: n }) { if (this.#h()) return; let r = this.#a.get(n); if (r) { if (this.#a.delete(n), clearTimeout(r.timeoutId), !this.#n.claimPeer(t)) { r.connection.close(); return; } this.#o.add(r.connection); try { await it(r.connection, new et(e)), this.#g(); let n = await this.#k(r.connection, r.channel); this.#g(), this.#i.dispatchEvent("peerConnected", { peerId: t, connection: r.connection, channel: n }); } catch (e) { r.connection.close(), this.#i.dispatchEvent("peerConnectFailed", { peerId: t, error: new h("connection-failed", e instanceof Error ? e.message : String(e), e) }); } finally { this.#o.delete(r.connection); } } } #O(e) { return new Promise((t, n) => { if (e.iceGatheringState === "complete") { t(); return; } if (e.signalingState === "closed") { n(/* @__PURE__ */ Error("RTCPeerConnection closed")); return; } let r, i = () => { clearTimeout(r), e.removeEventListener("icegatheringstatechange", a), e.removeEventListener("icecandidate", o), e.removeEventListener("signalingstatechange", s), this.#s.signal.removeEventListener("abort", c); }, a = () => { e.iceGatheringState === "complete" && (i(), t()); }, o = (e) => { e.candidate === null && (i(), t()); }, s = () => { e.signalingState === "closed" && (i(), n(/* @__PURE__ */ Error("RTCPeerConnection closed"))); },