mod daemon; mod dbus; use log::LevelFilter; use std::future; use daemon::signals::Signal; use daemon::Daemon; use dbus::endpoint::DbusRegistry; 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_millis() .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"); // Create shared D-Bus registry let dbus_registry = DbusRegistry::new(connection.clone()); // Create and register server implementation let server = ServerImpl::new(daemon.event_sender.clone()); dbus_registry.register_object(interface::OBJECT_PATH, server, |cr| { vec![ interface::register_net_buzzert_kordophone_repository(cr), interface::register_net_buzzert_kordophone_settings(cr), ] }); 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"); dbus_registry .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 ); dbus_registry .send_signal( interface::OBJECT_PATH, DbusSignals::MessagesUpdated { conversation_id }, ) .unwrap_or_else(|_| { log::error!("Failed to send signal"); 0 }); } Signal::AttachmentDownloaded(attachment_id) => { log::debug!("Sending signal: AttachmentDownloaded for attachment {}", attachment_id); dbus_registry .send_signal(interface::OBJECT_PATH, DbusSignals::AttachmentDownloadCompleted { attachment_id }) .unwrap_or_else(|_| { log::error!("Failed to send signal"); 0 }); } Signal::AttachmentUploaded(upload_guid, attachment_guid) => { log::debug!("Sending signal: AttachmentUploaded for upload {}, attachment {}", upload_guid, attachment_guid); dbus_registry .send_signal(interface::OBJECT_PATH, DbusSignals::AttachmentUploadCompleted { upload_guid, attachment_guid }) .unwrap_or_else(|_| { log::error!("Failed to send signal"); 0 }); } } } }); daemon.run().await; future::pending::<()>().await; unreachable!() }