use futures::{
future::{self, BoxFuture, FutureExt},
pin_mut, select, Future,
};
use pezsc_service::Error as ServiceError;
pub struct Signals(BoxFuture<'static, ()>);
impl Signals {
pub fn future(self) -> BoxFuture<'static, ()> {
self.0
}
#[cfg(target_family = "unix")]
pub fn capture() -> std::result::Result<Self, ServiceError> {
use tokio::signal::unix::{signal, SignalKind};
let mut stream_int = signal(SignalKind::interrupt()).map_err(ServiceError::Io)?;
let mut stream_term = signal(SignalKind::terminate()).map_err(ServiceError::Io)?;
Ok(Signals(
async move {
future::select(stream_int.recv().boxed(), stream_term.recv().boxed()).await;
}
.boxed(),
))
}
#[cfg(not(unix))]
pub fn capture() -> Result<Self, ServiceError> {
use tokio::signal::ctrl_c;
Ok(Signals(
async move {
let _ = ctrl_c().await;
}
.boxed(),
))
}
pub fn dummy() -> Self {
Self(future::pending().boxed())
}
pub async fn run_until_signal<F, E>(self, func: F) -> Result<(), E>
where
F: Future<Output = Result<(), E>> + future::FusedFuture,
E: std::error::Error + Send + Sync + 'static,
{
let signals = self.future().fuse();
pin_mut!(func, signals);
select! {
_ = signals => {},
res = func => res?,
}
Ok(())
}
pub async fn try_until_signal<F, T>(self, func: F) -> Result<T, ()>
where
F: Future<Output = T> + future::FusedFuture,
{
let signals = self.future().fuse();
pin_mut!(func, signals);
select! {
s = signals => Err(s),
res = func => Ok(res),
}
}
}