use super::context::AgentContext;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SessionState {
Active,
Idle,
Expired,
}
#[derive(Debug)]
pub struct Session {
pub id: Arc<str>,
pub agent_name: Arc<str>,
pub context: AgentContext,
pub state: SessionState,
pub created_at: Instant,
pub last_active: Instant,
pub timeout: Duration,
}
impl Session {
pub fn new(
id: Arc<str>,
agent_name: Arc<str>,
context: AgentContext,
timeout: Duration,
) -> Self {
let now = Instant::now();
Self {
id,
agent_name,
context,
state: SessionState::Active,
created_at: now,
last_active: now,
timeout,
}
}
pub fn is_expired(&self) -> bool {
self.last_active.elapsed() > self.timeout
}
pub fn touch(&mut self) {
self.last_active = Instant::now();
self.state = SessionState::Active;
}
pub fn mark_idle(&mut self) {
self.state = SessionState::Idle;
}
}
pub struct SessionManager {
sessions: HashMap<Arc<str>, Session>,
default_timeout: Duration,
}
impl SessionManager {
pub fn new(timeout_minutes: u32) -> Self {
Self {
sessions: HashMap::new(),
default_timeout: Duration::from_secs(timeout_minutes as u64 * 60),
}
}
pub fn create(&mut self, agent_name: Arc<str>, context: AgentContext) -> Arc<str> {
let id: Arc<str> = Arc::from(format!("session_{}", uuid::Uuid::new_v4().simple()));
let session = Session::new(id.clone(), agent_name, context, self.default_timeout);
self.sessions.insert(id.clone(), session);
id
}
pub fn get(&self, id: &str) -> Option<&Session> {
self.sessions.get(id)
}
pub fn get_mut(&mut self, id: &str) -> Option<&mut Session> {
self.sessions.get_mut(id)
}
pub fn get_by_agent(&self, agent_name: &str) -> Option<&Session> {
self.sessions
.values()
.find(|s| s.agent_name.as_ref() == agent_name)
}
pub fn get_by_agent_mut(&mut self, agent_name: &str) -> Option<&mut Session> {
self.sessions
.values_mut()
.find(|s| s.agent_name.as_ref() == agent_name)
}
pub fn delete(&mut self, id: &str) -> bool {
self.sessions.remove(id).is_some()
}
pub fn delete_by_agent(&mut self, agent_name: &str) -> bool {
let id = self
.sessions
.iter()
.find(|(_, s)| s.agent_name.as_ref() == agent_name)
.map(|(id, _)| id.clone());
if let Some(id) = id {
self.sessions.remove(&id).is_some()
} else {
false
}
}
pub fn list(&self) -> Vec<&Session> {
self.sessions.values().collect()
}
pub fn cleanup_expired(&mut self) -> usize {
let expired: Vec<Arc<str>> = self
.sessions
.iter()
.filter(|(_, s)| s.is_expired())
.map(|(id, _)| id.clone())
.collect();
let count = expired.len();
for id in expired {
self.sessions.remove(&id);
}
count
}
pub fn count(&self) -> usize {
self.sessions.len()
}
}
impl Default for SessionManager {
fn default() -> Self {
Self::new(30)
}
}