use std::{ fs, path::{Path, PathBuf}, process::{id, Command, Stdio}, }; use super::server::ServerError; pub fn reserve_pid() -> Result<(), ServerError> { let pid_path = get_pid_path()?; is_running()?; fs::write(&pid_path, id().to_string()).map_err(|err| ServerError::Io(err))?; Command::new("chmod") .args(&["600", &pid_path.to_string_lossy()]) .output() .map_err(|err| ServerError::Io(err))?; Ok(()) } pub fn is_running() -> Result { let pid_path = get_pid_path()?; match fs::read(&pid_path) { Ok(old_pid) => { let old_pid = String::from_utf8(old_pid).map_err(|err| ServerError::from_debuggable(err))?; let old_pid = old_pid.trim(); Ok(Command::new("ps") .args(&["-p", old_pid]) .stdout(Stdio::null()) .stderr(Stdio::null()) .status() .map_err(|err| ServerError::Io(err))? .success()) } _ => Ok(false), } } pub fn run_in_background() -> Result<(), ServerError> { let this = std::env::args().next().unwrap(); Command::new(this) .stdout(Stdio::null()) .stderr(Stdio::null()) .args(&["-s"]) .spawn() .map_err(|err| ServerError::Io(err))?; Ok(()) } pub fn kill() -> Result<(), ServerError> { let pid_path = get_pid_path()?; let socket_path = get_socket_path()?; let pid = fs::read(&pid_path).map_err(|_| ServerError::NotRunning)?; let pid = String::from_utf8(pid).map_err(|err| ServerError::from_debuggable(err))?; let pid = pid.trim(); Command::new("kill") .arg(pid) .spawn() .map_err(|err| ServerError::Io(err))?; Command::new("rm") .args(&[ "-f", &pid_path.to_string_lossy(), &socket_path.to_string_lossy(), ]) .spawn() .map_err(|err| ServerError::Io(err))?; Ok(()) } pub fn get_socket_path() -> Result { Ok(get_runtime_dir()?.join("rmp.socket")) } fn get_runtime_dir() -> Result { let uid = String::from_utf8( Command::new("id") .arg("-u") .output() .map_err(|err| ServerError::Io(err))? .stdout, ) .map_err(|err| ServerError::from_debuggable(err))?; let dir = Path::new("/run/user").join(uid.trim().to_string()); Ok(dir) } fn get_pid_path() -> Result { Ok(get_runtime_dir()?.join("rmp.pid")) }