diff --git a/espanso/src/cli/daemon/mod.rs b/espanso/src/cli/daemon/mod.rs index 7adc2b8..6cd46d1 100644 --- a/espanso/src/cli/daemon/mod.rs +++ b/espanso/src/cli/daemon/mod.rs @@ -27,7 +27,14 @@ use espanso_ipc::IPCClient; use espanso_path::Paths; use log::{error, info, warn}; -use crate::{exit_code::{DAEMON_ALREADY_RUNNING, DAEMON_GENERAL_ERROR, DAEMON_SUCCESS, WORKER_EXIT_ALL_PROCESSES, WORKER_SUCCESS}, ipc::{create_ipc_client_to_worker, IPCEvent}, lock::{acquire_daemon_lock, acquire_worker_lock}}; +use crate::{ + exit_code::{ + DAEMON_ALREADY_RUNNING, DAEMON_GENERAL_ERROR, DAEMON_SUCCESS, WORKER_EXIT_ALL_PROCESSES, + WORKER_RESTART, WORKER_SUCCESS, + }, + ipc::{create_ipc_client_to_worker, IPCEvent}, + lock::{acquire_daemon_lock, acquire_worker_lock}, +}; use super::{CliModule, CliModuleArgs}; @@ -74,13 +81,11 @@ fn daemon_main(args: CliModuleArgs) -> i32 { spawn_worker(&paths, exit_notify.clone()); - ipc::initialize_and_spawn(&paths.runtime, exit_notify) + ipc::initialize_and_spawn(&paths.runtime, exit_notify.clone()) .expect("unable to initialize ipc server for daemon"); // TODO: start file watcher thread - let mut exit_code: i32 = DAEMON_SUCCESS; - loop { select! { recv(exit_signal) -> code => { @@ -89,24 +94,28 @@ fn daemon_main(args: CliModuleArgs) -> i32 { match code { WORKER_EXIT_ALL_PROCESSES => { info!("worker requested a general exit, quitting the daemon"); + break; + } + WORKER_RESTART => { + info!("worker requested a restart, spawning a new one..."); + spawn_worker(&paths, exit_notify.clone()); } _ => { error!("received unexpected exit code from worker {}, exiting", code); - exit_code = code + return code; } } }, Err(err) => { error!("received error when unwrapping exit_code: {}", err); - exit_code = DAEMON_GENERAL_ERROR; + return DAEMON_GENERAL_ERROR; }, } - break; }, } } - exit_code + DAEMON_SUCCESS } fn terminate_worker_if_already_running(runtime_dir: &Path, worker_ipc: impl IPCClient) { diff --git a/espanso/src/cli/worker/engine/mod.rs b/espanso/src/cli/worker/engine/mod.rs index d7c62bc..4458c32 100644 --- a/espanso/src/cli/worker/engine/mod.rs +++ b/espanso/src/cli/worker/engine/mod.rs @@ -27,7 +27,7 @@ use espanso_ui::{UIRemote, event::UIEvent}; use log::info; use ui::selector::MatchSelectorAdapter; -use crate::cli::worker::engine::{matcher::regex::RegexMatcherAdapterOptions, path::PathProviderAdapter}; +use crate::{cli::worker::engine::{matcher::regex::RegexMatcherAdapterOptions, path::PathProviderAdapter}, engine::event::ExitMode}; use super::ui::icon::IconPaths; @@ -48,7 +48,7 @@ pub fn initialize_and_spawn( ui_remote: Box, exit_signal: Receiver<()>, ui_event_receiver: Receiver, -) -> Result> { +) -> Result> { let handle = std::thread::Builder::new() .name("engine thread".to_string()) .spawn(move || { @@ -154,12 +154,12 @@ pub fn initialize_and_spawn( ); let mut engine = crate::engine::Engine::new(&funnel, &mut processor, &dispatcher); - let exit_all_processes = engine.run(); + let exit_mode = engine.run(); info!("engine eventloop has terminated, propagating exit event..."); ui_remote.exit(); - exit_all_processes + exit_mode })?; Ok(handle) diff --git a/espanso/src/cli/worker/engine/source/exit.rs b/espanso/src/cli/worker/engine/source/exit.rs index cd0dae9..2a50011 100644 --- a/espanso/src/cli/worker/engine/source/exit.rs +++ b/espanso/src/cli/worker/engine/source/exit.rs @@ -19,7 +19,7 @@ use crossbeam::channel::{Receiver, Select, SelectedOperation}; -use crate::engine::{event::{Event, EventType}, funnel}; +use crate::engine::{event::{Event, EventType, ExitMode}, funnel}; use super::sequencer::Sequencer; @@ -48,7 +48,7 @@ impl<'a> funnel::Source<'a> for ExitSource<'a> { .expect("unable to select data from ExitSource receiver"); Event { source_id: self.sequencer.next_id(), - etype: EventType::ExitRequested(false), + etype: EventType::ExitRequested(ExitMode::Exit), } } } \ No newline at end of file diff --git a/espanso/src/cli/worker/mod.rs b/espanso/src/cli/worker/mod.rs index 86c6702..a814d0a 100644 --- a/espanso/src/cli/worker/mod.rs +++ b/espanso/src/cli/worker/mod.rs @@ -20,7 +20,14 @@ use crossbeam::channel::unbounded; use log::{error, info}; -use crate::{exit_code::{WORKER_ALREADY_RUNNING, WORKER_EXIT_ALL_PROCESSES, WORKER_GENERAL_ERROR, WORKER_SUCCESS}, lock::acquire_worker_lock}; +use crate::{ + engine::event::ExitMode, + exit_code::{ + WORKER_ALREADY_RUNNING, WORKER_EXIT_ALL_PROCESSES, WORKER_GENERAL_ERROR, WORKER_RESTART, + WORKER_SUCCESS, + }, + lock::acquire_worker_lock, +}; use self::ui::util::convert_icon_paths_to_tray_vec; @@ -108,15 +115,20 @@ fn worker_main(args: CliModuleArgs) -> i32 { info!("waiting for engine exit mode..."); match engine_handle.join() { - Ok(exit_all_processes) => { - if exit_all_processes { - info!("exiting worker process and daemon..."); - return WORKER_EXIT_ALL_PROCESSES; - } else { + Ok(mode) => match mode { + ExitMode::Exit => { info!("exiting worker process..."); return WORKER_SUCCESS; } - } + ExitMode::ExitAllProcesses => { + info!("exiting worker process and daemon..."); + return WORKER_EXIT_ALL_PROCESSES; + } + ExitMode::RestartWorker => { + info!("exiting worker (to be restarted)"); + return WORKER_RESTART; + } + }, Err(err) => { error!("unable to read engine exit mode: {:?}", err); return WORKER_GENERAL_ERROR; diff --git a/espanso/src/engine/event/mod.rs b/espanso/src/engine/event/mod.rs index 8fe6d1a..2f52c43 100644 --- a/espanso/src/engine/event/mod.rs +++ b/espanso/src/engine/event/mod.rs @@ -48,8 +48,8 @@ impl Event { pub enum EventType { NOOP, ProcessingError(String), - ExitRequested(bool), // If true, exit also the daemon process and not just the worker - Exit(bool), + ExitRequested(ExitMode), + Exit(ExitMode), // Inputs Keyboard(input::KeyboardEvent), @@ -82,4 +82,11 @@ pub enum EventType { // UI ShowContextMenu(ui::ShowContextMenuEvent), +} + +#[derive(Debug, Clone)] +pub enum ExitMode { + Exit, + ExitAllProcesses, + RestartWorker, } \ No newline at end of file diff --git a/espanso/src/engine/mod.rs b/espanso/src/engine/mod.rs index 01b81a0..7045a95 100644 --- a/espanso/src/engine/mod.rs +++ b/espanso/src/engine/mod.rs @@ -19,7 +19,7 @@ use log::{debug}; -use self::{dispatch::Dispatcher, event::{Event, EventType}, funnel::{Funnel, FunnelResult}, process::Processor}; +use self::{dispatch::Dispatcher, event::{Event, EventType, ExitMode}, funnel::{Funnel, FunnelResult}, process::Processor}; pub mod dispatch; pub mod event; @@ -41,15 +41,15 @@ impl <'a> Engine<'a> { } } - pub fn run(&mut self) -> bool { + pub fn run(&mut self) -> ExitMode { loop { match self.funnel.receive() { FunnelResult::Event(event) => { let processed_events = self.processor.process(event); for event in processed_events { - if let EventType::Exit(exit_all_processes) = &event.etype { - debug!("exit event received, exiting engine"); - return *exit_all_processes; + if let EventType::Exit(mode) = &event.etype { + debug!("exit event received with mode {:?}, exiting engine", mode); + return mode.clone(); } self.dispatcher.dispatch(event); @@ -57,7 +57,7 @@ impl <'a> Engine<'a> { } FunnelResult::EndOfStream => { debug!("end of stream received"); - return false; + return ExitMode::Exit; } } } diff --git a/espanso/src/engine/process/middleware/context_menu.rs b/espanso/src/engine/process/middleware/context_menu.rs index 9a91d85..1bca094 100644 --- a/espanso/src/engine/process/middleware/context_menu.rs +++ b/espanso/src/engine/process/middleware/context_menu.rs @@ -20,10 +20,11 @@ use super::super::Middleware; use crate::engine::event::{ ui::{MenuItem, ShowContextMenuEvent, SimpleMenuItem}, - Event, EventType, + Event, EventType, ExitMode, }; const CONTEXT_ITEM_EXIT: u32 = 0; +const CONTEXT_ITEM_RELOAD: u32 = 1; pub struct ContextMenuMiddleware {} @@ -51,18 +52,30 @@ impl Middleware for ContextMenuMiddleware { event.source_id, EventType::ShowContextMenu(ShowContextMenuEvent { // TODO: add actual entries - items: vec![MenuItem::Simple(SimpleMenuItem { - id: CONTEXT_ITEM_EXIT, - label: "Exit espanso".to_string(), - })], + items: vec![ + MenuItem::Simple(SimpleMenuItem { + id: CONTEXT_ITEM_RELOAD, + label: "Reload config".to_string(), + }), + MenuItem::Separator, + MenuItem::Simple(SimpleMenuItem { + id: CONTEXT_ITEM_EXIT, + label: "Exit espanso".to_string(), + }), + ], }), ); } EventType::ContextMenuClicked(context_click_event) => { match context_click_event.context_item_id { - CONTEXT_ITEM_EXIT => { - Event::caused_by(event.source_id, EventType::ExitRequested(true)) - } + CONTEXT_ITEM_EXIT => Event::caused_by( + event.source_id, + EventType::ExitRequested(ExitMode::ExitAllProcesses), + ), + CONTEXT_ITEM_RELOAD => Event::caused_by( + event.source_id, + EventType::ExitRequested(ExitMode::RestartWorker), + ), custom => { // TODO: handle dynamic items todo!() diff --git a/espanso/src/engine/process/middleware/exit.rs b/espanso/src/engine/process/middleware/exit.rs index 177b7a7..205b5f1 100644 --- a/espanso/src/engine/process/middleware/exit.rs +++ b/espanso/src/engine/process/middleware/exit.rs @@ -36,9 +36,9 @@ impl Middleware for ExitMiddleware { } fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { - if let EventType::ExitRequested(exit_all_processes) = &event.etype { - debug!("received ExitRequested event with 'exit_all_processes: {}', dispatching exit", exit_all_processes); - return Event::caused_by(event.source_id, EventType::Exit(*exit_all_processes)); + if let EventType::ExitRequested(mode) = &event.etype { + debug!("received ExitRequested event with mode: {:?}, dispatching exit", mode); + return Event::caused_by(event.source_id, EventType::Exit(mode.clone())); } event diff --git a/espanso/src/exit_code.rs b/espanso/src/exit_code.rs index 6d4618e..26e0c38 100644 --- a/espanso/src/exit_code.rs +++ b/espanso/src/exit_code.rs @@ -21,6 +21,7 @@ pub const WORKER_SUCCESS: i32 = 0; pub const WORKER_ALREADY_RUNNING: i32 = 1; pub const WORKER_GENERAL_ERROR: i32 = 2; pub const WORKER_EXIT_ALL_PROCESSES: i32 = 101; +pub const WORKER_RESTART: i32 = 102; pub const DAEMON_SUCCESS: i32 = 0; pub const DAEMON_ALREADY_RUNNING: i32 = 1;