Skip to main content

forge_runtime/cron/
registry.rs

1use std::collections::HashMap;
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::Arc;
5
6use forge_core::cron::{CronContext, CronInfo, ForgeCron};
7
8/// Type alias for boxed cron handler function.
9pub type BoxedCronHandler = Arc<
10    dyn Fn(&CronContext) -> Pin<Box<dyn Future<Output = forge_core::Result<()>> + Send + '_>>
11        + Send
12        + Sync,
13>;
14
15/// A registered cron entry.
16pub struct CronEntry {
17    /// Cron metadata.
18    pub info: CronInfo,
19    /// Execution handler.
20    pub handler: BoxedCronHandler,
21}
22
23impl CronEntry {
24    /// Create a new cron entry from a ForgeCron implementor.
25    pub fn new<C: ForgeCron>() -> Self {
26        Self {
27            info: C::info(),
28            handler: Arc::new(|ctx| C::execute(ctx)),
29        }
30    }
31}
32
33/// Registry of all cron jobs.
34#[derive(Default)]
35pub struct CronRegistry {
36    crons: HashMap<String, CronEntry>,
37}
38
39impl CronRegistry {
40    /// Create a new empty registry.
41    pub fn new() -> Self {
42        Self {
43            crons: HashMap::new(),
44        }
45    }
46
47    /// Register a cron handler.
48    pub fn register<C: ForgeCron>(&mut self) {
49        let entry = CronEntry::new::<C>();
50        self.crons.insert(entry.info.name.to_string(), entry);
51    }
52
53    /// Get a cron entry by name.
54    pub fn get(&self, name: &str) -> Option<&CronEntry> {
55        self.crons.get(name)
56    }
57
58    /// List all registered crons.
59    pub fn list(&self) -> Vec<&CronEntry> {
60        self.crons.values().collect()
61    }
62
63    /// Get the number of registered crons.
64    pub fn len(&self) -> usize {
65        self.crons.len()
66    }
67
68    /// Check if the registry is empty.
69    pub fn is_empty(&self) -> bool {
70        self.crons.is_empty()
71    }
72
73    /// Get all cron names.
74    pub fn names(&self) -> Vec<&str> {
75        self.crons.keys().map(|s| s.as_str()).collect()
76    }
77}
78
79impl Clone for CronRegistry {
80    fn clone(&self) -> Self {
81        Self {
82            crons: self
83                .crons
84                .iter()
85                .map(|(k, v)| {
86                    (
87                        k.clone(),
88                        CronEntry {
89                            info: v.info.clone(),
90                            handler: v.handler.clone(),
91                        },
92                    )
93                })
94                .collect(),
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_empty_registry() {
105        let registry = CronRegistry::new();
106        assert!(registry.is_empty());
107        assert_eq!(registry.len(), 0);
108    }
109}