use std::sync::Arc; use tokio::io; use tokio::sync::mpsc; use tokio::{ select, signal::unix::{signal, Signal, SignalKind}, }; type SendersVec = Arc>>>; /// # Fn set_valid_destructor /// ## for initializing process of unstoppable grubbing metrics. /// /// *input* : `Result<()>` /// /// *output* : `Err` if it cant create signals listeners | `Ok` on returning Monitor /// /// *initiator* : main thread /// /// *managing* : `Arc>>>` /// /// *depends on* : Sig, Signals /// pub async fn set_valid_destructor(senders: SendersVec) -> anyhow::Result<()> { let (mut int, mut term, mut stop) = ( Sig::new(Signals::Sigint, senders.clone()), Sig::new(Signals::Sigterm, senders.clone()), Sig::new(Signals::Sigstop, senders.clone()), ); select! { _ = int.post_processing() => {log::info!("Initializing interruption...")}, _ = term.post_processing() => {log::info!("Initializing termination...")}, _ = stop.post_processing() => {log::info!("Initializing freezing...")}, } Ok(()) } /// # Enum Signals /// ## for instancing each managed system signals (such as SIGINT) /// /// > (element needed in Sig constructor's signature) /// /// *depends on* : - enum Signals { Sigint, Sigterm, Sigstop, } /// # Struct Signals /// ## for instancing each managed system signals (such as SIGINT) /// /// > (needed to construct system signals listener) /// /// *depends on* : Signals struct Sig { signal: Signal, sig_type: Signals, senders: SendersVec, } /// ## default Sig's constructor impl Sig { fn new(signal_type: Signals, sends: SendersVec) -> Self { Sig { signal: signal_type.get_signal().unwrap(), sig_type: signal_type, senders: sends, } } } /// ## trait Display realization for returning String-name of signal /// /// > (needed in logs) impl std::fmt::Display for Signals { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Signals::Sigint => write!(f, "SIGINT"), Signals::Sigterm => write!(f, "SIGTERM"), Signals::Sigstop => write!(f, "SIGSTOP"), } } } /// ## associated func to init signals listener impl Signals { fn get_signal(&self) -> io::Result { match self { Signals::Sigint => signal(SignalKind::interrupt()), Signals::Sigterm => signal(SignalKind::terminate()), Signals::Sigstop => signal(SignalKind::quit()), } } } /// # Trait SigPostProcessing /// ## to handle post-processing jobs after getting system signal /// /// ## > (needed in signals post-processing) /// trait SigPostProcessing { async fn post_processing(&mut self) -> io::Result<()>; } /// # Trait SigPostProcessing realization for Sig struct /// ## to deinitialize Monitor correctly after getting signal /// /// ## > (needed in signals post-processing) /// impl SigPostProcessing for Sig { async fn post_processing(&mut self) -> io::Result<()> { // manipulations ... if self.signal.recv().await.is_some() { log::info!("Got {} signal", self.sig_type); for prc in self.senders.clone().iter() { let _ = prc.send(111).await; } } Ok(()) } } #[cfg(test)] mod signals_unittest { use super::*; #[tokio::test] async fn get_signal_check() { assert!(Signals::Sigint.get_signal().is_ok()) } }