bronzeflow_time/
schedule_expr.rs

1use bronzeflow_utils::ayn_error;
2use chrono::Duration;
3use cron::Schedule;
4use std::str::FromStr;
5
6use bronzeflow_utils::prelude::{BronzeError, Result};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum FixPreset {
10    /// The task does not need to run
11    NotRun,
12    /// The task is run only once
13    Once,
14    /// The task runs every hour
15    Hourly,
16    /// The task runs every day
17    Daily,
18    /// The task runs one a week
19    Weekly,
20    /// The task runs every month
21    Monthly,
22    /// The task runs every year
23    Yearly,
24}
25
26#[derive(Debug, Clone)]
27pub enum SchedulePreset {
28    NotRun,
29    Once,
30}
31
32// TODO, support duration schedule
33#[derive(Debug, Clone)]
34pub struct ScheduleDuration(Duration);
35
36#[derive(Debug, Clone)]
37pub enum ScheduleExpr {
38    Cron(Schedule),
39    Preset(SchedulePreset),
40    // Duration(ScheduleDuration)
41}
42
43impl ScheduleExpr {
44    pub fn to_cron_schedule(&self) -> Result<Schedule> {
45        match self {
46            ScheduleExpr::Cron(s) => Ok(s.clone()),
47            _ => Err(BronzeError::msg("Can`t transform to schedule")),
48        }
49    }
50}
51
52impl<'a> TryFrom<&'a str> for ScheduleExpr {
53    type Error = BronzeError;
54
55    fn try_from(value: &'a str) -> std::result::Result<Self, Self::Error> {
56        ScheduleExpr::from_str(value)
57    }
58}
59
60impl TryFrom<FixPreset> for ScheduleExpr {
61    type Error = BronzeError;
62
63    fn try_from(value: FixPreset) -> std::result::Result<Self, Self::Error> {
64        match value {
65            FixPreset::NotRun => Ok(ScheduleExpr::Preset(SchedulePreset::NotRun)),
66            FixPreset::Once => Ok(ScheduleExpr::Preset(SchedulePreset::Once)),
67            s => {
68                let s: String = s.get_string();
69                Schedule::from_str(s.as_str())
70                    .map(ScheduleExpr::Cron)
71                    .map_err(BronzeError::msg)
72            },
73        }
74    }
75}
76
77impl FromStr for FixPreset {
78    type Err = BronzeError;
79
80    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
81        match s.trim() {
82            "@none" => Ok(FixPreset::NotRun),
83            "@once" => Ok(FixPreset::Once),
84            "@hourly" => Ok(FixPreset::Hourly),
85            "@daily" => Ok(FixPreset::Daily),
86            "@weekly" => Ok(FixPreset::Weekly),
87            "@monthly" => Ok(FixPreset::Monthly),
88            "@yearly" => Ok(FixPreset::Yearly),
89            _ => Err(ayn_error!("Error preset string: {}", s)),
90        }
91    }
92}
93
94impl FromStr for ScheduleExpr {
95    type Err = BronzeError;
96
97    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
98        let s = s.trim();
99        if let Ok(c) = Schedule::from_str(s) {
100            return Ok(ScheduleExpr::Cron(c));
101        }
102        FixPreset::from_str(s).map_or_else(Err, |r: FixPreset| r.try_into())
103    }
104}
105
106impl FixPreset {
107    fn get_string(&self) -> String {
108        match self {
109            FixPreset::NotRun => "@none".to_string(),
110            FixPreset::Once => "@once".to_string(),
111            FixPreset::Hourly => "@hourly".to_string(),
112            FixPreset::Daily => "@daily".to_string(),
113            FixPreset::Weekly => "@weekly".to_string(),
114            FixPreset::Monthly => "@monthly".to_string(),
115            FixPreset::Yearly => "@yearly".to_string(),
116        }
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use std::assert_matches::assert_matches;
124
125    #[test]
126    fn test_parse_fix_reset_from_str() {
127        assert_eq!(FixPreset::NotRun, FixPreset::from_str("@none").unwrap());
128        assert_eq!(FixPreset::Once, FixPreset::from_str("@once").unwrap());
129        assert_eq!(FixPreset::Hourly, FixPreset::from_str("@hourly").unwrap());
130        assert_eq!(FixPreset::Daily, FixPreset::from_str("@daily").unwrap());
131        assert_eq!(FixPreset::Weekly, "@weekly".parse().unwrap());
132        assert_eq!(FixPreset::Monthly, "@monthly".parse().unwrap());
133        assert_eq!(FixPreset::Yearly, "@yearly".parse().unwrap());
134    }
135
136    #[test]
137    fn test_parse_schedule_expr_from_str() {
138        let not_run = ScheduleExpr::from_str("@none").ok();
139        assert_matches!(not_run, Some(ScheduleExpr::Preset(SchedulePreset::NotRun)));
140
141        let once = ScheduleExpr::from_str("@once").ok();
142        assert_matches!(once, Some(ScheduleExpr::Preset(SchedulePreset::Once)));
143
144        assert_matches!(ScheduleExpr::from_str("error str expr").ok(), None);
145        let s1: Option<ScheduleExpr> = "0 0 0 * * 1 *".parse().ok();
146        assert_matches!(s1, Some(_));
147
148        let s2 = "1/10 * * * * * *".parse().ok();
149        assert_matches!(s2, Some(ScheduleExpr::Cron(_)));
150    }
151}