use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use std::sync::{Arc, RwLock};
use std::time::Duration;
use chrono::{DateTime, Utc};
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
#[derive(Clone, Default)]
pub(crate) struct TimeoutWheel<T: Clone + Hash + std::cmp::Eq> {
wheel: Arc<RwLock<BTreeMap<DateTime<Utc>, T>>>,
map: Arc<RwLock<HashMap<T, DateTime<Utc>>>>,
timeout: Arc<RwLock<Duration>>,
}
impl<T: Clone + Hash + std::cmp::Eq> TimeoutWheel<T> {
pub fn new() -> Self {
TimeoutWheel {
wheel: Arc::new(RwLock::new(BTreeMap::new())),
map: Arc::new(RwLock::new(HashMap::new())),
timeout: Arc::new(RwLock::new(DEFAULT_TIMEOUT)),
}
}
pub fn with_timeout(self, timeout: Duration) -> Self {
*self.timeout.write().unwrap() = timeout;
self
}
pub fn set_timeout(&self, timeout: Duration) {
*self.timeout.write().unwrap() = timeout;
}
pub fn insert(&self, e: T, instant: DateTime<Utc>) {
self.wheel.write().unwrap().insert(instant, e.clone());
self.map.write().unwrap().insert(e, instant);
}
pub fn expired(&self) -> Vec<T> {
let now = Utc::now();
let timeout = *self.timeout.read().unwrap();
self.wheel
.read()
.unwrap()
.iter()
.take_while(|(instant, _)| **instant + timeout < now)
.map(|(_, value)| value.clone())
.collect()
}
pub fn remove(&self, value: &T) -> Option<T> {
self.map
.write()
.unwrap()
.remove(value)
.and_then(|instant| self.wheel.write().unwrap().remove(&instant))
}
}