use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Instant;
use tokio_util::sync::CancellationToken;
static LAST_CTRLC: parking_lot::Mutex<Option<Instant>> = parking_lot::Mutex::new(None);
pub fn install(cancel_token: CancellationToken, running: Arc<AtomicBool>) -> anyhow::Result<()> {
let ct = cancel_token.clone();
let r = running.clone();
ctrlc_handler(move || {
let mut last = LAST_CTRLC.lock();
let now = Instant::now();
if let Some(prev) = *last {
if now.duration_since(prev).as_millis() < 500 {
eprintln!("\nForce exit.");
std::process::exit(130);
}
}
*last = Some(now);
if r.load(Ordering::Relaxed) {
ct.cancel();
eprintln!("\n Cancelling... (press Ctrl+C again to force exit)");
} else {
eprintln!("\nGoodbye.");
std::process::exit(0);
}
});
Ok(())
}
fn ctrlc_handler(f: impl Fn() + Send + 'static) {
let _ = ctrlc::set_handler(f);
}
#[allow(dead_code)]
pub fn fresh_cancel_token() -> CancellationToken {
CancellationToken::new()
}