1#![forbid(unsafe_code)]
28#![warn(missing_debug_implementations)]
29#![warn(missing_docs)]
30
31use chrono::prelude::*;
32use chrono::Duration;
33use std::thread;
34
35pub mod prelude {
37 pub use crate::Schedule;
38 pub use crate::TaskRunner;
39}
40
41#[derive(Debug, Copy, Clone)]
43pub struct Schedule;
44
45impl Schedule {
46 pub fn every() -> ScheduleBuilderOne {
48 ScheduleBuilderOne
49 }
50
51 pub fn every_num(amount: u32) -> ScheduleBuilderOnes {
53 ScheduleBuilderOnes { amount }
54 }
55}
56
57#[derive(Debug)]
59pub struct ScheduleBuilderOne;
60
61impl ScheduleBuilderOne {
62 pub fn minute(self) -> ScheduleBuilderTwo {
64 ScheduleBuilderTwo {
65 interval: Interval::Minute(1),
66 limit: None,
67 }
68 }
69
70 pub fn hour(self) -> ScheduleBuilderTwo {
72 ScheduleBuilderTwo {
73 interval: Interval::Hour(1),
74 limit: None,
75 }
76 }
77
78 pub fn day(self) -> ScheduleBuilderTwo {
80 ScheduleBuilderTwo {
81 interval: Interval::Day(1),
82 limit: None,
83 }
84 }
85
86 pub fn week(self) -> ScheduleBuilderTwo {
88 ScheduleBuilderTwo {
89 interval: Interval::Week(1),
90 limit: None,
91 }
92 }
93
94 pub fn month(self) -> ScheduleBuilderTwo {
96 ScheduleBuilderTwo {
97 interval: Interval::Month(1),
98 limit: None,
99 }
100 }
101
102 pub fn year(self) -> ScheduleBuilderTwo {
104 ScheduleBuilderTwo {
105 interval: Interval::Year(1),
106 limit: None,
107 }
108 }
109
110 pub fn monday(self) -> ScheduleBuilderTwoDates {
112 ScheduleBuilderTwoDates {
113 interval: Interval::Week(1),
114 limit: None,
115 day: Weekday::Mon,
116 time: None,
117 }
118 }
119
120 pub fn tuesday(self) -> ScheduleBuilderTwoDates {
122 ScheduleBuilderTwoDates {
123 interval: Interval::Week(1),
124 limit: None,
125 day: Weekday::Tue,
126 time: None,
127 }
128 }
129
130 pub fn wednesday(self) -> ScheduleBuilderTwoDates {
132 ScheduleBuilderTwoDates {
133 interval: Interval::Week(1),
134 limit: None,
135 day: Weekday::Wed,
136 time: None,
137 }
138 }
139
140 pub fn thursday(self) -> ScheduleBuilderTwoDates {
142 ScheduleBuilderTwoDates {
143 interval: Interval::Week(1),
144 limit: None,
145 day: Weekday::Thu,
146 time: None,
147 }
148 }
149
150 pub fn friday(self) -> ScheduleBuilderTwoDates {
152 ScheduleBuilderTwoDates {
153 interval: Interval::Week(1),
154 limit: None,
155 day: Weekday::Fri,
156 time: None,
157 }
158 }
159
160 pub fn saturday(self) -> ScheduleBuilderTwoDates {
162 ScheduleBuilderTwoDates {
163 interval: Interval::Week(1),
164 limit: None,
165 day: Weekday::Sat,
166 time: None,
167 }
168 }
169
170 pub fn sunday(self) -> ScheduleBuilderTwoDates {
172 ScheduleBuilderTwoDates {
173 interval: Interval::Week(1),
174 limit: None,
175 day: Weekday::Sun,
176 time: None,
177 }
178 }
179}
180
181#[derive(Debug, Copy, Clone)]
183pub struct ScheduleBuilderOnes {
184 amount: u32,
185}
186
187impl ScheduleBuilderOnes {
188 pub fn minutes(self) -> ScheduleBuilderTwo {
190 ScheduleBuilderTwo {
191 interval: Interval::Minute(self.amount),
192 limit: None,
193 }
194 }
195
196 pub fn hours(self) -> ScheduleBuilderTwo {
198 ScheduleBuilderTwo {
199 interval: Interval::Hour(self.amount),
200 limit: None,
201 }
202 }
203
204 pub fn days(self) -> ScheduleBuilderTwo {
206 ScheduleBuilderTwo {
207 interval: Interval::Day(self.amount),
208 limit: None,
209 }
210 }
211
212 pub fn weeks(self) -> ScheduleBuilderTwo {
214 ScheduleBuilderTwo {
215 interval: Interval::Week(self.amount),
216 limit: None,
217 }
218 }
219
220 pub fn months(self) -> ScheduleBuilderTwo {
222 ScheduleBuilderTwo {
223 interval: Interval::Month(self.amount),
224 limit: None,
225 }
226 }
227
228 pub fn years(self) -> ScheduleBuilderTwo {
230 ScheduleBuilderTwo {
231 interval: Interval::Year(self.amount),
232 limit: None,
233 }
234 }
235
236 pub fn monday(self) -> ScheduleBuilderTwoDates {
238 ScheduleBuilderTwoDates {
239 interval: Interval::Week(self.amount),
240 limit: None,
241 day: Weekday::Mon,
242 time: None,
243 }
244 }
245
246 pub fn tuesday(self) -> ScheduleBuilderTwoDates {
248 ScheduleBuilderTwoDates {
249 interval: Interval::Week(self.amount),
250 limit: None,
251 day: Weekday::Tue,
252 time: None,
253 }
254 }
255
256 pub fn wednesday(self) -> ScheduleBuilderTwoDates {
258 ScheduleBuilderTwoDates {
259 interval: Interval::Week(self.amount),
260 limit: None,
261 day: Weekday::Wed,
262 time: None,
263 }
264 }
265
266 pub fn thursday(self) -> ScheduleBuilderTwoDates {
268 ScheduleBuilderTwoDates {
269 interval: Interval::Week(1),
270 limit: None,
271 day: Weekday::Thu,
272 time: None,
273 }
274 }
275
276 pub fn friday(self) -> ScheduleBuilderTwoDates {
278 ScheduleBuilderTwoDates {
279 interval: Interval::Week(1),
280 limit: None,
281 day: Weekday::Fri,
282 time: None,
283 }
284 }
285
286 pub fn saturday(self) -> ScheduleBuilderTwoDates {
288 ScheduleBuilderTwoDates {
289 interval: Interval::Week(1),
290 limit: None,
291 day: Weekday::Sat,
292 time: None,
293 }
294 }
295
296 pub fn sunday(self) -> ScheduleBuilderTwoDates {
298 ScheduleBuilderTwoDates {
299 interval: Interval::Week(1),
300 limit: None,
301 day: Weekday::Sun,
302 time: None,
303 }
304 }
305}
306
307#[derive(Debug, Copy, Clone)]
308enum Interval {
309 Minute(u32),
310 Hour(u32),
311 Day(u32),
312 Week(u32),
313 Month(u32),
314 Year(u32),
315}
316
317#[derive(Debug)]
319pub struct ScheduleBuilderTwo {
320 interval: Interval,
321 limit: Option<u64>,
322}
323
324impl ScheduleBuilderTwo {
325 pub fn limit(mut self, amount: u64) {
327 self.limit = Some(amount)
328 }
329
330 pub fn run<F: Fn() + Send + 'static>(self, fun: F) -> Scheduled<F> {
332 Scheduled {
333 execution_time: next_interval(self.interval),
334 execution_interval: self.interval,
335 execution_limit: self.limit,
336 function: fun,
337 }
338 }
339}
340
341#[derive(Debug)]
344pub struct ScheduleBuilderTwoDates {
345 interval: Interval,
346 limit: Option<u64>,
347 day: Weekday,
348 time: Option<NaiveTime>,
349}
350
351impl ScheduleBuilderTwoDates {
352 pub fn limit(mut self, amount: u64) {
354 self.limit = Some(amount)
355 }
356
357 pub fn at(mut self, time: &str) {
359 let naive_time = NaiveTime::parse_from_str(time, "%H:%M").unwrap();
360 self.time = Some(naive_time)
361 }
362
363 pub fn run<F: Fn() + Send + 'static>(self, fun: F) -> Scheduled<F> {
365 Scheduled {
366 execution_time: first_day_exec(self.day, self.time),
367 execution_interval: self.interval,
368 execution_limit: self.limit,
369 function: fun,
370 }
371 }
372}
373
374fn first_day_exec(day: Weekday, time: Option<NaiveTime>) -> DateTime<Utc> {
375 let now = Utc::now();
376 let current_day = now.day();
377 let current_weekday = now.weekday().number_from_monday();
378 let to_add = (current_weekday + day.number_from_monday()) % 7;
379 let with_day = Utc::now().with_day(current_day + to_add).unwrap();
380 match time {
381 Some(t) => with_day
382 .with_hour(t.hour())
383 .unwrap()
384 .with_minute(t.minute())
385 .unwrap()
386 .with_second(t.second())
387 .unwrap(),
388 None => with_day,
389 }
390}
391
392fn next_interval(i: Interval) -> DateTime<Utc> {
393 match i {
394 Interval::Minute(a) => Utc::now() + Duration::minutes(a as i64),
395 Interval::Hour(a) => Utc::now() + Duration::hours(a as i64),
396 Interval::Day(a) => Utc::now() + Duration::days(a as i64),
397 Interval::Week(a) => Utc::now() + Duration::weeks(a as i64),
398 Interval::Month(a) => {
399 let time = Utc::now();
400 let month = time.month();
401 time.with_month(month + a).unwrap()
402 }
403 Interval::Year(a) => {
404 let time = Utc::now();
405 let year = time.year();
406 time.with_year(year + a as i32).unwrap()
407 }
408 }
409}
410
411#[derive(Debug)]
413pub struct Scheduled<F: Fn() + Send + 'static> {
414 execution_time: DateTime<Utc>,
415 execution_interval: Interval,
416 execution_limit: Option<u64>,
417 function: F,
418}
419
420#[derive(Debug)]
422pub struct TaskRunner<F: Fn() + Send + 'static> {
423 tasks: Vec<Scheduled<F>>,
424}
425
426impl<F: Fn() + Send + 'static> TaskRunner<F> {
427 pub fn new(tasks: Vec<Scheduled<F>>) -> TaskRunner<F> {
429 TaskRunner { tasks }
430 }
431
432 pub fn one(task: Scheduled<F>) -> TaskRunner<F> {
434 TaskRunner { tasks: vec![task] }
435 }
436
437 pub fn run(mut self) {
439 thread::spawn(move || loop {
440 let current_time = Utc::now();
441 for task in self.tasks.iter_mut() {
442 if current_time < task.execution_time {
443 continue;
444 };
445 (task.function)();
446 if let Some(x) = task.execution_limit {
447 task.execution_limit = Some(x - 1);
448 };
449 task.execution_time = next_interval(task.execution_interval);
450 }
451 self.tasks = self
452 .tasks
453 .into_iter()
454 .filter(|x| match x.execution_limit {
455 Some(x) => x < 1,
456 None => false,
457 })
458 .collect();
459 thread::sleep(Duration::seconds(5).to_std().unwrap())
460 });
461 }
462}