From b89190c02fc514e6b6f47a4696bb06bdd081effe Mon Sep 17 00:00:00 2001 From: Alexander Olofsson Date: Sun, 14 Apr 2024 21:28:32 +0200 Subject: [PATCH] Add simple DBus system Fixes #640 --- Cargo.toml | 4 ++ src/dbus/mod.rs | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + 3 files changed, 158 insertions(+) create mode 100644 src/dbus/mod.rs diff --git a/Cargo.toml b/Cargo.toml index c86147eb..a97de70c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,6 +99,9 @@ tokio = { version = "1.24.2", default-features = false, features = [ ], optional = true } log = { version = "0.4.14", default-features = false, optional = true } +# DBus +zbus = { version = "4.1.2", optional = true} + [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] # WebAssembly in the Web js-sys = { version = "0.3.55", optional = true } @@ -175,6 +178,7 @@ wasm-web = [ ] networking = ["std", "splits-io-api"] auto-splitting = ["std", "livesplit-auto-splitting", "tokio", "log"] +dbus = ["tokio", "zbus"] [lib] bench = false diff --git a/src/dbus/mod.rs b/src/dbus/mod.rs new file mode 100644 index 00000000..cb77f16b --- /dev/null +++ b/src/dbus/mod.rs @@ -0,0 +1,152 @@ +//! The dbus module provides the functionality necessary to handle DBus +//! communication, specifically regarding reading and writing state to an +//! active timer. + +use crate::{ + timing::{SharedTimer, TimerPhase}, + TimeSpan +}; +use std::{ + future::pending, + thread, + // thread::JoinHandle +}; +use tokio::runtime; +use zbus::{ + connection, + interface, +}; + +// This type exists mainly to make registering the DBus interface easier. +#[derive(Clone)] +struct DBusTimer(SharedTimer); + +#[interface(name = "org.livesplit.LiveSplit")] +impl DBusTimer { + fn start(&self) { + self.0.write().unwrap().start(); + } + + fn split(&self) { + self.0.write().unwrap().split_or_start(); + } + + fn skip_split(&self) { + self.0.write().unwrap().skip_split(); + } + + fn undo_split(&self) { + self.0.write().unwrap().undo_split(); + } + + fn toggle_pause(&self) { + self.0.write().unwrap().toggle_pause_or_start(); + } + + fn reset(&self) { + self.0.write().unwrap().reset(true); + } + + fn undo_all_pauses(&self) { + self.0.write().unwrap().undo_all_pauses(); + } + + + #[zbus(property)] + fn comparison(&self) -> String { + self.0.write().unwrap().current_comparison().to_string() + } + #[zbus(property)] + fn set_comparison(&self, comparison: &str) { + let _ = self.0.write().unwrap().set_current_comparison(comparison); + } + + fn previous_comparison(&self) { + self.0.write().unwrap().switch_to_previous_comparison(); + } + + fn next_comparison(&self) { + self.0.write().unwrap().switch_to_next_comparison(); + } + + + fn toggle_timing_method(&self) { + self.0.write().unwrap().toggle_timing_method(); + } + + fn set_game_time(&self, time: f64) { + self.0.write().unwrap().set_game_time(TimeSpan::from_seconds(time)); + } + + fn pause_game_time(&self) { + self.0.write().unwrap().pause_game_time(); + } + + fn resume_game_time(&self) { + self.0.write().unwrap().resume_game_time(); + } + + fn set_variable(&self, name: &str, value: &str) { + self.0.write().unwrap().set_custom_variable(name, value); + } + + #[zbus(property)] + fn running(&self) -> bool { + self.0.write().unwrap().current_phase() == TimerPhase::Running + } + #[zbus(property)] + fn set_running(&self, running: bool) { + if running { + match self.0.write().unwrap().current_phase() { + TimerPhase::Paused => self.0.write().unwrap().resume(), + TimerPhase::NotRunning => self.0.write().unwrap().start(), + _ => {} + }; + } else { + self.0.write().unwrap().pause(); + } + } +} + +/// A system reference that will spin up a background thread to handle DBus +/// communication. +pub struct DBusSystem { + //dbus_worker: JoinHandle>, +} + +impl DBusSystem { + /// Starts the DBus system, will take ownership of the name and handle + /// requests in the background. + pub fn new(timer: SharedTimer) -> Self { + let dbus_timer = DBusTimer(timer); + // let dbus_worker = + thread::Builder::new() + .name("DBus Worker".into()) + .spawn(move || { + runtime::Builder::new_current_thread() + .enable_time() + .build() + .unwrap() + .block_on(run_dbus(dbus_timer)) + }) + .unwrap(); + + Self { + // dbus_worker, + } + } +} + +async fn run_dbus( + timer: DBusTimer, +) -> zbus::Result<()> { + let _conn = connection::Builder::session()? + .name("org.livesplit.LiveSplit")? + .serve_at("/org/livesplit/LiveSplit", timer)? + .build() + .await?; + + loop { + pending::<()>().await; + } +} diff --git a/src/lib.rs b/src/lib.rs index c089f784..d99798dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,8 @@ pub mod analysis; pub mod auto_splitting; pub mod comparison; pub mod component; +#[cfg(feature = "dbus")] +pub mod dbus; #[cfg(feature = "std")] mod hotkey_config; #[cfg(feature = "std")]