use std::time::Duration;
use anyhow::{Result, anyhow};
use repo::daemon::{
MountDaemonRequest, MountDaemonResponse, load_endpoint, mount_daemon_endpoint_path, pid_alive,
};
use super::client::{rpc, sweep_stale_mounts};
use crate::cli::Cli;
#[cfg(all(target_os = "linux", feature = "mount"))]
pub fn cmd_daemon_serve(cli: &Cli) -> Result<()> {
let repo_root = resolve_repo_root(cli)?;
super::server::run_mount_daemon(&repo_root)
}
#[cfg(not(all(target_os = "linux", feature = "mount")))]
pub fn cmd_daemon_serve(_cli: &Cli) -> Result<()> {
Err(
crate::cli::commands::mount_lifecycle::virtualized_unsupported_error()
.context("heddle daemon serve"),
)
}
pub fn cmd_daemon_status(cli: &Cli) -> Result<()> {
let repo_root = resolve_repo_root(cli)?;
let response = rpc(&repo_root, &MountDaemonRequest::Health {}, false)?;
match response {
Some(MountDaemonResponse::Health {
version,
ok,
uptime_s,
mount_count,
}) => {
println!(
"daemon: ok={ok} version={version} uptime_s={uptime_s} mount_count={mount_count}"
);
Ok(())
}
Some(MountDaemonResponse::Error { code, message, .. }) => {
Err(anyhow!("daemon health failed: [{code}] {message}"))
}
Some(other) => Err(anyhow!("unexpected daemon response: {other:?}")),
None => {
println!(
"daemon: not running (no live endpoint at {})",
mount_daemon_endpoint_path(&repo_root).display()
);
Ok(())
}
}
}
pub fn cmd_daemon_stop(cli: &Cli) -> Result<()> {
let repo_root = resolve_repo_root(cli)?;
let endpoint_path = mount_daemon_endpoint_path(&repo_root);
let recorded_pid = load_endpoint(&endpoint_path).ok().and_then(|e| e.pid);
match rpc(&repo_root, &MountDaemonRequest::Shutdown {}, false)? {
Some(MountDaemonResponse::Shutdown { ok: true, .. }) => {}
Some(MountDaemonResponse::Error { code, message, .. }) => {
return Err(anyhow!("daemon refused shutdown: [{code}] {message}"));
}
Some(other) => return Err(anyhow!("unexpected daemon response: {other:?}")),
None => {
println!("daemon: not running");
return Ok(());
}
}
for _ in 0..40 {
if !endpoint_path.exists() {
break;
}
std::thread::sleep(Duration::from_millis(50));
}
if let Some(pid) = recorded_pid {
for _ in 0..40 {
if !pid_alive(pid) {
break;
}
std::thread::sleep(Duration::from_millis(50));
}
}
sweep_stale_mounts(&repo_root);
println!("daemon: stopped");
Ok(())
}
fn resolve_repo_root(cli: &Cli) -> Result<std::path::PathBuf> {
if let Some(root) = cli.repo.as_ref() {
return Ok(root.clone());
}
let repo = repo::Repository::open(&std::env::current_dir()?)?;
Ok(repo.root().to_path_buf())
}