#[cfg(unix)]
mod client;
#[cfg(unix)]
mod idle;
#[cfg(unix)]
mod notify;
#[cfg(unix)]
mod paths;
#[cfg(unix)]
mod protocol;
#[cfg(unix)]
mod server;
#[cfg(unix)]
pub use client::{
flush as client_flush, ping, read_pid, response_found, response_messages, response_ok,
response_uuid, response_value, shutdown, Client,
};
#[cfg(unix)]
pub use notify::{subscribe, watch, EventHub, Notice};
#[cfg(unix)]
pub use paths::{daemon_dir, events_socket_path, pid_path, socket_path};
#[cfg(unix)]
pub use protocol::{ok_empty, Request, Response};
#[cfg(unix)]
pub use server::run as run_server;
use std::process::{Command, Stdio};
use crate::error::{Error, Result};
use crate::home::UnifierHome;
pub fn ensure_running(home: &UnifierHome) -> Result<()> {
if is_running(home) {
return Ok(());
}
start(home, false)
}
pub fn is_running(home: &UnifierHome) -> bool {
#[cfg(unix)]
{
Client::is_running(home)
}
#[cfg(not(unix))]
{
let _ = home;
false
}
}
pub fn start(home: &UnifierHome, foreground: bool) -> Result<()> {
#[cfg(not(unix))]
{
let _ = (home, foreground);
return Err(Error::msg("hot daemon requires a Unix platform"));
}
#[cfg(unix)]
{
if Client::is_running(home) {
return Err(Error::msg("daemon is already running"));
}
home.ensure()?;
std::fs::create_dir_all(crate::daemon::paths::daemon_dir(home))?;
if foreground {
return run_server(home.clone());
}
let exe = std::env::current_exe()?;
let mut cmd = Command::new(exe);
cmd.arg("daemon").arg("run");
if let Some(p) = home.global_path().to_str() {
cmd.args(["--home", p]);
}
if let Some(name) = home.chroot_name() {
cmd.args(["--chroot", name]);
}
cmd.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
let child = cmd.spawn()?;
wait_for_socket(home, child.id())?;
Ok(())
}
}
pub fn stop(home: &UnifierHome) -> Result<()> {
#[cfg(not(unix))]
{
let _ = home;
return Err(Error::msg("hot daemon requires a Unix platform"));
}
#[cfg(unix)]
{
shutdown(home)
}
}
pub fn status(home: &UnifierHome) -> Result<()> {
#[cfg(not(unix))]
{
let _ = home;
println!("daemon: unavailable (requires Unix)");
return Ok(());
}
#[cfg(unix)]
{
if Client::is_running(home) {
let pid = read_pid(home)?.unwrap_or(0);
println!("daemon: running (pid {pid})");
println!("socket: {}", socket_path(home).display());
println!("events: {}", events_socket_path(home).display());
} else {
println!("daemon: stopped");
}
Ok(())
}
}
pub fn flush(home: &UnifierHome) -> Result<()> {
#[cfg(not(unix))]
{
let _ = home;
return Err(Error::msg("hot daemon requires a Unix platform"));
}
#[cfg(unix)]
{
let dirty = client_flush(home)?;
if dirty {
println!("flushed dirty state to disk");
} else {
println!("nothing to flush");
}
Ok(())
}
}
#[cfg(unix)]
fn wait_for_socket(home: &UnifierHome, _pid: u32) -> Result<()> {
let path = socket_path(home);
for _ in 0..100 {
if path.exists() && Client::is_running(home) {
return ping(home);
}
std::thread::sleep(std::time::Duration::from_millis(50));
}
Err(Error::msg("daemon failed to start"))
}