Skip to main content

pharos_server/
lifecycle.rs

1use std::{future::Future, io, pin::Pin, sync::Arc};
2
3type Hook = Arc<dyn Fn() -> Pin<Box<dyn Future<Output = io::Result<()>> + Send>> + Send + Sync>;
4
5/// Hook phases in the configuration lifecycle.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub enum Phase {
8    Startup,
9    /// Listeners have been installed after Startup, including on Reload.
10    Started,
11    Shutdown,
12    Restart,
13    RestartFailed,
14}
15
16/// Setup-time registration of ordered synchronous or asynchronous hooks.
17#[derive(Clone, Default)]
18pub struct Lifecycle {
19    hooks: Vec<(Phase, Hook)>,
20}
21
22impl Lifecycle {
23    pub fn register<F, Fut>(&mut self, phase: Phase, hook: F)
24    where
25        F: Fn() -> Fut + Send + Sync + 'static,
26        Fut: Future<Output = io::Result<()>> + Send + 'static,
27    {
28        self.hooks.push((phase, Arc::new(move || Box::pin(hook()))));
29    }
30
31    pub fn register_sync<F>(&mut self, phase: Phase, hook: F)
32    where
33        F: Fn() -> io::Result<()> + Send + Sync + 'static,
34    {
35        self.register(phase, move || std::future::ready(hook()));
36    }
37
38    pub async fn run(&self, phase: Phase) -> io::Result<()> {
39        for (_, hook) in self
40            .hooks
41            .iter()
42            .filter(|(registered, _)| *registered == phase)
43        {
44            hook().await?;
45        }
46        Ok(())
47    }
48
49    pub fn extend(&mut self, other: &Self) {
50        self.hooks.extend(other.hooks.iter().cloned());
51    }
52}
53
54impl std::fmt::Debug for Lifecycle {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        f.debug_struct("Lifecycle")
57            .field("hooks", &self.hooks.len())
58            .finish()
59    }
60}