diff --git a/espanso/src/cli/daemon/mod.rs b/espanso/src/cli/daemon/mod.rs index 6747556..631eec1 100644 --- a/espanso/src/cli/daemon/mod.rs +++ b/espanso/src/cli/daemon/mod.rs @@ -90,20 +90,26 @@ fn daemon_main(args: CliModuleArgs) -> i32 { // at a given time. let mut _current_troubleshoot_guard = None; - let config_store = match troubleshoot::load_config_or_troubleshoot(&paths, &paths_overrides) { - troubleshoot::LoadResult::Correct(load_result) => load_result.config_store, - troubleshoot::LoadResult::Warning(load_result, guard) => { - _current_troubleshoot_guard = guard; - load_result.config_store - } - troubleshoot::LoadResult::Fatal(mut guard) => { - guard - .wait() - .expect("unable to wait for troubleshooting guard"); - error!("critical error while loading config"); - return DAEMON_FATAL_CONFIG_ERROR; - } - }; + let (watcher_notify, watcher_signal) = unbounded::<()>(); + + watcher::initialize_and_spawn(&paths.config, watcher_notify) + .expect("unable to initialize config watcher thread"); + + let config_store = + match troubleshoot::load_config_or_troubleshoot_until_config_is_correct_or_abort( + &paths, + &paths_overrides, + watcher_signal.clone(), + ) { + Ok((result, guard)) => { + _current_troubleshoot_guard = guard; + result.config_store + } + Err(err) => { + error!("critical error while loading config: {}", err); + return DAEMON_FATAL_CONFIG_ERROR; + } + }; info!("espanso version: {}", VERSION); // TODO: print os system and version? (with os_info crate) @@ -126,13 +132,6 @@ fn daemon_main(args: CliModuleArgs) -> i32 { ipc::initialize_and_spawn(&paths.runtime, exit_notify.clone()) .expect("unable to initialize ipc server for daemon"); - let (watcher_notify, watcher_signal) = unbounded::<()>(); - - if config_store.default().auto_restart() { - watcher::initialize_and_spawn(&paths.config, watcher_notify) - .expect("unable to initialize config watcher thread"); - } - if cli_args.is_present("show-welcome") { ui::show_welcome_screen(&preferences); } @@ -140,6 +139,10 @@ fn daemon_main(args: CliModuleArgs) -> i32 { loop { select! { recv(watcher_signal) -> _ => { + if !config_store.default().auto_restart() { + continue; + } + info!("configuration change detected, restarting worker process..."); // Before killing the previous worker, we make sure there is no fatal error diff --git a/espanso/src/cli/daemon/troubleshoot.rs b/espanso/src/cli/daemon/troubleshoot.rs index ddc4e6a..12b132c 100644 --- a/espanso/src/cli/daemon/troubleshoot.rs +++ b/espanso/src/cli/daemon/troubleshoot.rs @@ -18,9 +18,13 @@ */ use std::process::{Child, Command}; +use std::time::Duration; -use anyhow::{Result}; +use anyhow::{bail, Result}; +use crossbeam::channel::Receiver; +use crossbeam::select; use espanso_path::Paths; +use log::info; use crate::cli::util::CommandExt; use crate::cli::PathsOverrides; @@ -47,10 +51,15 @@ impl TroubleshootGuard { pub fn new(child: Child) -> Self { Self { child } } + #[allow(dead_code)] pub fn wait(&mut self) -> Result<()> { self.child.wait()?; Ok(()) } + pub fn try_wait(&mut self) -> Result { + let result = self.child.try_wait()?; + Ok(result.is_some()) + } } impl Drop for TroubleshootGuard { @@ -97,3 +106,44 @@ pub fn load_config_or_troubleshoot(paths: &Paths, paths_overrides: &PathsOverrid } } } + +pub fn load_config_or_troubleshoot_until_config_is_correct_or_abort( + paths: &Paths, + paths_overrides: &PathsOverrides, + watcher_receiver: Receiver<()>, +) -> Result<(ConfigLoadResult, Option)> { + let mut _troubleshoot_guard = None; + + loop { + // If the loading process is fatal, we keep showing the troubleshooter until + // either the config is correct or the user aborts by closing the troubleshooter + _troubleshoot_guard = match load_config_or_troubleshoot(paths, paths_overrides) { + LoadResult::Correct(result) => return Ok((result, None)), + LoadResult::Warning(result, guard) => return Ok((result, guard)), + LoadResult::Fatal(guard) => Some(guard), + }; + + loop { + select! { + recv(watcher_receiver) -> _ => { + info!("config change detected, reloading configs..."); + + break + }, + default(Duration::from_millis(500)) => { + if let Some(guard) = &mut _troubleshoot_guard { + if let Ok(ended) = guard.try_wait() { + if ended { + bail!("user aborted troubleshooter"); + } + } else { + bail!("unable to wait for troubleshooter"); + } + } else { + bail!("no troubleshoot guard found"); + } + } + } + } + } +}