|
|
|
|
|
|
|
use error_stack::Report; |
|
#[cfg(feature = "memory-cache")] |
|
use mini_moka::sync::Cache as MokaCache; |
|
#[cfg(feature = "memory-cache")] |
|
use std::time::Duration; |
|
use tokio::sync::Mutex; |
|
|
|
use crate::{config::parser::Config, models::aggregation_models::SearchResults}; |
|
|
|
use super::error::PoolError; |
|
#[cfg(feature = "redis-cache")] |
|
use super::redis_cacher::RedisCache; |
|
|
|
|
|
#[derive(Clone)] |
|
pub enum Cache { |
|
|
|
Disabled, |
|
#[cfg(feature = "redis-cache")] |
|
|
|
Redis(RedisCache), |
|
#[cfg(feature = "memory-cache")] |
|
|
|
InMemory(MokaCache<String, SearchResults>), |
|
} |
|
|
|
impl Cache { |
|
|
|
pub async fn build(_config: &Config) -> Self { |
|
#[cfg(feature = "redis-cache")] |
|
if let Some(url) = &_config.redis_url { |
|
log::info!("Using Redis running at {} for caching", &url); |
|
return Cache::new( |
|
RedisCache::new(url, 5) |
|
.await |
|
.expect("Redis cache configured"), |
|
); |
|
} |
|
#[cfg(feature = "memory-cache")] |
|
{ |
|
log::info!("Using an in-memory cache"); |
|
return Cache::new_in_memory(); |
|
} |
|
#[cfg(not(feature = "memory-cache"))] |
|
{ |
|
log::info!("Caching is disabled"); |
|
Cache::Disabled |
|
} |
|
} |
|
|
|
|
|
#[cfg(feature = "redis-cache")] |
|
pub fn new(redis_cache: RedisCache) -> Self { |
|
Cache::Redis(redis_cache) |
|
} |
|
|
|
|
|
#[cfg(feature = "memory-cache")] |
|
pub fn new_in_memory() -> Self { |
|
let cache = MokaCache::builder() |
|
.max_capacity(1000) |
|
.time_to_live(Duration::from_secs(60)) |
|
.build(); |
|
Cache::InMemory(cache) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn cached_json(&mut self, url: &str) -> Result<SearchResults, Report<PoolError>> { |
|
match self { |
|
Cache::Disabled => Err(Report::new(PoolError::MissingValue)), |
|
#[cfg(feature = "redis-cache")] |
|
Cache::Redis(redis_cache) => { |
|
let json = redis_cache.cached_json(url).await?; |
|
Ok(serde_json::from_str::<SearchResults>(&json) |
|
.map_err(|_| PoolError::SerializationError)?) |
|
} |
|
#[cfg(feature = "memory-cache")] |
|
Cache::InMemory(in_memory) => match in_memory.get(&url.to_string()) { |
|
Some(res) => Ok(res), |
|
None => Err(Report::new(PoolError::MissingValue)), |
|
}, |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn cache_results( |
|
&mut self, |
|
search_results: &SearchResults, |
|
url: &str, |
|
) -> Result<(), Report<PoolError>> { |
|
match self { |
|
Cache::Disabled => Ok(()), |
|
#[cfg(feature = "redis-cache")] |
|
Cache::Redis(redis_cache) => { |
|
let json = serde_json::to_string(search_results) |
|
.map_err(|_| PoolError::SerializationError)?; |
|
redis_cache.cache_results(&json, url).await |
|
} |
|
#[cfg(feature = "memory-cache")] |
|
Cache::InMemory(cache) => { |
|
cache.insert(url.to_string(), search_results.clone()); |
|
Ok(()) |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
pub struct SharedCache { |
|
|
|
cache: Mutex<Cache>, |
|
} |
|
|
|
impl SharedCache { |
|
|
|
pub fn new(cache: Cache) -> Self { |
|
Self { |
|
cache: Mutex::new(cache), |
|
} |
|
} |
|
|
|
|
|
pub async fn cached_json(&self, url: &str) -> Result<SearchResults, Report<PoolError>> { |
|
let mut mut_cache = self.cache.lock().await; |
|
mut_cache.cached_json(url).await |
|
} |
|
|
|
|
|
|
|
pub async fn cache_results( |
|
&self, |
|
search_results: &SearchResults, |
|
url: &str, |
|
) -> Result<(), Report<PoolError>> { |
|
let mut mut_cache = self.cache.lock().await; |
|
mut_cache.cache_results(search_results, url).await |
|
} |
|
} |
|
|