1use chrono::{FixedOffset, Local};
2use cron::Schedule;
3
4use std::str::FromStr;
5use std::thread;
6use std::time::Duration;
7
8use command::Command;
9
10pub struct CronJob {
12 name: String,
13 command: Box<dyn Command>,
14 seconds: Option<String>,
15 minutes: Option<String>,
16 hours: Option<String>,
17 day_of_month: Option<String>,
18 month: Option<String>,
19 day_of_week: Option<String>,
20 year: Option<String>,
21 offset: Option<FixedOffset>,
22 interval: u64,
23}
24
25impl CronJob {
26 pub fn new<C: Command>(name: &str, command: C) -> Self {
28 CronJob {
29 name: name.to_string(),
30 command: Box::new(command),
31 seconds: None,
32 minutes: None,
33 hours: None,
34 day_of_month: None,
35 month: None,
36 day_of_week: None,
37 year: None,
38 offset: None,
39 interval: 500,
40 }
41 }
42
43 pub fn seconds(&mut self, seconds: &str) -> &mut Self {
44 self.seconds = Some(seconds.to_string());
45 self
46 }
47
48 pub fn minutes(&mut self, minutes: &str) -> &mut Self {
49 self.minutes = Some(minutes.to_string());
50 self
51 }
52
53 pub fn hours(&mut self, hours: &str) -> &mut Self {
54 self.hours = Some(hours.to_string());
55 self
56 }
57
58 pub fn day_of_month(&mut self, day_of_month: &str) -> &mut Self {
59 self.day_of_month = Some(day_of_month.to_string());
60 self
61 }
62
63 pub fn month(&mut self, month: &str) -> &mut Self {
64 self.month = Some(month.to_string());
65 self
66 }
67
68 pub fn day_of_week(&mut self, day_of_week: &str) -> &mut Self {
69 self.day_of_week = Some(day_of_week.to_string());
70 self
71 }
72
73 pub fn year(&mut self, year: &str) -> &mut Self {
74 self.year = Some(year.to_string());
75 self
76 }
77
78 pub fn offset(&mut self, timezone_offset: i32) -> &mut Self {
79 self.offset = Some(FixedOffset::east(timezone_offset));
80 self
81 }
82
83 pub fn set_checking_interval(&mut self, interval: u64) -> &mut Self {
85 self.interval = interval;
86 self
87 }
88
89 pub fn get_schedule(&mut self) -> Schedule {
91 let asterix = String::from("*");
92 let cron = format!(
93 "{} {} {} {} {} {} {}",
94 self.seconds.as_ref().unwrap_or(&asterix),
95 self.minutes.as_ref().unwrap_or(&asterix),
96 self.hours.as_ref().unwrap_or(&asterix),
97 self.day_of_month.as_ref().unwrap_or(&asterix),
98 self.month.as_ref().unwrap_or(&asterix),
99 self.day_of_week.as_ref().unwrap_or(&asterix),
100 self.year.as_ref().unwrap_or(&asterix)
101 );
102 Schedule::from_str(&cron).unwrap()
103 }
104
105 pub fn start_job(&mut self) {
107 let schedule = self.get_schedule();
108 let offset = self.offset.unwrap_or_else(|| FixedOffset::east(0));
109
110 loop {
111 let mut upcoming = schedule.upcoming(offset).take(1);
112 thread::sleep(Duration::from_millis(self.interval));
113 let local = &Local::now();
114
115 if let Some(datetime) = upcoming.next() {
116 if datetime.timestamp() <= local.timestamp() {
117 self.command.execute(&self.name);
118 }
119 }
120 }
121 }
122
123 pub fn start_job_threaded(mut cronjob: CronJob) {
125 thread::Builder::new()
126 .name(cronjob.name.clone())
127 .spawn(move || cronjob.start_job())
128 .expect("There was an error in an cronjob");
129 }
130}