diff --git a/Cargo.lock b/Cargo.lock index 8a3048a..2103613 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,6 +233,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", "simplelog 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -294,6 +295,11 @@ dependencies = [ "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.4.0" @@ -520,6 +526,11 @@ name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.99" @@ -538,6 +549,16 @@ dependencies = [ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_yaml" version = "0.8.9" @@ -747,6 +768,7 @@ dependencies = [ "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" @@ -777,8 +799,10 @@ dependencies = [ "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" "checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" "checksum simplelog 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe8c881061cce7ee205784634eda7a61922925e7cc2833188467d3a560e027" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" diff --git a/Cargo.toml b/Cargo.toml index 0d657e3..dfe9d1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ log = "0.4.8" simplelog = "0.7.1" zip = "0.5.3" fs2 = "0.4.3" +serde_json = "1.0.40" [target.'cfg(unix)'.dependencies] libc = "0.2.62" diff --git a/src/context/macos.rs b/src/context/macos.rs index 190a971..e609f95 100644 --- a/src/context/macos.rs +++ b/src/context/macos.rs @@ -108,7 +108,7 @@ extern fn icon_click_callback(_self: *mut c_void) { unsafe { let _self = _self as *mut MacContext; - let event = Event::Action(ActionEvent::IconClick); + let event = Event::Action(ActionType::IconClick); (*_self).send_channel.send(event).unwrap(); } } @@ -117,7 +117,7 @@ extern fn context_menu_click_callback(_self: *mut c_void, id: i32) { unsafe { let _self = _self as *mut MacContext; - let event = Event::Action(ActionEvent::ContextMenuClick(ActionType::from(id))); + let event = Event::Action(ActionType::from(id)); (*_self).send_channel.send(event).unwrap(); } } \ No newline at end of file diff --git a/src/context/windows.rs b/src/context/windows.rs index c918d01..a48fb92 100644 --- a/src/context/windows.rs +++ b/src/context/windows.rs @@ -127,7 +127,7 @@ extern fn icon_click_callback(_self: *mut c_void) { unsafe { let _self = _self as *mut WindowsContext; - let event = Event::Action(ActionEvent::IconClick); + let event = Event::Action(ActionType::IconClick); (*_self).send_channel.send(event).unwrap(); } } @@ -137,7 +137,7 @@ extern fn context_menu_click_callback(_self: *mut c_void, id: i32) { unsafe { let _self = _self as *mut WindowsContext; - let event = Event::Action(ActionEvent::ContextMenuClick(ActionType::from(id))); + let event = Event::Action(ActionType::from(id)); (*_self).send_channel.send(event).unwrap(); } } \ No newline at end of file diff --git a/src/engine.rs b/src/engine.rs index e8bb5d1..f5c8599 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -5,7 +5,7 @@ use crate::config::BackendType; use crate::clipboard::ClipboardManager; use log::{info}; use crate::ui::{UIManager, MenuItem, MenuItemType}; -use crate::event::{ActionEventReceiver, ActionEvent, ActionType}; +use crate::event::{ActionEventReceiver, ActionType}; use std::cell::RefCell; use std::process::exit; @@ -114,20 +114,16 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager> ActionEventReceiver for Engine<'a, S, C, M, U>{ - fn on_action_event(&self, e: ActionEvent) { + fn on_action_event(&self, e: ActionType) { match e { - ActionEvent::IconClick => { + ActionType::IconClick => { self.ui_manager.show_menu(self.build_menu()); }, - ActionEvent::ContextMenuClick(id) => { - match id { - ActionType::Exit => { - info!("Terminating expanso from the context menu"); - exit(0); - }, - _ => {} - } - } + ActionType::Exit => { + info!("Terminating espanso."); + exit(0); + }, + _ => {} } } } \ No newline at end of file diff --git a/src/event/mod.rs b/src/event/mod.rs index ead9efa..441e98e 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -4,21 +4,16 @@ use serde::{Serialize, Deserialize}; #[derive(Debug, Clone)] pub enum Event { - Action(ActionEvent), + Action(ActionType), Key(KeyEvent) } -#[derive(Debug, Clone)] -pub enum ActionEvent { - IconClick, - ContextMenuClick(ActionType) -} - #[derive(Debug, Clone)] pub enum ActionType { Noop = 0, Toggle = 1, Exit = 2, + IconClick = 3, } impl From for ActionType { @@ -26,6 +21,7 @@ impl From for ActionType { match id { 1 => ActionType::Toggle, 2 => ActionType::Exit, + 3 => ActionType::IconClick, _ => ActionType::Noop, } } @@ -59,5 +55,5 @@ pub trait KeyEventReceiver { } pub trait ActionEventReceiver { - fn on_action_event(&self, e: ActionEvent); + fn on_action_event(&self, e: ActionType); } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index eedfa72..8441d81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ use crate::event::manager::{DefaultEventManager, EventManager}; use crate::matcher::scrolling::ScrollingMatcher; use crate::system::SystemManager; use crate::ui::UIManager; +use crate::protocol::*; mod ui; mod event; @@ -29,6 +30,7 @@ mod system; mod context; mod matcher; mod keyboard; +mod protocol; mod clipboard; const VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -145,12 +147,15 @@ fn daemon_main(config_set: ConfigSet) { let (send_channel, receive_channel) = mpsc::channel(); - let context = context::new(send_channel); + let context = context::new(send_channel.clone()); thread::spawn(move || { daemon_background(receive_channel, config_set); }); + let ipc_manager = protocol::get_ipc_manager(send_channel.clone()); + ipc_manager.start_server(); + context.eventloop(); } @@ -257,7 +262,7 @@ fn detect_main() { println!("==> Title: '{}'", curr_title); println!("==> Class: '{}'", curr_class); println!("==> Executable: '{}'", curr_exec); - println!(""); + println!(); } last_title = curr_title; diff --git a/src/matcher/scrolling.rs b/src/matcher/scrolling.rs index ddc34eb..3de456c 100644 --- a/src/matcher/scrolling.rs +++ b/src/matcher/scrolling.rs @@ -1,6 +1,6 @@ use crate::matcher::{Match, MatchReceiver}; use std::cell::RefCell; -use crate::event::{KeyModifier, ActionEventReceiver, ActionEvent, ActionType}; +use crate::event::{KeyModifier, ActionEventReceiver, ActionType}; use crate::config::ConfigManager; use crate::event::KeyModifier::BACKSPACE; use std::time::SystemTime; @@ -123,15 +123,10 @@ impl <'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMa } impl <'a, R: MatchReceiver, M: ConfigManager<'a>> ActionEventReceiver for ScrollingMatcher<'a, R, M> { - fn on_action_event(&self, e: ActionEvent) { + fn on_action_event(&self, e: ActionType) { match e { - ActionEvent::ContextMenuClick(action_type) => { - match action_type { - ActionType::Toggle => { - self.toggle(); - }, - _ => {} - } + ActionType::Toggle => { + self.toggle(); }, _ => {} } diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs new file mode 100644 index 0000000..67684f2 --- /dev/null +++ b/src/protocol/mod.rs @@ -0,0 +1,40 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Result; +use std::sync::mpsc::Sender; +use crate::event::Event; +use crate::event::Event::*; +use crate::event::ActionType; +use crate::event::ActionType::*; + +#[cfg(target_os = "windows")] +mod windows; + +#[cfg(not(target_os = "windows"))] +mod unix; + +pub trait IPCManager { + fn start_server(&self); +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct IPCCommand { + id: String, + payload: String, +} + +impl IPCCommand { + fn to_event(&self) -> Option { + match self.id.as_ref() { + "exit" => { + Some(Event::Action(ActionType::Exit)) + }, + _ => None + } + } +} + +// UNIX IMPLEMENTATION +#[cfg(not(target_os = "windows"))] +pub fn get_ipc_manager(event_channel: Sender) -> impl IPCManager { + unix::UnixIPCManager::new(event_channel) +} \ No newline at end of file diff --git a/src/protocol/unix.rs b/src/protocol/unix.rs new file mode 100644 index 0000000..83d6734 --- /dev/null +++ b/src/protocol/unix.rs @@ -0,0 +1,63 @@ +use std::io::{BufRead, BufReader, Read}; +use std::os::unix::net::{UnixStream,UnixListener}; +use std::thread; +use log::{info, error}; +use std::sync::mpsc::Sender; +use super::IPCCommand; + +use crate::context; +use crate::context::get_data_dir; +use crate::event::*; + +const UNIX_SOCKET_NAME : &str = "espanso.sock"; + +pub struct UnixIPCManager { + event_channel: Sender, +} + +impl UnixIPCManager { + pub fn new(event_channel: Sender) -> UnixIPCManager { + UnixIPCManager{event_channel} + } +} + +impl super::IPCManager for UnixIPCManager { + fn start_server(&self) { + std::thread::spawn(|| { + let espanso_dir = context::get_data_dir(); + let unix_socket = espanso_dir.join(UNIX_SOCKET_NAME); + + std::fs::remove_file(unix_socket.clone()); + let listener = UnixListener::bind(unix_socket.clone()).expect("Can't bind to Unix Socket"); + + info!("Binded to IPC unix socket: {}", unix_socket.as_path().display()); + + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let mut json_str= String::new(); + let mut buf_reader = BufReader::new(stream); + buf_reader.read_to_string(&mut json_str); + + let command : Result = serde_json::from_str(&json_str); + match command { + Ok(command) => { + let event = command.to_event(); + if let Some(event) = event { + // TODO: send event to event channel + } + }, + Err(e) => { + error!("Error deserializing JSON command: {}", e); + }, + } + } + Err(err) => { + println!("Error: {}", err); + break; + } + } + } + }); + } +} \ No newline at end of file