diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/transport.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/transport.js | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport.js b/packages/meshbay-hub/src/meshbay_hub/static/transport.js index 56ec2c7..4eb7ac2 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/transport.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/transport.js @@ -1727,6 +1727,30 @@ class MeshBayTransport { get gekRaw() { return this._gekRaw; } + /** + * Give an automatic reconnect already in progress (see _reconnectLoop) a + * bounded chance to land before giving up. + * + * _sendAndWait does this internally for every request that goes through + * it, so most callers never need this directly. It exists for the ones + * that check `transport.connected` themselves before doing anything else — + * music-player.js's fetchTrackBlob is the one this was written for: found + * live throwing "Transport not connected" on the track *after* a + * screen-lock reconnect had already been under way for a while, because + * that check ran, saw `connected` still false, and threw before the + * reconnect it only had to wait a few seconds for got the chance to finish. + * A no-op — returns immediately — when nothing is being reconnected, + * including once one has already succeeded, so it is safe to call + * unconditionally ahead of such a check. + */ + async waitForReconnect(timeoutMs = 6000) { + if (!this._reconnectPromise) return; + await Promise.race([ + this._reconnectPromise.catch(() => {}), + new Promise((r) => setTimeout(r, timeoutMs)), + ]); + } + close() { // Must be set before pc.close() below: that close() itself can drive the // pc to "closed" synchronously, and the connectionstatechange handler @@ -1745,19 +1769,12 @@ class MeshBayTransport { async _sendAndWait(obj, timeoutMs = 30000) { // A reconnect already in flight (see _reconnectLoop) means the channel - // this would send on is the one just declared dead. Waiting here, bounded - // rather than open-ended — the loop can be backing off for up to 30s - // between attempts, and a caller (in particular file-utils.js's - // pipelinedDownload, which retries a lost chunk itself) should get its - // own timeout rather than sit through someone else's backoff — gives a - // fresh handshake a real chance to land before this request is even - // attempted, instead of guaranteeing it dies with the old one. - if (this._reconnectPromise && !this._inReconnectAttempt) { - await Promise.race([ - this._reconnectPromise.catch(() => {}), - new Promise((r) => setTimeout(r, 6000)), - ]); - } + // this would send on is the one just declared dead. `_inReconnectAttempt` + // excludes the handshake connect() itself makes while reconnecting — that + // call runs *inside* this same _reconnectPromise, which cannot resolve + // until it returns, so waiting on it here would just be waiting on + // itself for the full 6s, on every step of the handshake, every time. + if (!this._inReconnectAttempt) await this.waitForReconnect(6000); return new Promise((resolve, reject) => { const id = this._seqId++; const timeout = setTimeout(() => { |