use std::collections::HashMap;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
pub struct LessonCache {
store: RwLock<HashMap<String, (Instant, String)>>,
ttl: Duration,
max_entries: usize,
}
impl LessonCache {
pub fn new(ttl: Duration, max_entries: usize) -> Self {
Self {
store: RwLock::new(HashMap::new()),
ttl,
max_entries,
}
}
pub async fn get(&self, session_id: &str, query: &str) -> Option<String> {
let key = Self::key(session_id, query);
let store = self.store.read().await;
if let Some((ts, value)) = store.get(&key) {
if ts.elapsed() < self.ttl {
return Some(value.clone());
}
}
None
}
pub async fn set(&self, session_id: &str, query: &str, context_block: String) {
let key = Self::key(session_id, query);
let mut store = self.store.write().await;
if store.len() >= self.max_entries {
if let Some(oldest_key) = store
.iter()
.min_by_key(|(_, (ts, _))| *ts)
.map(|(k, _)| k.clone())
{
store.remove(&oldest_key);
}
}
store.insert(key, (Instant::now(), context_block));
}
#[allow(dead_code)]
pub async fn clear(&self) {
self.store.write().await.clear();
}
fn key(session_id: &str, query: &str) -> String {
use std::hash::{Hash, Hasher};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
query.hash(&mut hasher);
let qh = format!("{:x}", hasher.finish());
format!("{}:{}", session_id, &qh[..12.min(qh.len())])
}
}