From 1a8b6a7398b12b3686b80c6228875a79e7165a26 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sun, 18 Feb 2024 20:30:33 -0800 Subject: [PATCH] feat(client): introduce komorebi-client crate This commit introduces the komorebi-client library crate for other Rust applications to interact with a running instance of komorebi over Unix Domain Sockets. Currently the crate re-exports everything one might find in the komorebi::State struct and everything that is publicly exposed in komorebi-core. Public types and methods are still lacking documentation, and this crate should not be published on crates.io until this is no longer the case. --- Cargo.lock | 10 +++++ Cargo.toml | 1 + README.md | 6 +-- komorebi-client/Cargo.toml | 12 ++++++ komorebi-client/src/lib.rs | 79 ++++++++++++++++++++++++++++++++++++++ komorebi/src/lib.rs | 2 +- komorebi/src/winevent.rs | 6 ++- 7 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 komorebi-client/Cargo.toml create mode 100644 komorebi-client/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 27a8ae19..7da396e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -841,6 +841,16 @@ dependencies = [ "winreg 0.52.0", ] +[[package]] +name = "komorebi-client" +version = "0.1.22-dev.0" +dependencies = [ + "komorebi", + "komorebi-core", + "serde_json", + "uds_windows", +] + [[package]] name = "komorebi-core" version = "0.1.22-dev.0" diff --git a/Cargo.toml b/Cargo.toml index a19813fe..ad6df9e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ resolver = "2" members = [ "derive-ahk", "komorebi", + "komorebi-client", "komorebi-core", "komorebic", "komorebic-no-console", diff --git a/README.md b/README.md index 8bca40ba..6f9b17b3 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ if you want to test them together or create a build with everything integrated. ## Refactors to the codebase must have prior approval -`komorebi` is mature codebase with an internal consistency and structure that has developed organically over close to +`komorebi` is a mature codebase with an internal consistency and structure that has developed organically over close to half a decade. There are [countless hours of live coding videos](https://youtube.com/@LGUG2Z) demonstrating work on this project and @@ -138,8 +138,8 @@ distinguishing monitors by manufacturer hardware identifiers and video card port Refactors to the structure of the codebase are not taken lightly and require prior discussion and approval. -Please do not start refactoring the codebase with the expectation of having your changes integrated into the codebase -until you receive an explicit approval or a request to do so. +Please do not start refactoring the codebase with the expectation of having your changes integrated until you receive an +explicit approval or a request to do so. Similarly, when implementing features and bug fixes, please stick to the structure of the codebase as much as possible and do not take this as an opportunity to do some "refactoring along the way". diff --git a/komorebi-client/Cargo.toml b/komorebi-client/Cargo.toml new file mode 100644 index 00000000..3ce29195 --- /dev/null +++ b/komorebi-client/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "komorebi-client" +version = "0.1.22-dev.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +komorebi = { path = "../komorebi" } +komorebi-core = { path = "../komorebi-core" } +uds_windows = "1" +serde_json = "1" diff --git a/komorebi-client/src/lib.rs b/komorebi-client/src/lib.rs new file mode 100644 index 00000000..589142c0 --- /dev/null +++ b/komorebi-client/src/lib.rs @@ -0,0 +1,79 @@ +#![warn(clippy::all, clippy::nursery, clippy::pedantic)] +#![allow(clippy::missing_errors_doc)] + +pub use komorebi::container::Container; +pub use komorebi::monitor::Monitor; +pub use komorebi::ring::Ring; +pub use komorebi::window::Window; +pub use komorebi::window_manager_event::WindowManagerEvent; +pub use komorebi::workspace::Workspace; +pub use komorebi::Notification; +pub use komorebi::NotificationEvent; +pub use komorebi::State; +pub use komorebi_core::Arrangement; +pub use komorebi_core::Axis; +pub use komorebi_core::CustomLayout; +pub use komorebi_core::CycleDirection; +pub use komorebi_core::DefaultLayout; +pub use komorebi_core::Direction; +pub use komorebi_core::Layout; +pub use komorebi_core::OperationDirection; +pub use komorebi_core::Rect; +pub use komorebi_core::SocketMessage; + +use komorebi::DATA_DIR; + +use std::io::BufReader; +use std::io::Read; +use std::io::Write; +use std::net::Shutdown; +pub use uds_windows::UnixListener; +use uds_windows::UnixStream; + +const KOMOREBI: &str = "komorebi.sock"; + +pub fn send_message(message: &SocketMessage) -> std::io::Result<()> { + let socket = DATA_DIR.join(KOMOREBI); + let mut connected = false; + while !connected { + if let Ok(mut stream) = UnixStream::connect(&socket) { + connected = true; + stream.write_all(serde_json::to_string(message)?.as_bytes())?; + } + } + + Ok(()) +} +pub fn send_query(message: &SocketMessage) -> std::io::Result { + let socket = DATA_DIR.join(KOMOREBI); + + let mut stream = UnixStream::connect(socket)?; + stream.write_all(serde_json::to_string(message)?.as_bytes())?; + stream.shutdown(Shutdown::Write)?; + + let mut reader = BufReader::new(stream); + let mut response = String::new(); + reader.read_to_string(&mut response)?; + + Ok(response) +} + +pub fn subscribe(name: &str) -> std::io::Result { + let socket = DATA_DIR.join(name); + + match std::fs::remove_file(&socket) { + Ok(()) => {} + Err(error) => match error.kind() { + std::io::ErrorKind::NotFound => {} + _ => { + return Err(error); + } + }, + }; + + let listener = UnixListener::bind(&socket)?; + + send_message(&SocketMessage::AddSubscriberSocket(name.to_string()))?; + + Ok(listener) +} diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index 1fb868a8..413c93ba 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -170,7 +170,7 @@ lazy_static! { } }) }; - static ref DATA_DIR: PathBuf = dirs::data_local_dir().expect("there is no local data directory").join("komorebi"); + pub static ref DATA_DIR: PathBuf = dirs::data_local_dir().expect("there is no local data directory").join("komorebi"); pub static ref AHK_EXE: String = { let mut ahk: String = String::from("autohotkey.exe"); diff --git a/komorebi/src/winevent.rs b/komorebi/src/winevent.rs index 53eb3505..9d0968bd 100644 --- a/komorebi/src/winevent.rs +++ b/komorebi/src/winevent.rs @@ -227,7 +227,9 @@ impl TryFrom for WinEvent { EVENT_OBJECT_SELECTIONWITHIN => Ok(Self::ObjectSelectionWithin), EVENT_OBJECT_SHOW => Ok(Self::ObjectShow), EVENT_OBJECT_STATECHANGE => Ok(Self::ObjectStateChange), - EVENT_OBJECT_TEXTEDIT_CONVERSIONTARGETCHANGED => Ok(Self::ObjectTextEditConversionTargetChanged), + EVENT_OBJECT_TEXTEDIT_CONVERSIONTARGETCHANGED => { + Ok(Self::ObjectTextEditConversionTargetChanged) + } EVENT_OBJECT_TEXTSELECTIONCHANGED => Ok(Self::ObjectTextSelectionChanged), EVENT_OBJECT_UNCLOAKED => Ok(Self::ObjectUncloaked), EVENT_OBJECT_VALUECHANGE => Ok(Self::ObjectValueChange), @@ -272,4 +274,4 @@ impl TryFrom for WinEvent { _ => Err(()), } } -} \ No newline at end of file +}