From 2c044de38f6adcfbd3cc64eb9fa55e67d61e6f94 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 2 Nov 2026 13:22:44 +0100 Subject: config: parse the config once and reuse it until the file changes Every command, status line and notification went through Config::load, which reads *and* rewrites config.toml, so `rsp status` alone touched the file on each call. The daemon now keeps a parsed copy and only stats the file to notice outside edits, so `rsp settings set` still takes effect immediately. Config::save refreshes the cached copy too, and Config::config_path is shared by the loader and the cache. --- src/daemon.rs | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'src/daemon.rs') diff --git a/src/daemon.rs b/src/daemon.rs index 4f95820..eaae64f 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -190,7 +190,7 @@ pub fn spawn_try_scrobble_current( } pub fn start_daemon() -> Result<(), Box> { - let config = Config::load()?; + let config = Config::cached()?; let socket_path = Config::get_socket_path(); let pid_path = get_pid_path(&config); @@ -365,7 +365,7 @@ pub fn start_daemon() -> Result<(), Box> { if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached().ok().and_then(|c| c.display_format.clone()); notification::notify_track(&track, fmt.as_deref()); break; } @@ -448,7 +448,7 @@ pub fn start_daemon() -> Result<(), Box> { } pub fn stop_daemon() -> Result<(), Box> { - let config = Config::load()?; + let config = Config::cached()?; let pid_path = get_pid_path(&config); match check_running_daemon(&pid_path) { @@ -708,7 +708,7 @@ enum LoadedLyrics { /// Build the "Now playing" header shown above a track's lyrics. fn lyrics_header(track: &Track) -> String { - let name = match Config::load() + let name = match Config::cached() .ok() .and_then(|c| c.display_format.clone()) .as_deref() @@ -1022,7 +1022,7 @@ fn process_command( "Paused" }; let track = Track::from_path(track_path); - let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached().ok().and_then(|c| c.display_format.clone()); let track_str = match fmt.as_deref() { Some(f) => track.format(f), None => track.display_string(0, 1), @@ -1094,7 +1094,7 @@ fn process_command( "Shutting down\n".to_string() } "reload" | "validate" => { - if let Ok(config) = Config::load() { + if let Ok(config) = Config::cached() { let temp_scrobbler = Scrobbler::new( config.lastfm_api_key.clone(), config.lastfm_api_secret.clone(), @@ -1137,7 +1137,7 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached().ok().and_then(|c| c.display_format.clone()); notification::notify_track(&track, fmt.as_deref()); "Playing next track\n".to_string() } else { @@ -1160,7 +1160,7 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached().ok().and_then(|c| c.display_format.clone()); notification::notify_track(&track, fmt.as_deref()); "Playing previous track\n".to_string() } else { @@ -1202,7 +1202,7 @@ fn process_command( "Usage: shuffle [on|off|album|albums]\n".to_string() }; // Save to config - if let Ok(mut config) = Config::load() { + if let Ok(mut config) = Config::cached() { if mode_str == "off" || mode_str == "none" { config.shuffle = None; } else { @@ -1242,7 +1242,7 @@ fn process_command( let (album_tracks, display_name): (Vec, String) = if path.is_file() { let canon = std::fs::canonicalize(&path).unwrap_or_else(|_| path.clone()); let (artist, album, _, _, _) = crate::database::extract_metadata(&canon); - let full: Vec = match Config::load() { + let full: Vec = match Config::cached() { Ok(config) => match crate::database::Database::open(&config) { Ok(db) => db .find_tracks_by_album(&artist, &album) @@ -1267,7 +1267,7 @@ fn process_command( .to_string(); (rotated, name) } else { - match Config::load() { + match Config::cached() { Ok(config) => match crate::database::Database::open(&config) { Ok(db) => { let tracks = match db.resolve_path(query_str) { @@ -1352,7 +1352,7 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached().ok().and_then(|c| c.display_format.clone()); notification::notify_track(track, fmt.as_deref()); } format!( @@ -1464,7 +1464,7 @@ fn process_command( s.start(track.clone()); } let fmt = - Config::load().ok().and_then(|c| c.display_format.clone()); + Config::cached().ok().and_then(|c| c.display_format.clone()); notification::notify_track(track, fmt.as_deref()); } format!("Playing now: {}\n", path_str) @@ -1486,7 +1486,7 @@ fn process_command( s.start(track.clone()); } let fmt = - Config::load().ok().and_then(|c| c.display_format.clone()); + Config::cached().ok().and_then(|c| c.display_format.clone()); notification::notify_track(track, fmt.as_deref()); } format!("Queued: {}\n", path_str) @@ -1514,8 +1514,9 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = - Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached() + .ok() + .and_then(|c| c.display_format.clone()); notification::notify_track(track, fmt.as_deref()); } format!("Playing now: {}\n", path_str) @@ -1535,8 +1536,9 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = - Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached() + .ok() + .and_then(|c| c.display_format.clone()); notification::notify_track(&track, fmt.as_deref()); format!("Playing: {}\n", path_str) } else { @@ -1568,7 +1570,7 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load() + let fmt = Config::cached() .ok() .and_then(|c| c.display_format.clone()); notification::notify_track(track, fmt.as_deref()); @@ -1602,7 +1604,7 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load() + let fmt = Config::cached() .ok() .and_then(|c| c.display_format.clone()); notification::notify_track(track, fmt.as_deref()); @@ -1622,7 +1624,7 @@ fn process_command( _ => format!("Error: No audio files found in '{}'\n", path_str), } } else { - match Config::load() { + match Config::cached() { Ok(config) => match crate::database::Database::open(&config) { Ok(db) => { // Collect tracks: try hierarchical path first, fallback to search @@ -1666,7 +1668,7 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load() + let fmt = Config::cached() .ok() .and_then(|c| c.display_format.clone()); notification::notify_track(track, fmt.as_deref()); @@ -1710,7 +1712,7 @@ fn process_command( if let Ok(mut s) = scrobble_state.lock() { s.start(track.clone()); } - let fmt = Config::load() + let fmt = Config::cached() .ok() .and_then(|c| c.display_format.clone()); notification::notify_track( @@ -1772,7 +1774,7 @@ fn process_command( let current = audio.get_volume() as i8; let new_level = (current + sign * delta).clamp(0, 100) as u8; audio.set_volume(new_level as f32 / 100.0); - if let Ok(mut config) = Config::load() { + if let Ok(mut config) = Config::cached() { config.volume = Some(new_level); let _ = config.save(); } @@ -1781,7 +1783,7 @@ fn process_command( // Try absolute value if let Ok(level) = arg.parse::() { audio.set_volume(level as f32 / 100.0); - if let Ok(mut config) = Config::load() { + if let Ok(mut config) = Config::cached() { config.volume = Some(level); let _ = config.save(); } @@ -1811,7 +1813,7 @@ fn process_command( q.shuffled_indices().to_vec() }; let is_playing = audio.is_playing(); - let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); + let fmt = Config::cached().ok().and_then(|c| c.display_format.clone()); for (display_idx, &track_idx) in indices.iter().enumerate() { if let Some(track) = q.track_at(track_idx) { let track_str = match fmt.as_deref() { -- cgit v1.2.3