mod config; mod event_log; mod event_store; mod hooks; mod launchd; mod lifecycle; mod persist; mod registry; mod server; mod snapshot_store; mod state_store; 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()?; let state_path = lifecycle::spacesh_dir()?.join("state.json"); let store: std::sync::Arc = std::sync::Arc::new(state_store::JsonStateStore::new(state_path)); let events_path = lifecycle::spacesh_dir()?.join("events.json"); let event_store: std::sync::Arc = std::sync::Arc::new(event_store::JsonEventStore::new(events_path)); let snapshots_dir = lifecycle::spacesh_dir()?.join("snapshots"); let snapshot_store: std::sync::Arc = std::sync::Arc::new(snapshot_store::JsonSnapshotStore::new(snapshots_dir)); eprintln!("spaceshd listening on {}", sock.display()); server::serve(&sock, store, event_store, snapshot_store).await }