Skip to main content

cfdp_simplified/daemon/
timer.rs

1use std::time::{Duration, Instant};
2
3#[derive(Debug)]
4pub struct Counter {
5    start_time: Instant,
6    timeout: Duration,
7    max_count: u32,
8    count: u32,
9    occurred: bool,
10    paused: bool,
11}
12impl Counter {
13    pub fn new(timeout: Duration, max_count: u32) -> Self {
14        Self {
15            max_count,
16            timeout,
17            count: 0,
18            start_time: Instant::now(),
19            occurred: false,
20            paused: true,
21        }
22    }
23    /// start the timer (if it was paused), setting the start_time
24    /// clear the occurred flag
25    /// the counter value is not reset
26    fn restart(&mut self) {
27        self.update();
28        self.start_time = Instant::now();
29        self.paused = false;
30        self.occurred = false;
31    }
32
33    /// start the timer (if it was paused), setting the start_time
34    /// clear the occurred flag
35    /// reset the  counter value to 0
36    fn reset(&mut self) {
37        self.start_time = Instant::now();
38        self.paused = false;
39        self.occurred = false;
40        self.count = 0;
41    }
42
43    fn update(&mut self) {
44        if self.paused {
45            return;
46        }
47        let now = Instant::now();
48        while now.duration_since(self.start_time) >= self.timeout {
49            self.count = (self.count + 1).clamp(0, self.max_count);
50            self.start_time += self.timeout;
51            self.occurred = true;
52        }
53    }
54
55    pub fn pause(&mut self) {
56        self.update();
57        self.paused = true;
58    }
59
60    pub fn start(&mut self) {
61        self.paused = false;
62    }
63
64    pub fn limit_reached(&mut self) -> bool {
65        self.update();
66        self.count == self.max_count
67    }
68
69    pub fn timeout_occurred(&mut self) -> bool {
70        self.update();
71        self.occurred
72    }
73
74    pub fn until_timeout(&self) -> Duration {
75        let next_timeout = self.start_time + self.timeout;
76        let now = Instant::now();
77        if next_timeout > now {
78            next_timeout.duration_since(now)
79        } else {
80            Duration::ZERO
81        }
82    }
83
84    #[cfg(test)]
85    pub fn get_count(&self) -> u32 {
86        self.count
87    }
88
89    #[cfg(test)]
90    pub fn is_ticking(&self) -> bool {
91        !self.paused
92    }
93}
94
95#[derive(Debug)]
96pub struct Timer {
97    pub inactivity: Counter,
98    pub nak: Counter,
99    pub eof: Counter,
100    pub progress_report: Counter,
101}
102impl Timer {
103    pub fn new(
104        inactivity_timeout: i64,
105        inactivity_max_count: u32,
106        eof_timeout: i64,
107        eof_max_count: u32,
108        nak_timeout: i64,
109        nak_max_count: u32,
110        progress_report_interval_secs: i64,
111    ) -> Self {
112        Self {
113            inactivity: Counter::new(
114                Duration::from_secs(inactivity_timeout as u64),
115                inactivity_max_count,
116            ),
117            eof: Counter::new(Duration::from_secs(eof_timeout as u64), eof_max_count),
118            nak: Counter::new(Duration::from_secs(nak_timeout as u64), nak_max_count),
119            progress_report: Counter::new(
120                Duration::from_secs(progress_report_interval_secs as u64),
121                u32::MAX,
122            ),
123        }
124    }
125
126    pub fn restart_inactivity(&mut self) {
127        self.inactivity.restart()
128    }
129
130    pub fn reset_inactivity(&mut self) {
131        self.inactivity.reset()
132    }
133
134    pub fn restart_eof(&mut self) {
135        self.eof.restart()
136    }
137
138    pub fn reset_eof(&mut self) {
139        self.eof.reset()
140    }
141
142    pub fn restart_nak(&mut self) {
143        self.nak.restart()
144    }
145
146    pub fn reset_nak(&mut self) {
147        self.nak.reset()
148    }
149
150    pub fn reset_progress_report(&mut self) {
151        self.progress_report.reset()
152    }
153    /// returns the duration until one of the timers timeouts
154    /// if all timers are paused, returns Duration::MAX
155    pub fn until_timeout(&self) -> Duration {
156        let mut min = Duration::MAX;
157
158        if !self.eof.paused {
159            min = Duration::min(min, self.eof.until_timeout());
160        }
161
162        if !self.nak.paused {
163            min = Duration::min(min, self.nak.until_timeout());
164        }
165
166        if !self.inactivity.paused {
167            min = Duration::min(min, self.inactivity.until_timeout());
168        }
169
170        if !self.progress_report.paused {
171            min = Duration::min(min, self.progress_report.until_timeout());
172        }
173        min
174    }
175}
176
177#[cfg(test)]
178mod test {
179    use super::*;
180
181    use std::{thread, time::Duration};
182
183    #[test]
184    fn timeout() {
185        let mut timer = Timer::new(1_i64, 5, 1_i64, 5, 1_i64, 5, 1_i64);
186        timer.restart_inactivity();
187        thread::sleep(Duration::from_secs_f32(2.5_f32));
188        timer.inactivity.pause();
189        assert_eq!(timer.inactivity.get_count(), 2);
190        assert!(!timer.inactivity.limit_reached());
191        assert!(timer.inactivity.timeout_occurred())
192    }
193
194    #[test]
195    fn no_timeout() {
196        let mut timer = Timer::new(3_i64, 5, 1_i64, 5, 1_i64, 5, 1_i64);
197        timer.restart_inactivity();
198        thread::sleep(Duration::from_secs_f32(1.1_f32));
199        timer.inactivity.pause();
200        assert!(!timer.inactivity.timeout_occurred());
201        // sleep again but make sure to cross the threshold from the original time out
202        thread::sleep(Duration::from_secs_f32(1.5_f32));
203        assert!(!timer.inactivity.timeout_occurred());
204
205        assert_eq!(timer.inactivity.get_count(), 0)
206    }
207
208    #[test]
209    fn limit() {
210        let mut timer = Timer::new(1_i64, 1, 1_i64, 5, 1_i64, 5, 1_i64);
211        timer.restart_inactivity();
212        thread::sleep(Duration::from_secs_f32(1.5));
213        assert!(timer.inactivity.limit_reached());
214        // make sure the clamping works right
215        thread::sleep(Duration::from_secs_f32(1.5));
216        assert!(timer.inactivity.limit_reached());
217        assert_eq!(timer.inactivity.get_count(), 1);
218    }
219
220    #[test]
221    fn restart_no_fail() {
222        let mut timer = Timer::new(2_i64, 5, 1_i64, 5, 1_i64, 5, 1_64);
223        timer.restart_inactivity();
224        thread::sleep(Duration::from_secs_f32(1.5));
225        assert!(!timer.inactivity.timeout_occurred());
226        timer.restart_inactivity();
227        thread::sleep(Duration::from_secs_f32(2.2));
228        timer.inactivity.pause();
229
230        assert!(timer.inactivity.timeout_occurred())
231    }
232
233    #[test]
234    fn timeout_all() {
235        let mut timer = Timer::new(1_i64, 5, 1_i64, 5, 1_i64, 5, 1_i64);
236        timer.restart_inactivity();
237        timer.restart_eof();
238        timer.restart_nak();
239        timer.reset_progress_report();
240        thread::sleep(Duration::from_secs_f32(1.5));
241        assert!(timer.inactivity.timeout_occurred());
242        assert!(timer.eof.timeout_occurred());
243        assert!(timer.nak.timeout_occurred());
244        assert!(timer.progress_report.timeout_occurred());
245        assert_eq!(timer.inactivity.get_count(), 1);
246        assert_eq!(timer.eof.get_count(), 1);
247        assert_eq!(timer.nak.get_count(), 1);
248        assert_eq!(timer.progress_report.get_count(), 1);
249    }
250}