mod daemon; mod dbus; use log::LevelFilter; use std::future; use daemon::signals::Signal; use daemon::{Attachment, Daemon}; use dbus::endpoint::Endpoint as DbusEndpoint; use dbus::interface; use dbus::server_impl::ServerImpl; use dbus_tokio::connection; fn initialize_logging() { // Weird: is this the best way to do this? let log_level = std::env::var("RUST_LOG") .map(|s| s.parse::().unwrap_or(LevelFilter::Info)) .unwrap_or(LevelFilter::Info); env_logger::Builder::from_default_env() .format_timestamp_secs() .filter_level(log_level) .init(); } #[tokio::main] async fn main() { initialize_logging(); // Create the daemon let mut daemon = Daemon::new() .map_err(|e| { log::error!("Failed to start daemon: {}", e); std::process::exit(1); }) .unwrap(); // Initialize dbus session connection 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); }); // Acquire the name connection .request_name(interface::NAME, false, true, false) .await .expect("Unable to acquire dbus name"); let attachment = Attachment { guid: "asdf".into(), path: "/dev/null".into(), downloaded: false, }; let att_endpoint = DbusEndpoint::new(connection.clone(), attachment); att_endpoint .register_object("/net/buzzert/kordophonecd/attachments/test", |cr| { vec![interface::register_net_buzzert_kordophone_attachment(cr)] }) .await; // Create the server implementation let server = ServerImpl::new(connection.clone(), daemon.event_sender.clone()); // Register DBus interfaces with endpoint let endpoint = DbusEndpoint::new(connection.clone(), server); endpoint .register_object(interface::OBJECT_PATH, |cr| { vec![ interface::register_net_buzzert_kordophone_repository(cr), interface::register_net_buzzert_kordophone_settings(cr), ] }) .await; let mut signal_receiver = daemon.obtain_signal_receiver(); tokio::spawn(async move { use dbus::interface::signals as DbusSignals; while let Some(signal) = signal_receiver.recv().await { match signal { Signal::ConversationsUpdated => { log::debug!("Sending signal: ConversationsUpdated"); endpoint .send_signal(interface::OBJECT_PATH, DbusSignals::ConversationsUpdated {}) .unwrap_or_else(|_| { log::error!("Failed to send signal"); 0 }); } Signal::MessagesUpdated(conversation_id) => { log::debug!( "Sending signal: MessagesUpdated for conversation {}", conversation_id ); endpoint .send_signal( interface::OBJECT_PATH, DbusSignals::MessagesUpdated { conversation_id }, ) .unwrap_or_else(|_| { log::error!("Failed to send signal"); 0 }); } } } }); daemon.run().await; future::pending::<()>().await; unreachable!() }