use crate::config::ipc_security::IdempotencyConfig;
use std::collections::HashMap;
use std::time::{Duration, Instant};
struct CacheEntry {
response: String,
inserted: Instant,
}
pub struct IdempotencyCache {
entries: HashMap<String, CacheEntry>,
max_entries: usize,
ttl: Duration,
}
impl IdempotencyCache {
pub fn new(max_entries: usize, ttl: Duration) -> Self {
Self {
entries: HashMap::with_capacity(max_entries.min(64)),
max_entries,
ttl,
}
}
pub fn from_config(config: &IdempotencyConfig) -> Self {
Self::new(
config.max_cached_results,
Duration::from_secs(config.result_cache_ttl_seconds),
)
}
pub fn get(&self, request_id: &str) -> Option<String> {
self.purge_expired_internal();
self.entries
.get(request_id)
.filter(|entry| entry.inserted.elapsed() < self.ttl)
.map(|entry| entry.response.clone())
}
pub fn put(&mut self, request_id: String, response: String) {
self.purge_expired_internal();
if self.entries.len() >= self.max_entries
&& let Some(oldest_key) = self
.entries
.iter()
.min_by_key(|(_, entry)| entry.inserted)
.map(|(k, _)| k.clone())
{
self.entries.remove(&oldest_key);
}
self.entries.insert(
request_id,
CacheEntry {
response,
inserted: Instant::now(),
},
);
}
fn purge_expired_internal(&self) {
}
pub fn purge_expired(&mut self) {
let now = Instant::now();
self.entries
.retain(|_, entry| now.duration_since(entry.inserted) < self.ttl);
}
}