use std::fs;
use std::io::Write;
use crate::config::{LinksRegistry, SyncorConfig, SyncorPaths};
use crate::error::Result;
pub struct DaemonManager {
paths: SyncorPaths,
config: SyncorConfig,
}
impl DaemonManager {
pub fn new(paths: SyncorPaths, config: SyncorConfig) -> Self {
Self { paths, config }
}
pub async fn run(&self) -> Result<()> {
self.paths.ensure_dirs()?;
let pid = std::process::id();
let pid_path = self.paths.pid_file();
{
let mut f = fs::File::create(&pid_path)?;
writeln!(f, "{}", pid)?;
}
tracing::info!("daemon started (pid {})", pid);
let registry = LinksRegistry::load(&self.paths.links_file())?;
let link_count = registry.iter().count();
tracing::info!("loaded {} link(s) from registry", link_count);
tracing::info!(
"daemon ready (debounce={}s, poll={}s)",
self.config.debounce_secs,
self.config.default_poll_interval_secs,
);
let (_tx, rx) = tokio::sync::oneshot::channel::<()>();
let _ = rx.await;
let _ = fs::remove_file(&pid_path);
tracing::info!("daemon exited cleanly");
Ok(())
}
pub fn is_running(paths: &SyncorPaths) -> bool {
let pid_path = paths.pid_file();
if !pid_path.exists() {
return false;
}
let pid: i32 = match fs::read_to_string(&pid_path)
.ok()
.and_then(|s| s.trim().parse().ok())
{
Some(p) => p,
None => return false,
};
(unsafe { libc::kill(pid, 0) }) == 0
}
pub fn cleanup_stale(paths: &SyncorPaths) {
let pid_path = paths.pid_file();
let sock_path = paths.socket_path();
if pid_path.exists() {
let _ = fs::remove_file(&pid_path);
tracing::debug!("removed stale pid file: {}", pid_path.display());
}
if sock_path.exists() {
let _ = fs::remove_file(&sock_path);
tracing::debug!("removed stale socket: {}", sock_path.display());
}
}
}