use std::sync::Arc;
use std::time::{Duration, Instant};
use dashmap::DashMap;
pub struct DeduplicationStore {
entries: DashMap<String, Instant>,
window: Duration,
}
impl DeduplicationStore {
pub fn new(window_secs: u64) -> Arc<Self> {
let window = Duration::from_secs(window_secs);
let store = Arc::new(Self {
entries: DashMap::new(),
window,
});
let weak = Arc::downgrade(&store);
tokio::spawn(async move {
let interval = Duration::from_secs(window_secs.max(1) / 2 + 1);
loop {
tokio::time::sleep(interval).await;
let Some(store) = weak.upgrade() else {
break; };
store.purge_expired();
}
});
store
}
pub fn check_and_insert(&self, key: &str) -> bool {
let now = Instant::now();
if let Some(entry) = self.entries.get(key)
&& now.duration_since(*entry.value()) < self.window
{
return false; }
self.entries.insert(key.to_string(), now);
true
}
fn purge_expired(&self) {
let cutoff = Instant::now() - self.window;
self.entries.retain(|_, ts| *ts > cutoff);
}
}