use crate::process::SignalError;
use log::{debug, info};
use nix::sys::signal::kill;
use nix::unistd::Pid;
use tokio::signal::unix::{signal, SignalKind};
use tokio::sync::broadcast;
use tokio::sync::broadcast::{Receiver, Sender};
pub fn send_signal_by_instruction(instruction: &str, pid: i32) -> Result<(), SignalError> {
debug!("send signal by {instruction} instruction -> {pid}");
let instruction = instruction.to_lowercase();
let signal = match instruction.as_str() {
"hangup" => nix::sys::signal::Signal::SIGHUP,
"cont" => nix::sys::signal::Signal::SIGCONT,
"interrupt" => nix::sys::signal::Signal::SIGINT,
"stop" | "terminate" => nix::sys::signal::Signal::SIGTERM,
"quit" => nix::sys::signal::Signal::SIGQUIT,
"kill" => nix::sys::signal::Signal::SIGKILL,
_ => Err(SignalError::InvalidInstruction(instruction.to_string()))?,
};
kill(Pid::from_raw(pid), signal).map_err(|_| SignalError::SendSignal(signal.to_string()))
}
pub fn watch_signal() -> Receiver<nix::sys::signal::Signal> {
let (sender, receiver) = broadcast::channel(16);
tokio::spawn(async {
watch_signal_internal(sender)
.await
.expect("watch signal error");
});
receiver
}
async fn watch_signal_internal(
sender: Sender<nix::sys::signal::Signal>,
) -> Result<(), SignalError> {
debug!("watching signal...");
let mut sighup_stream = signal(SignalKind::hangup())
.map_err(|_| SignalError::RegisterSignalHandler("SIGHUP".to_string()))?;
let mut sigcont_stream = signal(SignalKind::from_raw(18))
.map_err(|_| SignalError::RegisterSignalHandler("SIGCONT".to_string()))?;
let mut sigint_stream = signal(SignalKind::interrupt())
.map_err(|_| SignalError::RegisterSignalHandler("SIGINT".to_string()))?;
let mut sigquit_stream = signal(SignalKind::quit())
.map_err(|_| SignalError::RegisterSignalHandler("SIGQUIT".to_string()))?;
let mut sigterm_stream = signal(SignalKind::terminate())
.map_err(|_| SignalError::RegisterSignalHandler("SIGTERM".to_string()))?;
loop {
tokio::select! {
_ = sighup_stream.recv() => {
let signal = nix::sys::signal::Signal::SIGHUP;
sender.send(signal).expect(format!("send signal error: {signal}").as_str());
info!("程序挂起({signal})");
}
_ = sigcont_stream.recv() => {
let signal = nix::sys::signal::Signal::SIGCONT;
sender.send(signal).expect(format!("send signal error: {signal}").as_str());
info!("程序继续运行({signal})");
}
_ = sigint_stream.recv() => {
let signal = nix::sys::signal::Signal::SIGINT;
sender.send(signal).expect(format!("send signal error: {signal}").as_str());
info!("程序中断运行({signal})");
break;
}
_ = sigquit_stream.recv() => {
let signal = nix::sys::signal::Signal::SIGQUIT;
sender.send(signal).expect(format!("send signal error: {signal}").as_str());
info!("程序退出运行({signal})");
break;
}
_ = sigterm_stream.recv() => {
let signal = nix::sys::signal::Signal::SIGTERM;
sender.send(signal).expect(format!("send signal error: {signal}").as_str());
info!("程序终止运行({signal})");
break;
}
}
}
Ok(())
}