iceyee_timer/
lib.rs

1// **************************************************
2// *  Author: Iceyee                                *
3// *  Mail: iceyee.studio@qq.com                    *
4// *  Git: https://github.com/iceyee                *
5// **************************************************
6//
7
8//! 时钟.
9
10// Use.
11
12use std::future::Future;
13use std::sync::atomic::AtomicBool;
14use std::sync::atomic::Ordering;
15use std::sync::Arc;
16use tokio::sync::Mutex as TokioMutex;
17use tokio::task::JoinHandle;
18use tokio::time::Sleep;
19
20// Enum.
21
22/// Error.
23///
24/// - @see [Timer]
25#[derive(Debug, Clone)]
26pub enum TimerError {
27    InvalidFormat,
28}
29
30impl std::fmt::Display for TimerError {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
32        match self {
33            Self::InvalidFormat => {
34                f.write_str("错误的格式.")?;
35            }
36        }
37        return Ok(());
38    }
39}
40
41impl std::error::Error for TimerError {}
42
43// Trait.
44
45// Struct.
46
47/// 时钟, 精度200ms ~ 400ms.
48
49#[derive(Clone, Debug)]
50pub struct Timer {
51    thread_handles: Arc<TokioMutex<Vec<JoinHandle<()>>>>,
52    is_stop: Arc<AtomicBool>,
53}
54
55impl Timer {
56    pub fn new() -> Self {
57        return Self {
58            thread_handles: Arc::new(TokioMutex::new(Vec::new())),
59            is_stop: Arc::new(AtomicBool::new(false)),
60        };
61    }
62
63    /// 延时, 单位:毫秒.
64    pub fn sleep(t: u64) -> Sleep {
65        use std::time::Duration;
66
67        return tokio::time::sleep(Duration::from_millis(t));
68    }
69
70    #[deprecated(
71        since = "2.0.0",
72        note = "停止时钟放到了Drop中, 只需要在主程序等待一段时间, 即可正确地释放资源."
73    )]
74    /// 停止时钟并结束所有与其绑定的定时任务.
75    pub async fn stop(&mut self) {
76        self.is_stop.store(true, Ordering::SeqCst);
77        loop {
78            match {
79                let handle = self.thread_handles.lock().await.pop();
80                handle
81            } {
82                Some(handle) => handle.await.unwrap(),
83                None => break,
84            }
85        }
86        return;
87    }
88
89    /// 定时任务, 模式匹配.
90    ///
91    /// - @param pattern "秒 分 时 日 月 周几", "second minute hour day month weekday", 可以参考linux的crontab.
92    /// - @param f
93    /// - @exception [TimerError::InvalidFormat] pattern参数, 格式错误.
94    pub fn schedule_pattern<F1, F2>(&mut self, pattern: &str, mut f: F1) -> Result<(), TimerError>
95    where
96        F1: FnMut() -> F2 + Send + 'static,
97        F2: Future<Output = ()> + Send + 'static,
98    {
99        // 在'*'可能有'/', 即SLASH.
100        enum Status {
101            MIN,
102            MAX,
103            SEPARATION,
104            SLASH,
105        }
106        let expand = |mut min: usize, max: usize, separation: usize| {
107            let mut result: Vec<usize> = Vec::new();
108            while min <= max {
109                result.push(min);
110                min += separation;
111            }
112            return result;
113        };
114        let mut table: [([bool; 60], usize, usize); 6] = [
115            ([false; 60], 0, 59),
116            ([false; 60], 0, 59),
117            ([false; 60], 0, 59),
118            ([false; 60], 1, 31),
119            ([false; 60], 1, 12),
120            ([false; 60], 1, 7),
121        ];
122        let mut pattern: String = pattern.to_string();
123        while pattern.contains("  ") {
124            pattern = pattern.replace("  ", " ");
125        }
126        if pattern.split(' ').count() != table.len() {
127            return Err(TimerError::InvalidFormat);
128        }
129        let mut index: usize = 0;
130        for x in pattern.split(' ') {
131            if x.len() == 0 {
132                return Err(TimerError::InvalidFormat);
133            }
134            for y in x.split([',', ',']) {
135                if y.len() == 0 {
136                    return Err(TimerError::InvalidFormat);
137                }
138                let mut status: Status = Status::MIN;
139                let mut min: Vec<u8> = Vec::new();
140                let mut max: Vec<u8> = Vec::new();
141                let mut separation: Vec<u8> = Vec::new();
142                for z in y.as_bytes() {
143                    match status {
144                        Status::MIN => {
145                            if (*z as char).is_ascii_digit() {
146                                min.push(*z);
147                            } else if *z == b'-' {
148                                status = Status::MAX;
149                            } else if *z == b'*' {
150                                if 0 < min.len() {
151                                    return Err(TimerError::InvalidFormat);
152                                }
153                                min.extend_from_slice(table[index].1.to_string().as_bytes());
154                                max.extend_from_slice(table[index].2.to_string().as_bytes());
155                                status = Status::SLASH;
156                            } else {
157                                return Err(TimerError::InvalidFormat);
158                            }
159                        }
160                        Status::MAX => {
161                            if (*z as char).is_ascii_digit() {
162                                max.push(*z);
163                            } else if *z == b'/' {
164                                status = Status::SEPARATION;
165                            } else {
166                                return Err(TimerError::InvalidFormat);
167                            }
168                        }
169                        Status::SEPARATION => {
170                            if (*z as char).is_ascii_digit() {
171                                separation.push(*z);
172                            } else {
173                                return Err(TimerError::InvalidFormat);
174                            }
175                        }
176                        Status::SLASH => {
177                            if *z == b'/' {
178                                status = Status::SEPARATION;
179                            }
180                        }
181                    }
182                }
183                match status {
184                    Status::MIN => {
185                        if min.len() == 0 {
186                            return Err(TimerError::InvalidFormat);
187                        } else {
188                            max = min.clone();
189                        }
190                    }
191                    Status::MAX => {
192                        if max.len() == 0 {
193                            return Err(TimerError::InvalidFormat);
194                        }
195                    }
196                    Status::SEPARATION => {
197                        if separation.len() == 0 {
198                            return Err(TimerError::InvalidFormat);
199                        }
200                    }
201                    Status::SLASH => {}
202                }
203                let min: usize = if min.len() == 0 {
204                    table[index].1
205                } else {
206                    String::from_utf8(min)
207                        .map_err(|_| TimerError::InvalidFormat)?
208                        .parse::<usize>()
209                        .map_err(|_| TimerError::InvalidFormat)?
210                };
211                let max: usize = if max.len() == 0 {
212                    table[index].2
213                } else {
214                    String::from_utf8(max)
215                        .map_err(|_| TimerError::InvalidFormat)?
216                        .parse::<usize>()
217                        .map_err(|_| TimerError::InvalidFormat)?
218                };
219                let separation: usize = if separation.len() == 0 {
220                    1
221                } else {
222                    String::from_utf8(separation)
223                        .map_err(|_| TimerError::InvalidFormat)?
224                        .parse::<usize>()
225                        .map_err(|_| TimerError::InvalidFormat)?
226                };
227                if min < table[index].1
228                    || table[index].2 < min
229                    || max < table[index].1
230                    || table[index].2 < max
231                    || max < min
232                {
233                    return Err(TimerError::InvalidFormat);
234                }
235                for z in expand(min, max, separation) {
236                    table[index].0[z] = true;
237                }
238            } // for y in x.split(',') {...}
239            index += 1;
240        } // for x in pattern.split(' ') {...}
241        let is_stop: Arc<AtomicBool> = self.is_stop.clone();
242        let handle = tokio::task::spawn(async move {
243            use iceyee_datetime::DateTime;
244            let second = &table[0];
245            let minute = &table[1];
246            let hour = &table[2];
247            let day = &table[3];
248            let month = &table[4];
249            let weekday = &table[5];
250            while !is_stop.load(Ordering::SeqCst) {
251                let t: u64 = (1000 - DateTime::now() as u64 % 1000) + 200;
252                let sl = tokio::task::spawn(Self::sleep(t));
253                let dt: DateTime = DateTime::new();
254                if second.0[dt.second]
255                    && minute.0[dt.minute]
256                    && hour.0[dt.hour]
257                    && day.0[dt.day]
258                    && month.0[dt.month]
259                    && weekday.0[dt.weekday]
260                {
261                    f().await;
262                }
263                while !is_stop.load(Ordering::SeqCst) && !sl.is_finished() {
264                    Self::sleep(50).await;
265                }
266            }
267        });
268        let thread_handles = self.thread_handles.clone();
269        tokio::task::spawn(async move {
270            thread_handles.lock().await.push(handle);
271        });
272        return Ok(());
273    }
274
275    /// 定时任务, 任务执行的同时等待, 时间单位:毫秒.
276    pub fn schedule_execute_before<F1, F2>(&mut self, delay: u64, period: u64, mut f: F1)
277    where
278        F1: FnMut() -> F2 + Send + 'static,
279        F2: Future<Output = ()> + Send + 'static,
280    {
281        let is_stop: Arc<AtomicBool> = self.is_stop.clone();
282        let handle = tokio::task::spawn(async move {
283            let sl = tokio::task::spawn(Timer::sleep(delay));
284            while !is_stop.load(Ordering::SeqCst) && !sl.is_finished() {
285                Self::sleep(200).await;
286            }
287            while !is_stop.load(Ordering::SeqCst) {
288                let sl = tokio::task::spawn(Timer::sleep(period));
289                f().await;
290                while !is_stop.load(Ordering::SeqCst) && !sl.is_finished() {
291                    Self::sleep(200).await;
292                }
293            }
294        });
295        let thread_handles = self.thread_handles.clone();
296        tokio::task::spawn(async move {
297            thread_handles.lock().await.push(handle);
298        });
299        return;
300    }
301
302    /// 定时任务, 在任务执行完成后等待, 时间单位:毫秒.
303    pub fn schedule_execute_after<F1, F2>(&mut self, delay: u64, period: u64, mut f: F1)
304    where
305        F1: FnMut() -> F2 + Send + 'static,
306        F2: Future<Output = ()> + Send + 'static,
307    {
308        let is_stop: Arc<AtomicBool> = self.is_stop.clone();
309        let handle = tokio::task::spawn(async move {
310            let sl = tokio::task::spawn(Self::sleep(delay));
311            while !is_stop.load(Ordering::SeqCst) && !sl.is_finished() {
312                Self::sleep(200).await;
313            }
314            while !is_stop.load(Ordering::SeqCst) {
315                f().await;
316                let sl = tokio::task::spawn(Self::sleep(period));
317                while !is_stop.load(Ordering::SeqCst) && !sl.is_finished() {
318                    Self::sleep(200).await;
319                }
320            }
321        });
322        let thread_handles = self.thread_handles.clone();
323        tokio::task::spawn(async move {
324            thread_handles.lock().await.push(handle);
325        });
326        return;
327    }
328}
329
330impl Drop for Timer {
331    fn drop(&mut self) {
332        self.is_stop.store(true, Ordering::SeqCst);
333        let thread_handles = self.thread_handles.clone();
334        tokio::task::spawn(async move {
335            let mut thread_handles = thread_handles.lock().await;
336            loop {
337                match thread_handles.pop() {
338                    Some(handle) => handle.await.unwrap(),
339                    None => break,
340                }
341            }
342        });
343        return;
344    }
345}
346
347// Function.