diff --git a/src/network/html/FilesPage.html b/src/network/html/FilesPage.html index 1721faa3..94ec65b3 100644 --- a/src/network/html/FilesPage.html +++ b/src/network/html/FilesPage.html @@ -818,7 +818,7 @@ let failedUploadsGlobal = []; let wsConnection = null; const WS_PORT = 81; -const WS_CHUNK_SIZE = 16384; // 16KB chunks for WebSocket - larger = faster +const WS_CHUNK_SIZE = 4096; // 4KB chunks - smaller for ESP32 stability // Get WebSocket URL based on current page location function getWsUrl() { @@ -831,6 +831,9 @@ function uploadFileWebSocket(file, onProgress, onComplete, onError) { return new Promise((resolve, reject) => { const ws = new WebSocket(getWsUrl()); let uploadStarted = false; + let sendingChunks = false; + + ws.binaryType = 'arraybuffer'; ws.onopen = function() { console.log('[WS] Connected, starting upload:', file.name); @@ -838,15 +841,53 @@ function uploadFileWebSocket(file, onProgress, onComplete, onError) { ws.send(`START:${file.name}:${file.size}:${currentPath}`); }; - ws.onmessage = function(event) { + ws.onmessage = async function(event) { const msg = event.data; console.log('[WS] Message:', msg); if (msg === 'READY') { uploadStarted = true; - // Start sending binary data in chunks - sendFileChunks(ws, file, onProgress); + sendingChunks = true; + + // Small delay to let connection stabilize + await new Promise(r => setTimeout(r, 50)); + + try { + // Send file in chunks + const totalSize = file.size; + let offset = 0; + + while (offset < totalSize && ws.readyState === WebSocket.OPEN) { + const chunkSize = Math.min(WS_CHUNK_SIZE, totalSize - offset); + const chunk = file.slice(offset, offset + chunkSize); + const buffer = await chunk.arrayBuffer(); + + // Wait for buffer to clear - more aggressive backpressure + while (ws.bufferedAmount > WS_CHUNK_SIZE * 2 && ws.readyState === WebSocket.OPEN) { + await new Promise(r => setTimeout(r, 5)); + } + + if (ws.readyState !== WebSocket.OPEN) { + throw new Error('WebSocket closed during upload'); + } + + ws.send(buffer); + offset += chunkSize; + + // Update local progress + if (onProgress) onProgress(offset, totalSize); + } + + sendingChunks = false; + console.log('[WS] All chunks sent, waiting for DONE'); + } catch (err) { + console.error('[WS] Error sending chunks:', err); + sendingChunks = false; + ws.close(); + reject(err); + } } else if (msg.startsWith('PROGRESS:')) { + // Server confirmed progress - we can use this for accurate tracking const parts = msg.split(':'); const received = parseInt(parts[1]); const total = parseInt(parts[2]); @@ -866,39 +907,21 @@ function uploadFileWebSocket(file, onProgress, onComplete, onError) { ws.onerror = function(event) { console.error('[WS] Error:', event); if (!uploadStarted) { - // WebSocket connection failed, reject to trigger fallback reject(new Error('WebSocket connection failed')); + } else if (!sendingChunks) { + reject(new Error('WebSocket error during upload')); } }; - ws.onclose = function() { - console.log('[WS] Connection closed'); + ws.onclose = function(event) { + console.log('[WS] Connection closed, code:', event.code, 'reason:', event.reason); + if (sendingChunks) { + reject(new Error('WebSocket closed unexpectedly')); + } }; }); } -// Send file in chunks via WebSocket -async function sendFileChunks(ws, file, onProgress) { - const totalSize = file.size; - let offset = 0; - - while (offset < totalSize) { - const chunk = file.slice(offset, offset + WS_CHUNK_SIZE); - const buffer = await chunk.arrayBuffer(); - - // Wait for buffer to clear if needed - while (ws.bufferedAmount > WS_CHUNK_SIZE * 4) { - await new Promise(r => setTimeout(r, 10)); - } - - ws.send(buffer); - offset += chunk.size; - - // Update local progress (server will confirm) - if (onProgress) onProgress(offset, totalSize); - } -} - // Upload file via HTTP (fallback method) function uploadFileHTTP(file, onProgress, onComplete, onError) { return new Promise((resolve, reject) => {