From 9d8c79f9f868372ef5aac7d9a73f9a4595345a50 Mon Sep 17 00:00:00 2001 From: Niklas Jensen Date: Sat, 31 Jan 2026 21:31:56 +0100 Subject: [PATCH] Fixed upload progress (svelte) - added emit await --- app/src/lib/filesystem/chunkedTransfer.ts | 10 +++++---- app/src/lib/stores/socket.ts | 27 ++++++++++++++++++----- esp32/src/communication/webserver.cpp | 9 ++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/app/src/lib/filesystem/chunkedTransfer.ts b/app/src/lib/filesystem/chunkedTransfer.ts index 7fa763b..7dfc067 100644 --- a/app/src/lib/filesystem/chunkedTransfer.ts +++ b/app/src/lib/filesystem/chunkedTransfer.ts @@ -343,7 +343,8 @@ export class FileSystemClient { this.activeUploads.set(transferId, upload) - // Stream all chunks without waiting for ACKs + // Stream chunks one at a time, waiting for each to be sent + ;(async () => { for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) { const offset = chunkIndex * chunkSize const end = Math.min(offset + chunkSize, fileSize) @@ -355,12 +356,12 @@ export class FileSystemClient { data: chunkData } - // Send chunk as fire-and-forget message - socket.emit(FSMessages.FSUploadData, uploadData) + // Wait for chunk to be sent before continuing + await socket.emit(FSMessages.FSUploadData, uploadData) upload.chunksSent++ - // Report progress + // Report progress after chunk is actually sent if (onProgress) { onProgress({ transferId, @@ -375,6 +376,7 @@ export class FileSystemClient { // All chunks sent - now wait for completion message from server // The timeout will handle if server doesn't respond + })() }) } diff --git a/app/src/lib/stores/socket.ts b/app/src/lib/stores/socket.ts index dd4d2d9..0148fcf 100644 --- a/app/src/lib/stores/socket.ts +++ b/app/src/lib/stores/socket.ts @@ -198,12 +198,27 @@ function createWebSocket() { unresponsiveTimeoutId = setTimeout(() => disconnect('unresponsive'), reconnectTimeoutTime) } - function emit(event: MessageFns, data: T) { - if (!ws || ws.readyState !== WebSocket.OPEN) return - const type = getNameFromMessageType(event) - const wsm = Message.create() as Record - wsm[type] = data - send(wsm as Message) + function emit(event: MessageFns, data: T): Promise { + return new Promise((resolve) => { + if (!ws || ws.readyState !== WebSocket.OPEN) { + resolve() + return + } + const type = getNameFromMessageType(event) + const wsm = Message.create() as Record + wsm[type] = data + send(wsm as Message) + + // Wait for buffer to flush before resolving + const checkBuffer = () => { + if (!ws || ws.bufferedAmount === 0) { + resolve() + } else { + setTimeout(checkBuffer, 5) + } + } + checkBuffer() + }) } function unsubscribeToMessageFromServer(event_type: MessageFns) { diff --git a/esp32/src/communication/webserver.cpp b/esp32/src/communication/webserver.cpp index 37b3686..668519e 100644 --- a/esp32/src/communication/webserver.cpp +++ b/esp32/src/communication/webserver.cpp @@ -268,6 +268,15 @@ esp_err_t WebServer::wsSend(int sockfd, const uint8_t* data, size_t len) { xSemaphoreTake(wsMutex_, portMAX_DELAY); esp_err_t ret = httpd_ws_send_frame_async(server_, sockfd, &frame); xSemaphoreGive(wsMutex_); + + if (ret != ESP_OK) { + if (httpd_ws_get_fd_info(server_, sockfd) != HTTPD_WS_CLIENT_WEBSOCKET) { + ESP_LOGW(TAG, "Removing disconnected client %d", sockfd); + removeWsClient(sockfd); + return ESP_ERR_INVALID_STATE; + } + } + return ret; }