#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Signal {
Interrupt,
Terminate,
}
impl Signal {
pub(crate) fn exit_code(self) -> u8 {
match self {
Signal::Interrupt => 130,
Signal::Terminate => 143,
}
}
pub(crate) fn name(self) -> &'static str {
match self {
Signal::Interrupt => "SIGINT",
Signal::Terminate => "SIGTERM",
}
}
}
#[cfg(unix)]
pub(crate) async fn requested() -> std::io::Result<Signal> {
use tokio::signal::unix::{SignalKind, signal};
let mut terminate = signal(SignalKind::terminate())?;
let mut interrupt = signal(SignalKind::interrupt())?;
tokio::select! {
_ = interrupt.recv() => Ok(Signal::Interrupt),
_ = terminate.recv() => Ok(Signal::Terminate),
}
}
#[cfg(windows)]
pub(crate) async fn requested() -> std::io::Result<Signal> {
use tokio::signal::windows::{ctrl_break, ctrl_c, ctrl_close, ctrl_logoff, ctrl_shutdown};
let (mut c, mut brk, mut close) = (ctrl_c()?, ctrl_break()?, ctrl_close()?);
let (mut logoff, mut shutdown) = (ctrl_logoff()?, ctrl_shutdown()?);
tokio::select! {
_ = c.recv() => Ok(Signal::Interrupt),
_ = brk.recv() => Ok(Signal::Terminate),
_ = close.recv() => Ok(Signal::Terminate),
_ = logoff.recv() => Ok(Signal::Terminate),
_ = shutdown.recv() => Ok(Signal::Terminate),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_signal_exits_as_a_shell_says_it() {
assert_eq!((Signal::Interrupt.exit_code(), Signal::Terminate.exit_code()), (130, 143));
}
}