refactor(tauri): use default managed runtime state

LanSpreadState now owns its empty initialization through Default. This keeps
the root runtime state construction in one place instead of building each
Arc<RwLock<_>> value inline before registering it with Tauri.

The setup hook now retrieves peer_game_db from the managed state and clones the
Arc before spawning async peer initialization. That preserves the existing
lifetime boundary while removing the separate outer peer_game_db binding.

There is no user-visible behavior change. The peer database, game list,
download tracking, games folder, and peer control channel still start empty and
are populated through the same setup and command paths.

Test Plan:
- cargo clippy
- cargo clippy --benches
- cargo clippy --tests
- cargo +nightly fmt

Refs: none
This commit is contained in:
2026-05-02 15:48:11 +02:00
parent 047cb72905
commit 3fb516af2b
@@ -16,12 +16,13 @@ use tokio::sync::{RwLock, mpsc::UnboundedSender};
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
/// Tauri-managed runtime state shared by commands and setup tasks.
#[derive(Default)]
struct LanSpreadState { struct LanSpreadState {
peer_ctrl: Arc<RwLock<Option<UnboundedSender<PeerCommand>>>>, peer_ctrl: Arc<RwLock<Option<UnboundedSender<PeerCommand>>>>,
games: Arc<RwLock<GameDB>>, games: Arc<RwLock<GameDB>>,
games_in_download: Arc<RwLock<HashSet<String>>>, games_in_download: Arc<RwLock<HashSet<String>>>,
games_folder: Arc<RwLock<String>>, games_folder: Arc<RwLock<String>>,
#[allow(dead_code)]
peer_game_db: Arc<RwLock<PeerGameDB>>, peer_game_db: Arc<RwLock<PeerGameDB>>,
} }
@@ -807,16 +808,6 @@ pub fn run() {
// channel to receive events from the peer // channel to receive events from the peer
let (tx_peer_event, mut rx_peer_event) = tokio::sync::mpsc::unbounded_channel::<PeerEvent>(); let (tx_peer_event, mut rx_peer_event) = tokio::sync::mpsc::unbounded_channel::<PeerEvent>();
let peer_game_db = Arc::new(RwLock::new(PeerGameDB::new()));
let lanspread_state = LanSpreadState {
peer_ctrl: Arc::new(RwLock::new(None)),
games: Arc::new(RwLock::new(GameDB::empty())),
games_in_download: Arc::new(RwLock::new(HashSet::new())),
games_folder: Arc::new(RwLock::new(String::new())),
peer_game_db: peer_game_db.clone(),
};
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_store::Builder::new().build()) .plugin(tauri_plugin_store::Builder::new().build())
.plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_dialog::init())
@@ -831,16 +822,15 @@ pub fn run() {
get_peer_count, get_peer_count,
get_game_thumbnail get_game_thumbnail
]) ])
.manage(lanspread_state) .manage(LanSpreadState::default())
.setup({ .setup({
let tx_peer_event_clone = tx_peer_event.clone(); let tx_peer_event_clone = tx_peer_event.clone();
let peer_game_db_clone = peer_game_db.clone();
move |app| { move |app| {
// Initialize peer system ONLY when games directory is set (games directory is mandatory) // Initialize peer system ONLY when games directory is set (games directory is mandatory)
// But the UI is responsive immediately - no blocking server discovery // But the UI is responsive immediately - no blocking server discovery
let app_handle_clone = app.handle().clone(); let app_handle_clone = app.handle().clone();
let tx_peer_event_for_spawn = tx_peer_event_clone.clone(); let tx_peer_event_for_spawn = tx_peer_event_clone.clone();
let peer_game_db_for_spawn = peer_game_db_clone.clone(); let peer_game_db_for_spawn = app.state::<LanSpreadState>().peer_game_db.clone();
tauri::async_runtime::spawn(async move { tauri::async_runtime::spawn(async move {
// Wait for games directory to be set by user (this is mandatory) // Wait for games directory to be set by user (this is mandatory)
loop { loop {