From 56b89432d3668d1acd968c7b07c4ad016f1d1800 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 10 May 2020 14:01:23 +0200 Subject: [PATCH] Implement Auto-reload on Windows. #239 --- src/engine.rs | 22 ++++++++++++++++- src/event/mod.rs | 2 ++ src/main.rs | 54 +++++++---------------------------------- src/protocol/mod.rs | 45 +++++++++++++++++++++++++++++++--- src/protocol/windows.rs | 31 +++++++++++++++-------- 5 files changed, 94 insertions(+), 60 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 3064430..50a41f0 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -32,6 +32,7 @@ use regex::{Regex}; use std::sync::Arc; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::Release; +use crate::protocol::{Service, IPCCommand, send_command_or_warn}; pub struct Engine<'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager, R: Renderer> { @@ -77,6 +78,18 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa item_id: ActionType::Toggle as i32, }); + menu.push(MenuItem{ + item_type: MenuItemType::Separator, + item_name: "".to_owned(), + item_id: 998, + }); + + menu.push(MenuItem{ + item_type: MenuItemType::Button, + item_name: "Reload configs".to_owned(), + item_id: ActionType::RestartWorker as i32, + }); + menu.push(MenuItem{ item_type: MenuItemType::Separator, item_name: "".to_owned(), @@ -332,15 +345,22 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager, R: Renderer> ActionEventReceiver for Engine<'a, S, C, M, U, R>{ fn on_action_event(&self, e: ActionType) { + let config = self.config_manager.default_config(); match e { ActionType::IconClick => { self.ui_manager.show_menu(self.build_menu()); }, - ActionType::Exit => { + ActionType::ExitWorker => { info!("terminating worker process"); self.ui_manager.cleanup(); exit(0); }, + ActionType::Exit => { + send_command_or_warn(Service::Daemon, config.clone(), IPCCommand::exit()); + }, + ActionType::RestartWorker => { + send_command_or_warn(Service::Daemon, config.clone(), IPCCommand::restart_worker()); + }, _ => {} } } diff --git a/src/event/mod.rs b/src/event/mod.rs index 254762a..dcecb82 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -38,6 +38,7 @@ pub enum ActionType { Enable = 4, Disable = 5, RestartWorker = 6, + ExitWorker = 7, } impl From for ActionType { @@ -49,6 +50,7 @@ impl From for ActionType { 4 => ActionType::Enable, 5 => ActionType::Disable, 6 => ActionType::RestartWorker, + 7 => ActionType::ExitWorker, _ => ActionType::Noop, } } diff --git a/src/main.rs b/src/main.rs index 7026c4d..47cd94e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -382,11 +382,7 @@ fn daemon_main(config_set: ConfigSet) { match event { Event::Action(ActionType::RestartWorker) => { // Terminate the worker process - let ipc_client = protocol::get_ipc_client(Service::Worker, config_set.default.clone()); - ipc_client.send_command(IPCCommand { - id: "exit".to_owned(), - payload: "".to_owned(), - }); + send_command_or_warn(Service::Worker, config_set.default.clone(), IPCCommand::exit_worker()); std::thread::sleep(Duration::from_millis(500)); @@ -394,11 +390,7 @@ fn daemon_main(config_set: ConfigSet) { crate::process::spawn_process(&espanso_path.to_string_lossy().to_string(), &vec!("worker".to_owned(), "--reload".to_owned())); }, Event::Action(ActionType::Exit) => { - let ipc_client = protocol::get_ipc_client(Service::Worker, config_set.default.clone()); - ipc_client.send_command(IPCCommand { - id: "exit".to_owned(), - payload: "".to_owned(), - }); + send_command_or_warn(Service::Worker, config_set.default.clone(), IPCCommand::exit_worker()); std::thread::sleep(Duration::from_millis(200)); @@ -408,9 +400,8 @@ fn daemon_main(config_set: ConfigSet) { _ => { // Forward the command to the worker let command = IPCCommand::from(event); - let ipc_client = protocol::get_ipc_client(Service::Worker, config_set.default.clone()); if let Some(command) = command { - ipc_client.send_command(command); + send_command_or_warn(Service::Worker, config_set.default.clone(), command); } } } @@ -431,7 +422,7 @@ fn watcher_background(sender: Sender) { let config_path = crate::context::get_config_dir(); watcher.watch(&config_path, RecursiveMode::Recursive).expect("unable to start watcher"); - info!("watching for changes in path: {:?}", config_path); + info!("watching for changes in path: {}", config_path.to_string_lossy()); loop { @@ -558,7 +549,7 @@ fn worker_background(receive_channel: Receiver, config_set: ConfigSet, is vec!(&engine), ); - info!("espanso is running!"); + info!("worker is running!"); event_manager.eventloop(); } @@ -742,17 +733,7 @@ fn stop_main(config_set: ConfigSet) { exit(3); } - let res = send_command(Service::Daemon, config_set.default, IPCCommand{ - id: "exit".to_owned(), - payload: "".to_owned(), - }); - - if let Err(e) = res { - println!("{}", e); - exit(1); - }else{ - exit(0); - } + send_command_or_warn(Service::Daemon, config_set.default, IPCCommand::exit()); } /// Kill the daemon if running and start it again @@ -761,10 +742,7 @@ fn restart_main(config_set: ConfigSet) { let lock_file = acquire_lock(); if lock_file.is_none() { // Terminate the current espanso daemon - send_command(Service::Daemon, config_set.default.clone(), IPCCommand { - id: "exit".to_owned(), - payload: "".to_owned(), - }); + send_command_or_warn(Service::Daemon, config_set.default.clone(), IPCCommand::exit()); }else{ release_lock(lock_file.unwrap()); } @@ -859,10 +837,7 @@ fn detect_main() { /// Send the given command to the espanso daemon fn cmd_main(config_set: ConfigSet, matches: &ArgMatches) { let command = if matches.subcommand_matches("exit").is_some() { - Some(IPCCommand { - id: String::from("exit"), - payload: String::from(""), - }) + Some(IPCCommand::exit()) }else if matches.subcommand_matches("toggle").is_some() { Some(IPCCommand { id: String::from("toggle"), @@ -883,23 +858,12 @@ fn cmd_main(config_set: ConfigSet, matches: &ArgMatches) { }; if let Some(command) = command { - let res = send_command(Service::Daemon, config_set.default, command); - - if res.is_ok() { - exit(0); - }else{ - println!("{}", res.unwrap_err()); - } + send_command_or_warn(Service::Daemon, config_set.default, command); } exit(1); } -fn send_command(service: Service, config: Configs, command: IPCCommand) -> Result<(), String> { - let ipc_client = protocol::get_ipc_client(service, config); - ipc_client.send_command(command) -} - fn log_main() { let espanso_dir = context::get_data_dir(); let log_file_path = espanso_dir.join(LOG_FILE); diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index fbf1540..60dc784 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -40,6 +40,14 @@ pub trait IPCClient { fn send_command(&self, command: IPCCommand) -> Result<(), String>; } +pub fn send_command_or_warn(service: Service, configs: Configs, command: IPCCommand) { + let ipc_client = get_ipc_client(service, configs); + if let Err(e) = ipc_client.send_command(command) { + error!("unable to send command to IPC server"); + } +} + + #[derive(Serialize, Deserialize, Debug)] pub struct IPCCommand { pub id: String, @@ -54,6 +62,9 @@ impl IPCCommand { "exit" => { Some(Event::Action(ActionType::Exit)) }, + "wexit" => { + Some(Event::Action(ActionType::ExitWorker)) + }, "toggle" => { Some(Event::Action(ActionType::Toggle)) }, @@ -63,6 +74,9 @@ impl IPCCommand { "disable" => { Some(Event::Action(ActionType::Disable)) }, + "restartworker" => { + Some(Event::Action(ActionType::RestartWorker)) + }, "notify" => { Some(Event::System(SystemEvent::NotifyRequest(self.payload.clone()))) }, @@ -73,13 +87,36 @@ impl IPCCommand { pub fn from(event: Event) -> Option { match event { Event::Action(ActionType::Exit) => Some(IPCCommand{id: "exit".to_owned(), payload: "".to_owned()}), + Event::Action(ActionType::ExitWorker) => Some(IPCCommand{id: "wexit".to_owned(), payload: "".to_owned()}), Event::Action(ActionType::Toggle) => Some(IPCCommand{id: "toggle".to_owned(), payload: "".to_owned()}), Event::Action(ActionType::Enable) => Some(IPCCommand{id: "enable".to_owned(), payload: "".to_owned()}), Event::Action(ActionType::Disable) => Some(IPCCommand{id: "disable".to_owned(), payload: "".to_owned()}), + Event::Action(ActionType::RestartWorker) => Some(IPCCommand{id: "restartworker".to_owned(), payload: "".to_owned()}), Event::System(SystemEvent::NotifyRequest(message)) => Some(IPCCommand{id: "notify".to_owned(), payload: message}), _ => None } } + + pub fn exit() -> IPCCommand { + Self { + id: "exit".to_owned(), + payload: "".to_owned(), + } + } + + pub fn exit_worker() -> IPCCommand { + Self { + id: "wexit".to_owned(), + payload: "".to_owned(), + } + } + + pub fn restart_worker() -> IPCCommand { + Self { + id: "restartworker".to_owned(), + payload: "".to_owned(), + } + } } fn process_event(event_channel: &Sender, stream: Result) { @@ -147,11 +184,11 @@ pub fn get_ipc_client(service: Service, _: Configs) -> impl IPCClient { // WINDOWS IMPLEMENTATION #[cfg(target_os = "windows")] -pub fn get_ipc_server(config_set: Configs, event_channel: Sender) -> impl IPCServer { - windows::WindowsIPCServer::new(config_set, event_channel) +pub fn get_ipc_server(service: Service, config: Configs, event_channel: Sender) -> impl IPCServer { + windows::WindowsIPCServer::new(service, config, event_channel) } #[cfg(target_os = "windows")] -pub fn get_ipc_client(config_set: Configs) -> impl IPCClient { - windows::WindowsIPCClient::new(config_set) +pub fn get_ipc_client(service: Service, config: Configs) -> impl IPCClient { + windows::WindowsIPCClient::new(service, config) } \ No newline at end of file diff --git a/src/protocol/windows.rs b/src/protocol/windows.rs index 8cabd30..a995564 100644 --- a/src/protocol/windows.rs +++ b/src/protocol/windows.rs @@ -23,24 +23,33 @@ use std::net::{TcpListener, TcpStream}; use super::IPCCommand; use crate::event::*; -use crate::protocol::{process_event, send_command}; -use crate::config::ConfigSet; +use crate::protocol::{process_event, send_command, Service}; +use crate::config::{Configs}; pub struct WindowsIPCServer { - config_set: ConfigSet, + service: Service, + config: Configs, event_channel: Sender, } +fn to_port(config: &Configs, service: &Service) -> u16 { + let port = match service { + Service::Daemon => {config.ipc_server_port}, + Service::Worker => {config.worker_ipc_server_port}, + }; + port as u16 +} + impl WindowsIPCServer { - pub fn new(config_set: ConfigSet, event_channel: Sender) -> WindowsIPCServer { - WindowsIPCServer {config_set, event_channel} + pub fn new(service: Service, config: Configs, event_channel: Sender) -> WindowsIPCServer { + WindowsIPCServer {service, config, event_channel} } } impl super::IPCServer for WindowsIPCServer { fn start(&self) { let event_channel = self.event_channel.clone(); - let server_port = self.config_set.default.ipc_server_port; + let server_port = to_port(&self.config, &self.service); std::thread::Builder::new().name("ipc_server".to_string()).spawn(move || { let listener = TcpListener::bind( format!("127.0.0.1:{}", server_port) @@ -56,19 +65,21 @@ impl super::IPCServer for WindowsIPCServer { } pub struct WindowsIPCClient { - config_set: ConfigSet, + service: Service, + config: Configs, } impl WindowsIPCClient { - pub fn new(config_set: ConfigSet) -> WindowsIPCClient { - WindowsIPCClient{config_set} + pub fn new(service: Service, config: Configs) -> WindowsIPCClient { + WindowsIPCClient{service, config} } } impl super::IPCClient for WindowsIPCClient { fn send_command(&self, command: IPCCommand) -> Result<(), String> { + let port = to_port(&self.config, &self.service); let stream = TcpStream::connect( - ("127.0.0.1", self.config_set.default.ipc_server_port as u16) + ("127.0.0.1", port) ); send_command(command, stream)