mod launchd; mod lifecycle; mod registry; mod server; mod surface; use anyhow::Result; /// Test-only support shared across the crate's test modules. #[cfg(test)] pub(crate) mod test_support { use std::sync::{Mutex, MutexGuard}; /// Process-wide serialization lock for the heavy socket/PTY integration tests. /// These bind sockets and spawn real PTYs/processes; running several at once on a /// many-core box starves each other's tasks and trips timing assumptions. Unit /// tests stay parallel; only guarded integration tests serialize on this lock. static SERIAL: Mutex<()> = Mutex::new(()); /// Acquire the serial lock for the duration of a test. Poison-tolerant so one /// panicking test does not cascade-fail the rest. pub(crate) fn serial() -> MutexGuard<'static, ()> { SERIAL.lock().unwrap_or_else(|e| e.into_inner()) } } #[tokio::main] async fn main() -> Result<()> { let arg = std::env::args().nth(1); match arg.as_deref() { Some("install-agent") => { launchd::install_agent()?; println!("launchd agent installed"); Ok(()) } Some("--help") | Some("-h") => { println!("spaceshd [install-agent]"); Ok(()) } _ => run_daemon().await, } } async fn run_daemon() -> Result<()> { let Some(_lock) = lifecycle::acquire_instance_lock()? else { eprintln!("another spaceshd is already running"); return Ok(()); }; lifecycle::clear_stale_socket()?; let sock = lifecycle::socket_path()?; eprintln!("spaceshd listening on {}", sock.display()); server::serve(&sock).await }