diff --git a/Overlord-Server/public/assets/filebrowser.js b/Overlord-Server/public/assets/filebrowser.js index 8569b83..1dc02b8 100644 --- a/Overlord-Server/public/assets/filebrowser.js +++ b/Overlord-Server/public/assets/filebrowser.js @@ -1249,9 +1249,17 @@ function waitForUploadAck(transfer, offset, timeoutMs) { }); } +function clearUploadPendingAcks(transfer, reason) { + transfer.pendingAcks.forEach((pending, _offset) => { + clearTimeout(pending.timeoutId); + pending.reject(new Error(reason)); + }); + transfer.pendingAcks.clear(); +} + async function sendChunkWithRetry(transfer, payload, offset) { - const maxRetries = 3; - const ackTimeoutMs = 15000; + const maxRetries = 5; + const ackTimeoutMs = 20000; const backoffMs = 300; for (let attempt = 1; attempt <= maxRetries; attempt += 1) { @@ -1314,13 +1322,68 @@ async function uploadFile(file) { activeTransfers.set(transferId, transfer); addTransferToUI(transfer); - const chunkSize = 512 * 1024; + const chunkSize = 900 * 1024; + const maxInFlightChunks = 6; transfer.expectedChunks = Math.max(1, Math.ceil(file.size / chunkSize)); - let offset = 0; + let nextOffset = 0; + const inFlight = new Set(); + + const processChunk = async (offset) => { + const chunk = file.slice(offset, offset + chunkSize); + const arrayBuffer = await chunk.arrayBuffer(); + const uint8Array = new Uint8Array(arrayBuffer); + + const payload = { + type: "file_upload", + path, + data: uint8Array, + offset, + transferId, + total: file.size, + }; + const ack = await sendChunkWithRetry(transfer, payload, offset); + + if (!transfer.ackedOffsets.has(offset)) { + transfer.ackedOffsets.add(offset); + transfer.receivedChunks += 1; + } + + if (Number.isFinite(ack?.received)) { + transfer.receivedBytes = Math.min(Number(ack.received), transfer.total); + transfer.sent = transfer.receivedBytes; + } else { + transfer.receivedBytes = Math.min(transfer.receivedBytes + chunk.size, transfer.total); + transfer.sent = transfer.receivedBytes; + } + + transfer.progress = Math.round((transfer.sent / file.size) * 100); + updateTransferProgress(transferId, transfer.progress, transfer.sent, file.size); + }; + + const fillUploadWindow = () => { + while ( + !transfer.cancelled && + nextOffset < file.size && + inFlight.size < maxInFlightChunks + ) { + const offset = nextOffset; + nextOffset += chunkSize; + + const task = processChunk(offset).finally(() => { + inFlight.delete(task); + }); + inFlight.add(task); + } + }; try { - while (offset < file.size) { + fillUploadWindow(); + + while (inFlight.size > 0) { + await Promise.race(inFlight); + if (transfer.cancelled) { + clearUploadPendingAcks(transfer, "Upload cancelled"); console.log("Upload cancelled:", path); removeTransfer(transferId); fileUploads.delete(path); @@ -1328,29 +1391,7 @@ async function uploadFile(file) { return; } - const chunk = file.slice(offset, offset + chunkSize); - const arrayBuffer = await chunk.arrayBuffer(); - const uint8Array = new Uint8Array(arrayBuffer); - - const payload = { type: "file_upload", path, data: uint8Array, offset, transferId, total: file.size }; - const ack = await sendChunkWithRetry(transfer, payload, offset); - - if (!transfer.ackedOffsets.has(offset)) { - transfer.ackedOffsets.add(offset); - transfer.receivedChunks += 1; - } - - if (Number.isFinite(ack?.received)) { - transfer.receivedBytes = Math.min(Number(ack.received), transfer.total); - transfer.sent = transfer.receivedBytes; - } else { - transfer.sent = offset + chunk.size; - } - - transfer.progress = Math.round((transfer.sent / file.size) * 100); - updateTransferProgress(transferId, transfer.progress, transfer.sent, file.size); - - offset += chunk.size; + fillUploadWindow(); } transfer.completed = true; @@ -1358,6 +1399,7 @@ async function uploadFile(file) { finishUpload(transfer); } } catch (err) { + clearUploadPendingAcks(transfer, "Upload aborted"); console.error("Upload error:", err); removeTransfer(transferId); fileUploads.delete(path); diff --git a/Overlord-Server/public/filebrowser.html b/Overlord-Server/public/filebrowser.html index 38b8570..6271edb 100644 --- a/Overlord-Server/public/filebrowser.html +++ b/Overlord-Server/public/filebrowser.html @@ -603,6 +603,6 @@ - +