use crate::handler::BoxFuture;
use crate::state::StateMap;
use std::sync::Arc;
use tokio::sync::watch;
#[derive(Clone, Debug)]
pub struct Shutdown {
inner: watch::Receiver<bool>,
}
impl Shutdown {
pub(crate) fn new(inner: watch::Receiver<bool>) -> Self {
Self { inner }
}
pub fn is_triggered(&self) -> bool {
*self.inner.borrow()
}
pub async fn recv(&mut self) {
loop {
if *self.inner.borrow() {
return;
}
if self.inner.changed().await.is_err() {
return;
}
}
}
}
#[cfg(any(test, feature = "testing"))]
#[derive(Clone, Debug)]
pub struct ShutdownSender(watch::Sender<bool>);
#[cfg(any(test, feature = "testing"))]
#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
#[allow(dead_code)]
#[must_use]
pub fn shutdown_channel() -> (ShutdownSender, Shutdown) {
let (tx, rx) = watch::channel(false);
(ShutdownSender(tx), Shutdown::new(rx))
}
#[cfg(any(test, feature = "testing"))]
impl ShutdownSender {
pub fn send(&self, value: bool) -> bool {
self.0.send(value).is_ok()
}
}
pub trait BackgroundService: Send {
fn name(&self) -> &str;
fn run(
self: Box<Self>,
state: Arc<StateMap>,
shutdown: Shutdown,
) -> BoxFuture<()>;
}
pub(crate) type BoxedService = Box<dyn BackgroundService>;
pub async fn wait_shutdown(mut shutdown: Shutdown) {
shutdown.recv().await
}