1use 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 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
31pub 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#[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}