use std::panic;
use std::sync::{Arc, Once};
pub struct ExitHook {
cleanup_fn: Arc<dyn Fn() + Send + Sync + 'static>,
}
impl ExitHook {
pub fn new<F>(f: F) -> Self
where
F: Fn() + Send + Sync + 'static
{
ExitHook {
cleanup_fn: Arc::new(f),
}
}
pub fn register(&self) -> Result<(), Box<dyn std::error::Error>> {
static INIT: Once = Once::new();
let cleanup_fn = Arc::clone(&self.cleanup_fn);
let original_hook = panic::take_hook();
let panic_cleanup_fn = Arc::clone(&cleanup_fn);
panic::set_hook(Box::new(move |panic_info| {
panic_cleanup_fn();
original_hook(panic_info);
}));
INIT.call_once(|| {
let ctrl_c_cleanup_fn = Arc::clone(&cleanup_fn);
if let Err(e) = ctrlc::set_handler(move || {
ctrl_c_cleanup_fn();
std::process::exit(0);
}) {
eprintln!("Error setting Ctrl-C handler: {}", e);
}
});
Ok(())
}
}
impl Drop for ExitHook {
fn drop(&mut self) {
(self.cleanup_fn)();
}
}