use anyhow::{Result, anyhow};
use std::path::PathBuf;
use std::time::Duration;
use crate::cmd::Cmd;
use crate::multiplexer::{create_backend, detect_backend};
use super::daemon;
pub(super) fn ensure_daemon_running() -> Result<PathBuf> {
let mux = create_backend(detect_backend());
let instance_id = mux.instance_id();
let sock_path = daemon::socket_path(&instance_id);
if std::os::unix::net::UnixStream::connect(&sock_path).is_ok() {
return Ok(sock_path);
}
let _ = std::fs::remove_file(&sock_path);
spawn_daemon()?;
if !wait_for_socket(&instance_id, Duration::from_secs(2)) {
return Err(anyhow!("Sidebar daemon failed to start"));
}
Ok(sock_path)
}
fn spawn_daemon() -> Result<()> {
let exe = std::env::current_exe()?;
std::process::Command::new(exe)
.arg("_sidebar-daemon")
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()?;
Ok(())
}
fn wait_for_socket(instance_id: &str, timeout: Duration) -> bool {
let path = daemon::socket_path(instance_id);
let start = std::time::Instant::now();
while start.elapsed() < timeout {
if path.exists() {
return true;
}
std::thread::sleep(Duration::from_millis(50));
}
false
}
fn daemon_pid() -> Option<String> {
Cmd::new("tmux")
.args(&["show-option", "-gqv", "@workmux_sidebar_daemon_pid"])
.run_and_capture_stdout()
.ok()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
}
pub(super) fn kill_daemon() {
if let Some(pid) = daemon_pid() {
let _ = std::process::Command::new("kill")
.args(["-TERM", &pid])
.status();
}
let _ = Cmd::new("tmux")
.args(&["set-option", "-gu", "@workmux_sidebar_daemon_pid"])
.run();
}
pub(super) fn signal_daemon() {
if let Some(pid) = daemon_pid() {
let _ = std::process::Command::new("kill")
.args(["-USR1", &pid])
.status();
}
}