use std::collections::HashMap;
use std::sync::RwLock;
use url::Url;
pub struct ConditionalCache {
entries: RwLock<HashMap<String, CacheEntry>>,
max_size: usize,
}
#[derive(Debug, Clone)]
pub struct CacheEntry {
pub etag: Option<String>,
pub last_modified: Option<String>,
pub cached_at: std::time::Instant,
}
impl Default for ConditionalCache {
fn default() -> Self {
Self::new(10000)
}
}
impl ConditionalCache {
pub fn new(max_size: usize) -> Self {
Self {
entries: RwLock::new(HashMap::new()),
max_size,
}
}
fn cache_key(url: &Url) -> String {
let mut url = url.clone();
url.set_fragment(None);
url.to_string()
}
pub fn get(&self, url: &Url) -> Option<CacheEntry> {
let key = Self::cache_key(url);
self.entries.read().ok()?.get(&key).cloned()
}
pub fn set(&self, url: &Url, etag: Option<String>, last_modified: Option<String>) {
let key = Self::cache_key(url);
let entry = CacheEntry {
etag,
last_modified,
cached_at: std::time::Instant::now(),
};
if let Ok(mut entries) = self.entries.write() {
if entries.len() >= self.max_size {
let to_remove: Vec<_> = entries
.iter()
.take(self.max_size / 10)
.map(|(k, _)| k.clone())
.collect();
for k in to_remove {
entries.remove(&k);
}
}
entries.insert(key, entry);
}
}
pub fn remove(&self, url: &Url) {
let key = Self::cache_key(url);
if let Ok(mut entries) = self.entries.write() {
entries.remove(&key);
}
}
pub fn clear(&self) {
if let Ok(mut entries) = self.entries.write() {
entries.clear();
}
}
pub fn len(&self) -> usize {
self.entries.read().map(|e| e.len()).unwrap_or(0)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct ConditionalRequest {
pub etag: Option<String>,
pub last_modified: Option<String>,
}
impl ConditionalRequest {
pub fn new() -> Self {
Self {
etag: None,
last_modified: None,
}
}
pub fn from_cache(entry: &CacheEntry) -> Self {
Self {
etag: entry.etag.clone(),
last_modified: entry.last_modified.clone(),
}
}
pub fn has_conditions(&self) -> bool {
self.etag.is_some() || self.last_modified.is_some()
}
}
impl Default for ConditionalRequest {
fn default() -> Self {
Self::new()
}
}