From b7df2de6a532d22e4e422521f40fad9d1fd7618e Mon Sep 17 00:00:00 2001 From: ddidderr Date: Tue, 19 May 2026 22:59:36 +0200 Subject: [PATCH] fix(download): emit failure events on early-returns and update UI transition Address backend early-return paths that were silently exiting without emitting a terminal event to the UI, and align the UI transition to "Downloading" with the actual start of the chunk transfer. - Added `DownloadGameFilesFailed` event emissions to `handlers.rs` in the unhandled early-return branches (when resolved file descriptions are empty or when no trusted peers are found without a local copy). This prevents the UI from getting stuck in a checking state. - Updated the frontend `'game-download-pre'` listener to keep the status in `CheckingPeers` during peer majority size validation, and let the UI switch to `Downloading` only upon `'game-download-begin'`. - Added clarifying comments explaining the safety and semantic roles of both listeners. Test Plan: - Run all unit tests to ensure no regressions: `just test` - Compile and build the Tauri project: `just build` --- crates/lanspread-peer/src/handlers.rs | 8 ++++++++ crates/lanspread-tauri-deno-ts/src/hooks/useGames.ts | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/lanspread-peer/src/handlers.rs b/crates/lanspread-peer/src/handlers.rs index 23c2f53..7da859b 100644 --- a/crates/lanspread-peer/src/handlers.rs +++ b/crates/lanspread-peer/src/handlers.rs @@ -251,6 +251,9 @@ pub async fn handle_download_game_files_command( log::error!( "No validated file descriptions available to download game {id}; request metadata first" ); + if let Err(send_err) = tx_notify_ui.send(PeerEvent::DownloadGameFilesFailed { id }) { + log::error!("Failed to send DownloadGameFilesFailed event: {send_err}"); + } return; } @@ -277,6 +280,11 @@ pub async fn handle_download_game_files_command( } } else { log::error!("No trusted peers available after majority validation for game {id}"); + if let Err(send_err) = + tx_notify_ui.send(PeerEvent::DownloadGameFilesFailed { id: id.clone() }) + { + log::error!("Failed to send DownloadGameFilesFailed event: {send_err}"); + } } return; } diff --git a/crates/lanspread-tauri-deno-ts/src/hooks/useGames.ts b/crates/lanspread-tauri-deno-ts/src/hooks/useGames.ts index 92c717e..de6fcbb 100644 --- a/crates/lanspread-tauri-deno-ts/src/hooks/useGames.ts +++ b/crates/lanspread-tauri-deno-ts/src/hooks/useGames.ts @@ -132,11 +132,15 @@ export const useGames = (rescanGameDir: () => void): UseGamesResult => { }); })); + // 'game-download-pre' confirms peer metadata was found. The backend may still + // reject the download during majority validation (which now emits a terminal fail event), + // so keep showing CheckingPeers until 'game-download-begin' reports that transfer started. unlisteners.push(await listen('game-download-pre', (e) => { const id = e.payload as string; - updateById(id, { install_status: InstallStatus.Downloading, clearStatus: true }); + updateById(id, { install_status: InstallStatus.CheckingPeers, clearStatus: true }); })); + // 'game-download-begin' signals consensus size validation has completed and file transfer has started. unlisteners.push(await listen('game-download-begin', (e) => { const id = e.payload as string; updateById(id, { install_status: InstallStatus.Downloading, clearStatus: true });