use log::info; use std::sync::{Arc, Mutex}; use dbus::{ channel::{MatchingReceiver, Sender}, message::MatchRule, nonblock::SyncConnection, Path, }; use dbus_crossroads::Crossroads; #[derive(Clone)] pub struct DbusRegistry { connection: Arc, crossroads: Arc>, message_handler_started: Arc>, } impl DbusRegistry { pub fn new(connection: Arc) -> Self { let mut cr = Crossroads::new(); // Enable async support for the crossroads instance. // (Currently irrelevant since dbus generates sync code) cr.set_async_support(Some(( connection.clone(), Box::new(|x| { tokio::spawn(x); }), ))); Self { connection, crossroads: Arc::new(Mutex::new(cr)), message_handler_started: Arc::new(Mutex::new(false)), } } pub fn register_object(&self, path: &str, implementation: T, register_fn: F) where T: Send + Clone + 'static, F: Fn(&mut Crossroads) -> R, R: IntoIterator>, { let dbus_path = String::from(path); let mut cr = self.crossroads.lock().unwrap(); let tokens: Vec<_> = register_fn(&mut cr).into_iter().collect(); cr.insert(dbus_path, &tokens, implementation); // Start message handler if not already started let mut handler_started = self.message_handler_started.lock().unwrap(); if !*handler_started { let crossroads_clone = self.crossroads.clone(); self.connection.start_receive( MatchRule::new_method_call(), Box::new(move |msg, conn| { let mut cr = crossroads_clone.lock().unwrap(); cr.handle_message(msg, conn).is_ok() }), ); *handler_started = true; info!(target: "dbus", "Started D-Bus message handler"); } info!(target: "dbus", "Registered object at {} with {} interfaces", path, tokens.len()); } pub fn send_signal(&self, path: &str, signal: S) -> Result where S: dbus::message::SignalArgs + dbus::arg::AppendAll, { let message = signal.to_emit_message(&Path::new(path).unwrap()); self.connection.send(message) } } // Keep the old Endpoint struct for backward compatibility during transition #[derive(Clone)] pub struct Endpoint { connection: Arc, implementation: T, } impl Endpoint { pub fn new(connection: Arc, implementation: T) -> Self { Self { connection, implementation, } } pub async fn register_object(&self, path: &str, register_fn: F) where F: Fn(&mut Crossroads) -> R, R: IntoIterator>, { let dbus_path = String::from(path); // Enable async support for the crossroads instance. // (Currently irrelevant since dbus generates sync code) let mut cr = Crossroads::new(); cr.set_async_support(Some(( self.connection.clone(), Box::new(|x| { tokio::spawn(x); }), ))); // Register the daemon as a D-Bus object with multiple interfaces let tokens: Vec<_> = register_fn(&mut cr).into_iter().collect(); cr.insert(dbus_path, &tokens, self.implementation.clone()); // Start receiving messages. self.connection.start_receive( MatchRule::new_method_call(), Box::new(move |msg, conn| cr.handle_message(msg, conn).is_ok()), ); info!(target: "dbus", "Registered endpoint at {} with {} interfaces", path, tokens.len()); } pub fn send_signal(&self, path: &str, signal: S) -> Result where S: dbus::message::SignalArgs + dbus::arg::AppendAll, { let message = signal.to_emit_message(&Path::new(path).unwrap()); self.connection.send(message) } }