use crate::env::{AppEnv, EnvError, APP_ENV};
use crate::signal::signal_manager_error::SignalManagerError;
use log::error;
use robotech_macros::log_call;
use std::path::PathBuf;
use std::process;
use tokio::sync::broadcast;
use wheel_rs::process::{
check_process, delete_pid_file, get_pid_file_path, read_pid, send_signal_by_instruction,
watch_signal, PidFileGuard,
};
#[derive(Debug)]
pub struct SignalManager {
pid_file_path: PathBuf,
pid_file_guard: Option<PidFileGuard>,
}
impl SignalManager {
#[log_call]
pub fn new(signal_instruction: String) -> Result<(Self, Option<i32>), SignalManagerError> {
let AppEnv { app_file_path, .. } = APP_ENV.get().ok_or(EnvError::GetAppEnv())?;
let pid_file_path = get_pid_file_path(app_file_path);
let old_pid = Self::parse_and_handle_signal_args(signal_instruction, &pid_file_path)?;
Ok((
Self {
pid_file_path,
pid_file_guard: None,
},
old_pid,
))
}
pub fn watch_signal(
&mut self,
) -> Result<broadcast::Receiver<nix::sys::signal::Signal>, SignalManagerError> {
self.pid_file_guard = Some(PidFileGuard::new(self.pid_file_path.clone())?);
Ok(watch_signal())
}
#[log_call]
fn parse_and_handle_signal_args(
signal_instruction: String,
pid_file_path: &PathBuf,
) -> Result<Option<i32>, SignalManagerError> {
let old_pid = read_pid(pid_file_path)?;
if signal_instruction == "restart" {
if let Some(old_pid) = old_pid
&& check_process(old_pid)?
{
return Ok(Some(old_pid));
}
Ok(None)
} else if signal_instruction == "start" {
if let Some(old_pid) = old_pid
&& check_process(old_pid)?
{
Err(SignalManagerError::ProgramIsRunning(old_pid))?
}
Ok(None)
} else {
let old_pid =
old_pid.ok_or(SignalManagerError::NotFoundPidFile(pid_file_path.clone()))?;
if let Err(e) = send_signal_by_instruction(&signal_instruction, old_pid) {
error!("Failed to send signal: {e}");
process::exit(1);
} else {
if signal_instruction == "kill" {
if let Err(e) = delete_pid_file(&pid_file_path) {
error!("Failed to delete pid file: {e}");
process::exit(1);
}
}
process::exit(0);
};
}
}
}