hyperclock/components/
watcher.rs1use crate::common::PhaseId;
4use crate::config::GongConfig;
5use crate::events::GongEvent;
6use crate::time::TickEvent;
7use chrono::Utc;
8use std::sync::Arc;
9use std::time::{Duration, Instant};
10use tokio::sync::broadcast;
11
12pub type ConditionCheck = Box<dyn Fn() -> bool + Send + Sync>;
14
15#[doc(hidden)]
17pub(crate) struct IntervalWatcher {
18 pub phase_to_watch: PhaseId,
19 pub interval: Duration,
20 pub last_fired: Instant,
21 pub task_logic: Box<dyn FnMut() + Send + Sync>,
22}
23
24impl IntervalWatcher {
25 pub(crate) fn new(
27 phase_to_watch: PhaseId,
28 interval: Duration,
29 task_logic: Box<dyn FnMut() + Send + Sync>,
30 ) -> Self {
31 Self {
32 phase_to_watch,
33 interval,
34 last_fired: Instant::now(),
35 task_logic,
36 }
37 }
38
39 pub(crate) fn process_phase(&mut self, current_phase: PhaseId) -> bool {
42 if current_phase == self.phase_to_watch {
43 if self.last_fired.elapsed() >= self.interval {
44 (self.task_logic)();
45 self.last_fired = Instant::now();
46 return true;
47 }
48 }
49 false
50 }
51}
52
53#[doc(hidden)]
55pub(crate) struct GongWatcher {
56 config: Arc<GongConfig>,
57 last_known_date: chrono::NaiveDate,
58}
59
60impl GongWatcher {
61 pub(crate) fn new(config: Arc<GongConfig>) -> Self {
63 let now = Utc::now().with_timezone(&config.timezone);
64 Self {
65 config,
66 last_known_date: now.date_naive(),
67 }
68 }
69
70 pub(crate) fn process_tick(
72 &mut self,
73 _tick: &TickEvent,
74 gong_event_sender: &broadcast::Sender<GongEvent>,
75 ) {
76 let now = Utc::now().with_timezone(&self.config.timezone);
77 let current_date = now.date_naive();
78
79 if current_date != self.last_known_date {
80 gong_event_sender
81 .send(GongEvent::DateChanged {
82 new_date: current_date,
83 })
84 .ok();
85
86 for holiday in &self.config.holidays {
87 if holiday.date == current_date {
88 gong_event_sender
89 .send(GongEvent::Holiday {
90 name: holiday.name.clone(),
91 date: holiday.date,
92 })
93 .ok();
94 }
95 }
96 self.last_known_date = current_date;
97 }
98 }
99}
100
101#[doc(hidden)]
103pub(crate) struct ConditionalWatcher {
104 pub condition: ConditionCheck,
105 pub task_logic: Box<dyn FnMut() + Send + Sync>,
106 pub is_one_shot: bool,
107}
108
109impl ConditionalWatcher {
110 pub(crate) fn new(
112 condition: ConditionCheck,
113 task_logic: Box<dyn FnMut() + Send + Sync>,
114 is_one_shot: bool,
115 ) -> Self {
116 Self {
117 condition,
118 task_logic,
119 is_one_shot,
120 }
121 }
122
123 pub(crate) fn check_and_fire(&mut self) -> bool {
126 if (self.condition)() {
127 (self.task_logic)();
128 true
129 } else {
130 false
131 }
132 }
133}