#[cfg(target_os = "linux")] mod dbus; #[cfg(target_os = "macos")] mod xpc; use log::LevelFilter; use std::future; use kordophoned::daemon::Daemon; 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(); } #[cfg(target_os = "linux")] async fn start_ipc_agent(daemon: &mut Daemon) { use dbus::agent::DBusAgent; // Start the D-Bus agent (events in, signals out). let agent = DBusAgent::new(daemon.event_sender.clone(), daemon.obtain_signal_receiver()); tokio::spawn(async move { agent.run().await; }); } #[cfg(target_os = "macos")] async fn start_ipc_agent(daemon: &mut Daemon) { // Start the macOS XPC agent (events in, signals out) on a dedicated thread. let agent = xpc::agent::XpcAgent::new(daemon.event_sender.clone(), daemon.obtain_signal_receiver()); std::thread::spawn(move || { // Use a single-threaded Tokio runtime for the XPC agent. let rt = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .expect("Unable to create tokio runtime for XPC agent"); rt.block_on(agent.run()); }); } #[cfg(not(any(target_os = "linux", target_os = "macos")))] async fn start_ipc_agent(daemon: &mut Daemon) { panic!("Unsupported IPC platform"); } #[tokio::main] async fn main() { initialize_logging(); // Create the daemon let mut daemon = Daemon::new() .map_err(|e| { log::error!("Failed to initialize daemon: {}", e); std::process::exit(1); }) .unwrap(); // Start the IPC agent. start_ipc_agent(&mut daemon).await; // Run the main daemon loop. daemon.run().await; // Keep the process alive as long as any background tasks are running. future::pending::<()>().await; }