use log::info; use std::sync::{Arc, Mutex}; use dbus_crossroads::Crossroads; use dbus_tokio::connection; use dbus::{ message::MatchRule, nonblock::SyncConnection, channel::{Sender, MatchingReceiver}, Path, }; pub struct Endpoint { connection: Arc, implementation: T, } impl Endpoint { pub fn new(implementation: T) -> Self { let (resource, connection) = connection::new_session_sync().unwrap(); // The resource is a task that should be spawned onto a tokio compatible // reactor ASAP. If the resource ever finishes, you lost connection to D-Bus. // // To shut down the connection, both call _handle.abort() and drop the connection. let _handle = tokio::spawn(async { let err = resource.await; panic!("Lost connection to D-Bus: {}", err); }); Self { connection, implementation } } pub async fn register( &self, name: &str, path: &str, register_fn: F ) where F: Fn(&mut Crossroads) -> R, R: IntoIterator>, { let dbus_path = String::from(path); self.connection .request_name(name, false, true, false) .await .expect("Unable to acquire dbus name"); let mut cr = Crossroads::new(); // Enable async support for the crossroads instance. // (Currently irrelevant since dbus generates sync code) 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) } }