use futures::prelude::*;
use futures::stream::FuturesUnordered;
use log::info;
use std::collections::HashMap;
use tokio::signal::unix::{signal, SignalKind};
use tokio::sync::broadcast::Sender;
pub struct SignalGuard {}
impl SignalGuard {
pub async fn wait_for_stop(signal_forwarder: &Sender<i32>) -> Option<()> {
// Default behavior in UNIX is to terminate process when any of the
// following signals are received. In each of these case we initiate
// the controlled shutdown.
let mut interrupt_stream = signal(SignalKind::interrupt()).ok()?;
let mut terminate_stream = signal(SignalKind::terminate()).ok()?;
let mut alarm_stream = signal(SignalKind::alarm()).ok()?;
let mut hangup_stream = signal(SignalKind::hangup()).ok()?;
let mut quit_stream = signal(SignalKind::quit()).ok()?;
let mut user_defined1_stream = signal(SignalKind::user_defined1()).ok()?;
let mut user_defined2_stream = signal(SignalKind::user_defined2()).ok()?;
let interrupt_future = interrupt_stream.recv();
let terminate_future = terminate_stream.recv();
let alarm_future = alarm_stream.recv();
let hangup_future = hangup_stream.recv();
let quit_future = quit_stream.recv();
let user_defined1_future = user_defined1_stream.recv();
let user_defined2_future = user_defined2_stream.recv();
let all_futures = vec![
interrupt_future,
terminate_future,
alarm_future,
hangup_future,
quit_future,
user_defined1_future,
user_defined2_future,
];
let mut signal_map = HashMap::with_capacity(all_futures.len());
signal_map.insert(0, SignalKind::interrupt().as_raw_value());
signal_map.insert(1, SignalKind::terminate().as_raw_value());
signal_map.insert(2, SignalKind::alarm().as_raw_value());
signal_map.insert(3, SignalKind::hangup().as_raw_value());
signal_map.insert(4, SignalKind::quit().as_raw_value());
signal_map.insert(5, SignalKind::user_defined1().as_raw_value());
signal_map.insert(6, SignalKind::user_defined2().as_raw_value());
let all_futures = all_futures
.into_iter()
.enumerate()
.map(|(i, fut)| fut.map(move |res| (i, res)))
.collect::<FuturesUnordered<_>>();
// use collection as a stream, await only first 1 future to complete
let first_one = all_futures.take(1).collect::<Vec<_>>().await;
let signal_index = first_one[0].0;
// Currently we mask all signals to SIGTERM.
let received = signal_map[&signal_index];
info!("SIGNAL_GUARD: RECEIVED CODE {} FROM OS", received);
signal_forwarder.send(received).unwrap();
Option::Some(())
}
}