1use std::time::Instant;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum DaemonState {
7 Active,
8 Idle,
9 Dormant,
10}
11
12pub struct IdleTracker {
13 last_query: Instant,
14 last_change: Instant,
15}
16
17impl Default for IdleTracker {
18 fn default() -> Self {
19 Self::new()
20 }
21}
22
23impl IdleTracker {
24 pub fn new() -> Self {
25 let now = Instant::now();
26 Self {
27 last_query: now,
28 last_change: now,
29 }
30 }
31
32 pub fn record_query(&mut self) {
33 self.last_query = Instant::now();
34 }
35
36 pub fn record_change(&mut self) {
37 self.last_change = Instant::now();
38 }
39
40 pub fn state(&self) -> DaemonState {
41 let last_activity = self.last_query.max(self.last_change);
42 let elapsed = last_activity.elapsed().as_secs();
43
44 if elapsed < 5 * 60 {
45 DaemonState::Active
46 } else if elapsed < 30 * 60 {
47 DaemonState::Idle
48 } else {
49 DaemonState::Dormant
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use std::time::Duration;
58
59 #[test]
60 fn test_idle_tracker() {
61 let mut tracker = IdleTracker::new();
62 assert_eq!(tracker.state(), DaemonState::Active);
63
64 tracker.last_query = Instant::now() - Duration::from_secs(6 * 60);
66 tracker.last_change = Instant::now() - Duration::from_secs(6 * 60);
67 assert_eq!(tracker.state(), DaemonState::Idle);
68
69 tracker.last_query = Instant::now() - Duration::from_secs(31 * 60);
71 tracker.last_change = Instant::now() - Duration::from_secs(31 * 60);
72 assert_eq!(tracker.state(), DaemonState::Dormant);
73
74 tracker.record_query();
76 assert_eq!(tracker.state(), DaemonState::Active);
77 }
78}