aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/file-utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/file-utils.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/file-utils.js37
1 files changed, 36 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/file-utils.js b/packages/meshbay-hub/src/meshbay_hub/static/file-utils.js
index b44d105..ba76ac9 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/file-utils.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/file-utils.js
@@ -117,6 +117,41 @@ function _b64ToU8(b64) {
return arr;
}
+// A dead transport (screen-lock WebRTC failure, see transport.js's
+// _reconnectLoop) surfaces here as a rejected fetchChunk — TransportLostError
+// when the pending request was killed outright, a plain timeout if it was
+// still waiting when this ran. Either way the chunk itself was never the
+// problem, and the file already on disk (writable has real bytes in it by
+// now) is worth more than an all-or-nothing download: retry the same chunk
+// instead of letting one bad moment abort the whole transfer. Each retry
+// re-enters transport.fetchChunk, whose own _sendAndWait waits out an
+// in-flight reconnect before trying again, so this loop is mostly just
+// giving that reconnect the time and the attempts to land.
+const CHUNK_RETRY_ATTEMPTS = 6;
+const CHUNK_RETRY_DELAY_MS = 1500;
+
+function _isRetryableTransportError(err) {
+ return err.name === 'TransportLostError'
+ || err.message === 'Response timeout'
+ || (err.message || '').startsWith('DataChannel not open');
+}
+
+async function _fetchChunkResilient(transport, fileId, index) {
+ let lastErr;
+ for (let attempt = 0; attempt < CHUNK_RETRY_ATTEMPTS; attempt++) {
+ try {
+ return await transport.fetchChunk(fileId, index);
+ } catch (err) {
+ if (!_isRetryableTransportError(err)) throw err;
+ lastErr = err;
+ if (attempt < CHUNK_RETRY_ATTEMPTS - 1) {
+ await new Promise((r) => setTimeout(r, CHUNK_RETRY_DELAY_MS));
+ }
+ }
+ }
+ throw lastErr;
+}
+
async function pipelinedDownload(transport, gekKey, fileId, totalChunks, onChunk,
writable, signal) {
const results = writable ? null : new Array(totalChunks);
@@ -125,7 +160,7 @@ async function pipelinedDownload(transport, gekKey, fileId, totalChunks, onChunk
const fire = () => {
while (nextSend < totalChunks && nextSend - nextRecv < PIPELINE_WINDOW) {
- inflight[nextSend] = transport.fetchChunk(fileId, nextSend);
+ inflight[nextSend] = _fetchChunkResilient(transport, fileId, nextSend);
nextSend++;
}
};