use std::process::ExitCode;
use super::pid;
pub fn dispatch() -> ExitCode {
let Some((server_pid, _port)) = pid::read_pid() else {
println!("No running dashboard found.");
return ExitCode::SUCCESS;
};
#[cfg(unix)]
{
let ret = unsafe { libc::kill(server_pid as libc::pid_t, libc::SIGTERM) };
if ret != 0 {
let err = std::io::Error::last_os_error();
eprintln!("error: could not send SIGTERM to PID {server_pid}: {err}");
return ExitCode::FAILURE;
}
}
#[cfg(windows)]
{
use std::os::windows::io::FromRawHandle;
let handle = unsafe {
windows_sys::Win32::System::Threading::OpenProcess(
windows_sys::Win32::System::Threading::PROCESS_TERMINATE,
0,
server_pid,
)
};
if handle.is_null() {
eprintln!("error: could not open process {server_pid}");
return ExitCode::FAILURE;
}
let ok = unsafe { windows_sys::Win32::System::Threading::TerminateProcess(handle, 1) };
unsafe { windows_sys::Win32::Foundation::CloseHandle(handle) };
if ok == 0 {
eprintln!("error: TerminateProcess failed for PID {server_pid}");
return ExitCode::FAILURE;
}
}
if let Err(e) = pid::remove_pid() {
eprintln!("warning: could not remove PID file: {e}");
}
println!("Dashboard stopped.");
ExitCode::SUCCESS
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dispatch_reports_success_when_no_dashboard_running() {
let _lock = crate::test_support::env_guard();
let tmp = tempfile::tempdir().unwrap();
let prev = std::env::var_os("AA_DATA_DIR");
std::env::set_var("AA_DATA_DIR", tmp.path());
let code = dispatch();
match prev {
Some(v) => std::env::set_var("AA_DATA_DIR", v),
None => std::env::remove_var("AA_DATA_DIR"),
}
assert_eq!(code, ExitCode::SUCCESS);
}
}