use std::collections::HashMap;
use std::sync::Mutex;
use std::time::{Duration, Instant};
pub const IDLE_TIMEOUT: Duration = Duration::from_secs(300);
pub struct SessionWindowMap {
inner: Mutex<HashMap<String, Instant>>,
}
impl Default for SessionWindowMap {
fn default() -> Self {
Self::new()
}
}
impl SessionWindowMap {
pub fn new() -> Self {
Self {
inner: Mutex::new(HashMap::new()),
}
}
pub fn touch(&self, tool: &str) -> bool {
let mut map = self.inner.lock().unwrap();
let now = Instant::now();
let is_new = map
.get(tool)
.map(|last| now.duration_since(*last) >= IDLE_TIMEOUT)
.unwrap_or(true);
map.insert(tool.to_string(), now);
is_new
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn first_touch_is_new_session() {
let m = SessionWindowMap::new();
assert!(m.touch("cursor"));
}
#[test]
fn immediate_second_touch_is_same_session() {
let m = SessionWindowMap::new();
m.touch("cursor");
assert!(!m.touch("cursor"));
}
#[test]
fn different_tools_are_independent() {
let m = SessionWindowMap::new();
m.touch("cursor");
assert!(
m.touch("codex"),
"codex is a new session even if cursor is active"
);
}
}