From 8a2ee7beae3a530cf863a60f57a0d996d0cf0705 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:07:28 -0500 Subject: [PATCH] Tighten torrent probe polling --- js/webtorrent.js | 65 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/js/webtorrent.js b/js/webtorrent.js index dce6785c..8fbaf4b8 100644 --- a/js/webtorrent.js +++ b/js/webtorrent.js @@ -23,6 +23,7 @@ import { WSS_TRACKERS } from "./constants.js"; import { safeDecodeURIComponent } from "./utils/safeDecode.js"; import { devLogger, userLogger } from "./utils/logger.js"; import { emit } from "./embedDiagnostics.js"; +import { infoHashFromMagnet } from "./magnets.js"; const DEFAULT_PROBE_TRACKERS = Object.freeze([...WSS_TRACKERS]); @@ -161,6 +162,8 @@ export class TorrentClient { // Timeout for SW operations this.TIMEOUT_DURATION = 60000; + + this.probeInFlight = new Map(); } ensureClientForProbe() { @@ -179,7 +182,7 @@ export class TorrentClient { */ async probePeers( magnetURI, - { timeoutMs = 8000, maxWebConns = 2, polls = 3, urlList = [] } = {} + { timeoutMs = 8000, maxWebConns = 2, polls = 2, urlList = [] } = {} ) { const magnet = typeof magnetURI === "string" ? magnetURI.trim() : ""; if (!magnet) { @@ -214,14 +217,21 @@ export class TorrentClient { }; } + const infoHash = infoHashFromMagnet(magnet); + const probeKey = infoHash || null; + + if (probeKey && this.probeInFlight.has(probeKey)) { + return this.probeInFlight.get(probeKey); + } + const client = this.ensureClientForProbe(); const safeTimeout = Math.max(0, normalizeNumber(timeoutMs, 8000)); - const safePolls = Math.max(1, Math.floor(normalizeNumber(polls, 3))); + const safePolls = Math.max(0, Math.floor(normalizeNumber(polls, 2))); const safeMaxWebConns = Math.max(1, Math.floor(normalizeNumber(maxWebConns, 2))); - const pollInterval = Math.max( - 250, - Math.floor(safeTimeout / Math.max(1, safePolls)) - ); + const pollInterval = + safePolls > 0 + ? Math.max(1000, Math.floor(safeTimeout / Math.max(1, safePolls))) + : 0; const startedAt = typeof performance !== "undefined" && performance?.now @@ -230,11 +240,12 @@ export class TorrentClient { emit("torrent-probe-start", { magnet: augmentedMagnet }); - return new Promise((resolve) => { + const probePromise = new Promise((resolve) => { let settled = false; let torrent = null; let timeoutId = null; let pollId = null; + let pollStartId = null; const finalize = (overrides = {}) => { if (settled) { @@ -249,6 +260,10 @@ export class TorrentClient { clearInterval(pollId); pollId = null; } + if (pollStartId) { + clearTimeout(pollStartId); + pollStartId = null; + } if (torrent) { try { torrent.destroy({ destroyStore: true }); @@ -328,16 +343,34 @@ export class TorrentClient { }, safeTimeout); } - pollId = setInterval(() => { - if (!torrent || settled) { - return; - } - const peers = Math.max(0, Math.floor(normalizeNumber(torrent.numPeers, 0))); - if (peers > 0) { - finalize({ healthy: true, peers, reason: "peer" }); - } - }, pollInterval); + if (safePolls > 0 && pollInterval > 0) { + pollStartId = setTimeout(() => { + if (!torrent || settled) { + return; + } + pollId = setInterval(() => { + if (!torrent || settled) { + return; + } + const peers = Math.max(0, Math.floor(normalizeNumber(torrent.numPeers, 0))); + if (peers > 0) { + finalize({ healthy: true, peers, reason: "peer" }); + } + }, pollInterval); + }, pollInterval); + } }); + + if (probeKey) { + this.probeInFlight.set(probeKey, probePromise); + probePromise.finally(() => { + if (this.probeInFlight.get(probeKey) === probePromise) { + this.probeInFlight.delete(probeKey); + } + }); + } + + return probePromise; } log(...args) {