Skip to main content

platform_core/
shutdown.rs

1use std::fmt::Debug;
2use std::sync::Arc;
3use tokio::sync::watch;
4
5#[derive(Clone)]
6pub struct Shutdown {
7    sender: Arc<watch::Sender<bool>>,
8    receiver: watch::Receiver<bool>,
9}
10
11impl Debug for Shutdown {
12    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        formatter.debug_struct("Shutdown").finish_non_exhaustive()
14    }
15}
16
17impl Shutdown {
18    pub fn new() -> Self {
19        let (sender, receiver) = watch::channel(false);
20        Self {
21            sender: Arc::new(sender),
22            receiver,
23        }
24    }
25
26    pub fn signal(&self) {
27        let _ = self.sender.send(true);
28    }
29
30    pub fn subscribe(&self) -> watch::Receiver<bool> {
31        self.receiver.clone()
32    }
33
34    pub async fn wait_for_signal() {
35        let ctrl_c = async {
36            tokio::signal::ctrl_c()
37                .await
38                .expect("failed to install Ctrl+C handler");
39        };
40
41        #[cfg(unix)]
42        let terminate = async {
43            tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
44                .expect("failed to install signal handler")
45                .recv()
46                .await;
47        };
48
49        #[cfg(not(unix))]
50        let terminate = std::future::pending::<()>();
51
52        tokio::select! {
53            () = ctrl_c => {},
54            () = terminate => {},
55        }
56    }
57}
58
59impl Default for Shutdown {
60    fn default() -> Self {
61        Self::new()
62    }
63}