1use log::debug;
9#[cfg(all(feature = "server", test))]
10use mock_instant::Instant;
11use serde::{Deserialize, Serialize};
12#[cfg(feature = "server")]
13use std::io::{Error, ErrorKind};
14#[cfg(all(feature = "server", not(test)))]
15use std::time::Instant;
16use std::{
17 fmt,
18 io::Result,
19 ops::{Deref, DerefMut},
20 sync::Arc,
21};
22#[cfg(feature = "server")]
23use tokio::sync::Mutex;
24
25use crate::handler::{self, Handler};
26
27#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
33pub enum TimerLoop {
34 #[default]
39 Infinite,
40
41 Fixed(usize),
43}
44
45impl From<usize> for TimerLoop {
46 fn from(count: usize) -> Self {
47 if count == 0 {
48 Self::Infinite
49 } else {
50 Self::Fixed(count)
51 }
52 }
53}
54
55#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
60pub struct TimerCycle {
61 pub name: String,
63
64 pub duration: usize,
72}
73
74impl TimerCycle {
75 pub fn new(name: impl ToString, duration: usize) -> Self {
76 Self {
77 name: name.to_string(),
78 duration,
79 }
80 }
81}
82
83impl<T: ToString> From<(T, usize)> for TimerCycle {
84 fn from((name, duration): (T, usize)) -> Self {
85 Self::new(name, duration)
86 }
87}
88
89#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
91pub struct TimerCycles(Vec<TimerCycle>);
92
93impl<T: IntoIterator<Item = TimerCycle>> From<T> for TimerCycles {
94 fn from(cycles: T) -> Self {
95 Self(cycles.into_iter().collect())
96 }
97}
98
99impl Deref for TimerCycles {
100 type Target = Vec<TimerCycle>;
101
102 fn deref(&self) -> &Self::Target {
103 &self.0
104 }
105}
106
107impl DerefMut for TimerCycles {
108 fn deref_mut(&mut self) -> &mut Self::Target {
109 &mut self.0
110 }
111}
112
113#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
118pub enum TimerState {
119 Running,
121
122 Paused,
124
125 #[default]
127 Stopped,
128}
129
130#[derive(Clone, Debug, Eq, PartialEq)]
135pub enum TimerEvent {
136 Started,
138
139 Began(TimerCycle),
141
142 Running(TimerCycle),
144
145 Set(TimerCycle),
147
148 Paused(TimerCycle),
150
151 Resumed(TimerCycle),
153
154 Ended(TimerCycle),
156
157 Stopped,
159}
160
161#[derive(Clone)]
163pub struct TimerConfig {
164 pub cycles: TimerCycles,
166
167 pub cycles_count: TimerLoop,
169
170 pub handler: Arc<Handler<TimerEvent>>,
172}
173
174impl Default for TimerConfig {
175 fn default() -> Self {
176 Self {
177 cycles: Default::default(),
178 cycles_count: Default::default(),
179 handler: handler::default(),
180 }
181 }
182}
183
184#[cfg(feature = "server")]
185impl TimerConfig {
186 fn clone_first_cycle(&self) -> Result<TimerCycle> {
187 self.cycles.first().cloned().ok_or_else(|| {
188 Error::new(
189 ErrorKind::NotFound,
190 "cannot find first cycle from timer config",
191 )
192 })
193 }
194}
195
196#[derive(Clone, Default, Serialize, Deserialize)]
198pub struct Timer {
199 #[serde(skip)]
201 pub config: TimerConfig,
202
203 pub state: TimerState,
205
206 pub cycle: TimerCycle,
208
209 pub cycles_count: TimerLoop,
211
212 #[cfg(feature = "server")]
213 #[serde(skip)]
214 pub started_at: Option<Instant>,
215
216 #[cfg(feature = "server")]
217 pub elapsed: usize,
218}
219
220impl fmt::Debug for Timer {
221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222 let timer = serde_json::to_string(self).map_err(|_| fmt::Error)?;
223 write!(f, "{timer}")
224 }
225}
226
227impl Eq for Timer {}
228
229#[cfg(feature = "server")]
230impl PartialEq for Timer {
231 fn eq(&self, other: &Self) -> bool {
232 self.state == other.state && self.cycle == other.cycle && self.elapsed() == other.elapsed()
233 }
234}
235
236#[cfg(not(feature = "server"))]
237impl PartialEq for Timer {
238 fn eq(&self, other: &Self) -> bool {
239 self.state == other.state && self.cycle == other.cycle
240 }
241}
242
243#[cfg(feature = "server")]
244impl Timer {
245 pub fn elapsed(&self) -> usize {
246 self.started_at
247 .map(|i| i.elapsed().as_secs() as usize)
248 .unwrap_or_default()
249 + self.elapsed
250 }
251
252 pub async fn update(&mut self) {
253 let mut elapsed = self.elapsed();
254
255 match self.state {
256 TimerState::Running => {
257 let (cycles, total_duration) = self.config.cycles.iter().cloned().fold(
258 (Vec::new(), 0),
259 |(mut cycles, mut sum), mut cycle| {
260 cycle.duration += sum;
261 sum = cycle.duration;
262 cycles.push(cycle);
263 (cycles, sum)
264 },
265 );
266
267 if let TimerLoop::Fixed(cycles_count) = self.cycles_count {
268 if elapsed >= (total_duration * cycles_count) {
269 self.state = TimerState::Stopped;
270 return;
271 }
272 }
273
274 elapsed = elapsed % total_duration;
275
276 let last_cycle = cycles[cycles.len() - 1].clone();
277 let next_cycle = cycles
278 .into_iter()
279 .fold(None, |next_cycle, mut cycle| match next_cycle {
280 None if elapsed < cycle.duration => {
281 cycle.duration = cycle.duration - elapsed;
282 Some(cycle)
283 }
284 _ => next_cycle,
285 })
286 .unwrap_or(last_cycle);
287
288 self.fire_event(TimerEvent::Running(self.cycle.clone()))
289 .await;
290
291 if self.cycle.name != next_cycle.name {
292 let mut prev_cycle = self.cycle.clone();
293 prev_cycle.duration = 0;
294 self.fire_events([
295 TimerEvent::Ended(prev_cycle),
296 TimerEvent::Began(next_cycle.clone()),
297 ])
298 .await;
299 }
300
301 self.cycle = next_cycle;
302 }
303 TimerState::Paused => {
304 }
306 TimerState::Stopped => {
307 }
309 }
310 }
311
312 pub async fn fire_event(&self, event: TimerEvent) {
313 let handler = &self.config.handler;
314 debug!("firing timer event {event:?}");
315 if let Err(err) = handler(event.clone()).await {
316 debug!("cannot fire timer event, skipping it");
317 debug!("{err:?}");
318 }
319 }
320
321 pub async fn fire_events(&self, events: impl IntoIterator<Item = TimerEvent>) {
322 for event in events.into_iter() {
323 self.fire_event(event).await
324 }
325 }
326
327 pub async fn start(&mut self) -> Result<()> {
328 if matches!(self.state, TimerState::Stopped) {
329 self.state = TimerState::Running;
330 self.cycle = self.config.clone_first_cycle()?;
331 self.cycles_count = self.config.cycles_count.clone();
332 self.started_at = Some(Instant::now());
333 self.elapsed = 0;
334 self.fire_events([TimerEvent::Started, TimerEvent::Began(self.cycle.clone())])
335 .await;
336 }
337 Ok(())
338 }
339
340 pub async fn set(&mut self, duration: usize) -> Result<()> {
341 self.cycle.duration = duration;
342 self.fire_event(TimerEvent::Set(self.cycle.clone())).await;
343 Ok(())
344 }
345
346 pub async fn pause(&mut self) -> Result<()> {
347 if matches!(self.state, TimerState::Running) {
348 self.state = TimerState::Paused;
349 self.elapsed = self.elapsed();
350 self.started_at = None;
351 self.fire_event(TimerEvent::Paused(self.cycle.clone()))
352 .await;
353 }
354 Ok(())
355 }
356
357 pub async fn resume(&mut self) -> Result<()> {
358 if matches!(self.state, TimerState::Paused) {
359 self.state = TimerState::Running;
360 self.started_at = Some(Instant::now());
361 self.fire_event(TimerEvent::Resumed(self.cycle.clone()))
362 .await;
363 }
364 Ok(())
365 }
366
367 pub async fn stop(&mut self) -> Result<()> {
368 if matches!(self.state, TimerState::Running) {
369 self.state = TimerState::Stopped;
370 self.fire_events([TimerEvent::Ended(self.cycle.clone()), TimerEvent::Stopped])
371 .await;
372 self.cycle = self.config.clone_first_cycle()?;
373 self.cycles_count = self.config.cycles_count.clone();
374 self.started_at = None;
375 self.elapsed = 0;
376 }
377 Ok(())
378 }
379}
380
381#[cfg(feature = "server")]
387#[derive(Clone, Debug, Default)]
388pub struct ThreadSafeTimer(Arc<Mutex<Timer>>);
389
390#[cfg(feature = "server")]
391impl ThreadSafeTimer {
392 pub fn new(config: TimerConfig) -> Result<Self> {
393 let mut timer = Timer::default();
394
395 timer.config = config;
396 timer.cycle = timer.config.clone_first_cycle()?;
397 timer.cycles_count = timer.config.cycles_count.clone();
398
399 Ok(Self(Arc::new(Mutex::new(timer))))
400 }
401
402 pub async fn update(&self) {
403 self.0.lock().await.update().await;
404 }
405
406 pub async fn start(&self) -> Result<()> {
407 self.0.lock().await.start().await
408 }
409
410 pub async fn get(&self) -> Timer {
411 self.0.lock().await.clone()
412 }
413
414 pub async fn set(&self, duration: usize) -> Result<()> {
415 self.0.lock().await.set(duration).await
416 }
417
418 pub async fn pause(&self) -> Result<()> {
419 self.0.lock().await.pause().await
420 }
421
422 pub async fn resume(&self) -> Result<()> {
423 self.0.lock().await.resume().await
424 }
425
426 pub async fn stop(&self) -> Result<()> {
427 self.0.lock().await.stop().await
428 }
429}
430
431#[cfg(feature = "server")]
432impl Deref for ThreadSafeTimer {
433 type Target = Arc<Mutex<Timer>>;
434
435 fn deref(&self) -> &Self::Target {
436 &self.0
437 }
438}
439
440#[cfg(feature = "server")]
441impl DerefMut for ThreadSafeTimer {
442 fn deref_mut(&mut self) -> &mut Self::Target {
443 &mut self.0
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use mock_instant::{Instant, MockClock};
450 use once_cell::sync::Lazy;
451 use std::{sync::Arc, time::Duration};
452
453 use super::*;
454
455 fn testing_timer() -> Timer {
456 Timer {
457 config: TimerConfig {
458 cycles: TimerCycles::from([
459 TimerCycle::new("a", 3),
460 TimerCycle::new("b", 2),
461 TimerCycle::new("c", 1),
462 ]),
463 ..Default::default()
464 },
465 state: TimerState::Running,
466 cycle: TimerCycle::new("a", 3),
467 started_at: Some(Instant::now()),
468 ..Default::default()
469 }
470 }
471
472 #[tokio::test]
473 async fn running_infinite_timer() {
474 let mut timer = testing_timer();
475
476 assert_eq!(timer.state, TimerState::Running);
477 assert_eq!(timer.cycle, TimerCycle::new("a", 3));
478
479 MockClock::advance(Duration::from_secs(2));
484 timer.update().await;
485
486 assert_eq!(timer.state, TimerState::Running);
487 assert_eq!(timer.cycle, TimerCycle::new("a", 1));
488
489 MockClock::advance(Duration::from_secs(1));
493 timer.update().await;
494
495 assert_eq!(timer.state, TimerState::Running);
496 assert_eq!(timer.cycle, TimerCycle::new("b", 2));
497
498 MockClock::advance(Duration::from_secs(2));
502 timer.update().await;
503
504 assert_eq!(timer.state, TimerState::Running);
505 assert_eq!(timer.cycle, TimerCycle::new("c", 1));
506
507 MockClock::advance(Duration::from_secs(1));
511 timer.update().await;
512
513 assert_eq!(timer.state, TimerState::Running);
514 assert_eq!(timer.cycle, TimerCycle::new("a", 3));
515 }
516
517 #[tokio::test]
518 async fn running_timer_events() {
519 static EVENTS: Lazy<Mutex<Vec<TimerEvent>>> = Lazy::new(|| Mutex::const_new(Vec::new()));
520
521 let mut timer = testing_timer();
522
523 timer.config.handler = Arc::new(|evt| {
524 Box::pin(async {
525 EVENTS.lock().await.push(evt);
526 Ok(())
527 })
528 });
529
530 MockClock::advance(Duration::from_secs(1));
532 timer.update().await;
533 MockClock::advance(Duration::from_secs(1));
534 timer.update().await;
535 MockClock::advance(Duration::from_secs(1));
536 timer.update().await;
537 MockClock::advance(Duration::from_secs(1));
538 timer.update().await;
539
540 assert_eq!(
541 *EVENTS.lock().await,
542 vec![
543 TimerEvent::Running(TimerCycle::new("a", 3)),
544 TimerEvent::Running(TimerCycle::new("a", 2)),
545 TimerEvent::Running(TimerCycle::new("a", 1)),
546 TimerEvent::Ended(TimerCycle::new("a", 0)),
547 TimerEvent::Began(TimerCycle::new("b", 2)),
548 TimerEvent::Running(TimerCycle::new("b", 2)),
549 ]
550 );
551 }
552
553 #[tokio::test]
554 async fn paused_timer_not_impacted_by_iterator() {
555 let mut timer = testing_timer();
556 timer.state = TimerState::Paused;
557 let prev_timer = timer.clone();
558 timer.update().await;
559 assert_eq!(prev_timer, timer);
560 }
561
562 #[tokio::test]
563 async fn stopped_timer_not_impacted_by_iterator() {
564 let mut timer = testing_timer();
565 timer.state = TimerState::Stopped;
566 let prev_timer = timer.clone();
567 timer.update().await;
568 assert_eq!(prev_timer, timer);
569 }
570
571 #[cfg(feature = "server")]
572 #[tokio::test]
573 async fn thread_safe_timer() {
574 let mut timer = testing_timer();
575 static EVENTS: Lazy<Mutex<Vec<TimerEvent>>> = Lazy::new(|| Mutex::const_new(Vec::new()));
576
577 timer.config.handler = Arc::new(move |evt| {
578 Box::pin(async {
579 EVENTS.lock().await.push(evt);
580 Ok(())
581 })
582 });
583 let timer = ThreadSafeTimer::new(timer.config).unwrap();
584
585 assert_eq!(
586 timer.get().await,
587 Timer {
588 state: TimerState::Stopped,
589 cycle: TimerCycle::new("a", 3),
590 ..Default::default()
591 }
592 );
593
594 timer.start().await.unwrap();
595 timer.set(21).await.unwrap();
596
597 assert_eq!(
598 timer.get().await,
599 Timer {
600 state: TimerState::Running,
601 cycle: TimerCycle::new("a", 21),
602 ..Default::default()
603 }
604 );
605
606 assert_eq!(
607 timer.get().await,
608 Timer {
609 state: TimerState::Running,
610 cycle: TimerCycle::new("a", 21),
611 ..Default::default()
612 }
613 );
614
615 timer.pause().await.unwrap();
616
617 assert_eq!(
618 timer.get().await,
619 Timer {
620 state: TimerState::Paused,
621 cycle: TimerCycle::new("a", 21),
622 ..Default::default()
623 }
624 );
625
626 timer.resume().await.unwrap();
627
628 assert_eq!(
629 timer.get().await,
630 Timer {
631 state: TimerState::Running,
632 cycle: TimerCycle::new("a", 21),
633 ..Default::default()
634 }
635 );
636
637 timer.stop().await.unwrap();
638
639 assert_eq!(
640 timer.get().await,
641 Timer {
642 state: TimerState::Stopped,
643 cycle: TimerCycle::new("a", 3),
644 ..Default::default()
645 }
646 );
647
648 assert_eq!(
649 *EVENTS.lock().await,
650 vec![
651 TimerEvent::Started,
652 TimerEvent::Began(TimerCycle::new("a", 3)),
653 TimerEvent::Set(TimerCycle::new("a", 21)),
654 TimerEvent::Paused(TimerCycle::new("a", 21)),
655 TimerEvent::Resumed(TimerCycle::new("a", 21)),
656 TimerEvent::Ended(TimerCycle::new("a", 21)),
657 TimerEvent::Stopped,
658 ]
659 );
660 }
661}