From 504fcb52c1a503a7325266d87e47fd87194f3f5b Mon Sep 17 00:00:00 2001 From: hsqStephenZhang Date: Tue, 28 Apr 2026 10:05:29 +0200 Subject: [PATCH 1/2] fix: use oneshot channel to send search outcome back --- cardinal/src-tauri/src/background.rs | 6 ++---- cardinal/src-tauri/src/commands.rs | 12 +++++------- cardinal/src-tauri/src/lib.rs | 5 +---- doc/inner/background-event-loop.md | 10 ++++++---- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/cardinal/src-tauri/src/background.rs b/cardinal/src-tauri/src/background.rs index 31d075c7..c4514da4 100644 --- a/cardinal/src-tauri/src/background.rs +++ b/cardinal/src-tauri/src/background.rs @@ -12,8 +12,7 @@ use once_cell::sync::Lazy; use parking_lot::Mutex; use rayon::spawn; use search_cache::{ - HandleFSEError, SearchCache, SearchOptions, SearchOutcome, SearchResultNode, SlabIndex, - WalkData, + HandleFSEError, SearchCache, SearchOptions, SearchResultNode, SlabIndex, WalkData, }; use search_cancel::CancellationToken; use serde::Serialize; @@ -44,7 +43,6 @@ pub struct BackgroundLoopChannels { pub finish_rx: Receiver>>, pub update_window_state_rx: Receiver<()>, pub search_rx: Receiver, - pub result_tx: Sender>, pub node_info_rx: Receiver, pub icon_viewport_rx: Receiver<(u64, Vec)>, pub rescan_rx: Receiver, @@ -309,7 +307,6 @@ pub fn run_background_event_loop( finish_rx, update_window_state_rx, search_rx, - result_tx, node_info_rx, icon_viewport_rx, rescan_rx, @@ -355,6 +352,7 @@ pub fn run_background_event_loop( query, options, cancellation_token, + result_tx } = job.expect("Search channel closed"); let opts = SearchOptions::from(options); let payload = cache.search_with_options(&query, opts, cancellation_token); diff --git a/cardinal/src-tauri/src/commands.rs b/cardinal/src-tauri/src/commands.rs index 4fcd2a12..455db64a 100644 --- a/cardinal/src-tauri/src/commands.rs +++ b/cardinal/src-tauri/src/commands.rs @@ -11,7 +11,7 @@ use crate::{ use anyhow::{Result, anyhow}; use base64::{Engine as _, engine::general_purpose}; use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf}; -use crossbeam_channel::{Receiver, Sender, bounded}; +use crossbeam_channel::{Sender, bounded}; use objc2::{ rc::{Retained, autoreleasepool}, runtime::ProtocolObject, @@ -51,6 +51,7 @@ pub struct SearchJob { pub query: String, pub options: SearchOptionsPayload, pub cancellation_token: CancellationToken, + pub result_tx: Sender>, } #[derive(Debug, Clone)] @@ -67,10 +68,7 @@ struct SortedViewCache { pub struct SearchState { search_tx: Sender, - result_rx: Receiver>, - node_info_tx: Sender, - icon_viewport_tx: Sender<(u64, Vec)>, rescan_tx: Sender, watch_config_tx: Sender, @@ -81,7 +79,6 @@ pub struct SearchState { impl SearchState { pub fn new( search_tx: Sender, - result_rx: Receiver>, node_info_tx: Sender, icon_viewport_tx: Sender<(u64, Vec)>, rescan_tx: Sender, @@ -90,7 +87,6 @@ impl SearchState { ) -> Self { Self { search_tx, - result_rx, node_info_tx, icon_viewport_tx, rescan_tx, @@ -275,16 +271,18 @@ pub async fn search( let options = options.unwrap_or_default(); let cancellation_token = CancellationToken::new(version); + let (result_tx, result_rx) = bounded(1); if let Err(e) = state.search_tx.send(SearchJob { query, options, cancellation_token, + result_tx, }) { error!("Failed to send search request: {e:?}"); return Ok(SearchResponse::default()); } - match state.result_rx.recv() { + match result_rx.recv() { Ok(res) => res, Err(e) => { error!("Failed to receive search result: {e:?}"); diff --git a/cardinal/src-tauri/src/lib.rs b/cardinal/src-tauri/src/lib.rs index bb448b0f..ff373b46 100644 --- a/cardinal/src-tauri/src/lib.rs +++ b/cardinal/src-tauri/src/lib.rs @@ -24,7 +24,7 @@ use lifecycle::{ APP_QUIT, AppLifecycleState, EXIT_REQUESTED, emit_app_state, load_app_state, update_app_state, }; use once_cell::sync::OnceCell; -use search_cache::{SearchCache, SearchOutcome, SlabIndex}; +use search_cache::{SearchCache, SlabIndex}; use search_cancel::CancellationToken; use std::{ path::{Path, PathBuf}, @@ -58,7 +58,6 @@ pub fn run() -> Result<()> { let (finish_tx, finish_rx) = bounded::>>(1); let (search_tx, search_rx) = unbounded::(); - let (result_tx, result_rx) = unbounded::>(); let (node_info_tx, node_info_rx) = unbounded::(); let (icon_viewport_tx, icon_viewport_rx) = unbounded::<(u64, Vec)>(); let (rescan_tx, rescan_rx) = unbounded::(); @@ -115,7 +114,6 @@ pub fn run() -> Result<()> { let app = builder .manage(SearchState::new( search_tx, - result_rx, node_info_tx, icon_viewport_tx.clone(), rescan_tx.clone(), @@ -153,7 +151,6 @@ pub fn run() -> Result<()> { let channels = BackgroundLoopChannels { finish_rx, search_rx, - result_tx, node_info_rx, icon_viewport_rx, rescan_rx, diff --git a/doc/inner/background-event-loop.md b/doc/inner/background-event-loop.md index 138099b8..6bc56cb2 100644 --- a/doc/inner/background-event-loop.md +++ b/doc/inner/background-event-loop.md @@ -9,13 +9,15 @@ ## Channels ```text -search_rx query + SearchOptionsPayload + CancellationToken -result_tx SearchOutcome back to the command handler +search_rx SearchJob { query, options, cancellation_token, result_tx } + result_tx returns SearchOutcome back to the command handler + +node_info_rx NodeInfoRequest { slab_indices, response_tx } + response_tx returns SearchResultNode expansion -node_info_rx slab indices -> SearchResultNode expansion icon_viewport_rx visible slab indices for thumbnail prefetch icon_update_tx IconPayload batches back to the UI - +``` rescan_rx manual full-rescan requests watch_config_rx watch-root / ignore-path changes update_window_state_rx From 15939c26b97b7b5488fd53c7909a5d1daad1ba13 Mon Sep 17 00:00:00 2001 From: hsqStephenZhang Date: Tue, 28 Apr 2026 10:54:11 +0200 Subject: [PATCH 2/2] fix: doc --- doc/inner/background-event-loop.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/inner/background-event-loop.md b/doc/inner/background-event-loop.md index 6bc56cb2..990dbd73 100644 --- a/doc/inner/background-event-loop.md +++ b/doc/inner/background-event-loop.md @@ -9,15 +9,13 @@ ## Channels ```text -search_rx SearchJob { query, options, cancellation_token, result_tx } +search_rx query + SearchOptionsPayload + CancellationToken + result_tx result_tx returns SearchOutcome back to the command handler -node_info_rx NodeInfoRequest { slab_indices, response_tx } - response_tx returns SearchResultNode expansion - +node_info_rx slab indices -> SearchResultNode expansion icon_viewport_rx visible slab indices for thumbnail prefetch icon_update_tx IconPayload batches back to the UI -``` + rescan_rx manual full-rescan requests watch_config_rx watch-root / ignore-path changes update_window_state_rx