actr-cli 0.2.1

Command line tool for Actor-RTC framework projects
Documentation
use crate::error::{ActrCliError, Result};
use std::time::{Duration, Instant};

#[cfg(unix)]
pub(crate) fn terminate_process(pid: u32) -> Result<bool> {
    use nix::errno::Errno;
    use nix::sys::signal::{Signal, kill};
    use nix::unistd::Pid;

    let pid = i32::try_from(pid)
        .map_err(|_| ActrCliError::command_error(format!("Invalid PID {}", pid)))?;
    match kill(Pid::from_raw(pid), Signal::SIGTERM) {
        Ok(()) => Ok(true),
        Err(Errno::ESRCH) => Ok(false),
        Err(error) => Err(ActrCliError::command_error(format!(
            "Failed to send SIGTERM to {}: {}",
            pid, error
        ))),
    }
}

#[cfg(unix)]
pub(crate) fn kill_process(pid: u32) -> Result<bool> {
    use nix::errno::Errno;
    use nix::sys::signal::{Signal, kill};
    use nix::unistd::Pid;

    let pid = i32::try_from(pid)
        .map_err(|_| ActrCliError::command_error(format!("Invalid PID {}", pid)))?;
    match kill(Pid::from_raw(pid), Signal::SIGKILL) {
        Ok(()) => Ok(true),
        Err(Errno::ESRCH) => Ok(false),
        Err(error) => Err(ActrCliError::command_error(format!(
            "Failed to send SIGKILL to {}: {}",
            pid, error
        ))),
    }
}

#[cfg(not(unix))]
pub(crate) fn terminate_process(_pid: u32) -> Result<bool> {
    Err(ActrCliError::command_error(
        "stop is only supported on Unix systems".to_string(),
    ))
}

#[cfg(not(unix))]
pub(crate) fn kill_process(_pid: u32) -> Result<bool> {
    Err(ActrCliError::command_error(
        "process control is only supported on Unix systems".to_string(),
    ))
}

pub(crate) async fn wait_for_exit(pid: u32, timeout: Duration) -> bool {
    let deadline = Instant::now() + timeout;
    while Instant::now() < deadline {
        if !is_process_alive(pid) {
            return true;
        }
        tokio::time::sleep(Duration::from_millis(100)).await;
    }

    !is_process_alive(pid)
}

#[cfg(unix)]
pub(crate) fn is_process_alive(pid: u32) -> bool {
    use nix::errno::Errno;
    use nix::sys::signal::kill;
    use nix::unistd::Pid;

    let Ok(pid) = i32::try_from(pid) else {
        return false;
    };

    match kill(Pid::from_raw(pid), None) {
        Ok(()) => true,
        Err(Errno::EPERM) => true,
        Err(Errno::ESRCH) => false,
        Err(_) => false,
    }
}

#[cfg(not(unix))]
pub(crate) fn is_process_alive(_pid: u32) -> bool {
    false
}