utils_box/
threads.rs

1//! # Linux OS utilities
2//! A toolbox of small utilities for Linux environments.
3//! Useful for fast binary development via the provided signal handling and panic hooks.
4
5use futures::stream::StreamExt;
6use log::{error, info};
7use signal_hook::consts::signal::*;
8use signal_hook_tokio::Signals;
9use std::panic;
10use tokio::task::JoinHandle;
11
12pub fn signal_init() -> (signal_hook::iterator::Handle, JoinHandle<()>) {
13    // Termination Signals Initilization
14    let signals = Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT]).unwrap();
15    let signals_handle = signals.handle();
16
17    let signals_task = tokio::spawn(handle_signals(signals));
18
19    (signals_handle, signals_task)
20}
21
22#[cfg(target_family = "unix")]
23pub async fn signal_wait(
24    signals_handle: signal_hook::iterator::Handle,
25    signals_task: JoinHandle<()>,
26) {
27    signals_handle.close();
28    signals_task.await.unwrap();
29}
30
31/// Helper Function: Panic Handler
32pub fn panic_handler_init() {
33    panic::set_hook(Box::new(|panic_info| {
34        match panic_info.payload().downcast_ref::<String>() {
35            Some(as_string) => {
36                error!("PANIC occurred: {as_string}");
37            }
38            None => {
39                error!("PANIC occurred: {panic_info:?}");
40            }
41        }
42        if let Some(location) = panic_info.location() {
43            error!(
44                "PANIC occurred in file '{}' at line {}",
45                location.file(),
46                location.line()
47            );
48        } else {
49            error!("PANIC occurred but can't get location information...");
50        }
51
52        std::process::abort();
53    }));
54
55    info!("SP Scanner [Panic Handler] REGISTERED!");
56}
57
58/// Helper Function: Handle of System Termination Signals
59#[cfg(target_family = "unix")]
60#[allow(clippy::never_loop)]
61async fn handle_signals(signals: Signals) {
62    use log::warn;
63
64    let mut signals = signals.fuse();
65
66    while let Some(signal) = signals.next().await {
67        match signal {
68            SIGHUP | SIGTERM | SIGINT | SIGQUIT => {
69                warn!(
70                    "SP Scanner [Termination signals] [{signal:?}] RECEIVED! Terminating Tasks & Exiting..."
71                );
72                signal_hook::low_level::exit(1);
73            }
74            _ => unreachable!(),
75        }
76    }
77}