use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
#[derive(Debug, Clone, Default)]
pub struct Activity {
last: Arc<Mutex<Option<Instant>>>,
}
impl Activity {
pub fn touch(&self) {
*self.last.lock().expect("activity poisoned") = Some(Instant::now());
}
pub fn has_seen_activity(&self) -> bool {
self.last.lock().expect("activity poisoned").is_some()
}
pub fn is_idle_for(&self, idle: Duration) -> bool {
match *self.last.lock().expect("activity poisoned") {
None => true,
Some(at) => at.elapsed() >= idle,
}
}
pub fn is_active(&self, idle: Duration) -> bool {
self.has_seen_activity() && !self.is_idle_for(idle)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_fresh_activity_has_seen_nothing_and_is_idle() {
let activity = Activity::default();
assert!(!activity.has_seen_activity());
assert!(activity.is_idle_for(Duration::from_secs(1)));
assert!(!activity.is_active(Duration::from_secs(60)));
}
#[test]
fn touching_makes_it_active_then_idle_again() {
let activity = Activity::default();
activity.touch();
assert!(activity.has_seen_activity());
assert!(activity.is_active(Duration::from_secs(60)));
assert!(!activity.is_idle_for(Duration::from_secs(60)));
std::thread::sleep(Duration::from_millis(20));
assert!(activity.is_idle_for(Duration::from_millis(10)));
assert!(!activity.is_active(Duration::from_millis(10)));
}
}