|
|
|
|
|
|
|
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::CacheError; |
|
#[cfg(feature = "redis-cache")] |
|
use super::redis_cacher::RedisCache; |
|
|
|
|
|
#[derive(Clone)] |
|
pub enum Cache { |
|
|
|
Disabled, |
|
#[cfg(all(feature = "redis-cache", not(feature = "memory-cache")))] |
|
|
|
Redis(RedisCache), |
|
#[cfg(all(feature = "memory-cache", not(feature = "redis-cache")))] |
|
|
|
InMemory(MokaCache<String, SearchResults>), |
|
#[cfg(all(feature = "redis-cache", feature = "memory-cache"))] |
|
|
|
Hybrid(RedisCache, MokaCache<String, SearchResults>), |
|
} |
|
|
|
impl Cache { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn build(_config: &Config) -> Self { |
|
#[cfg(all(feature = "redis-cache", feature = "memory-cache"))] |
|
{ |
|
log::info!("Using a hybrid cache"); |
|
Cache::new_hybrid( |
|
RedisCache::new(&_config.redis_url, 5) |
|
.await |
|
.expect("Redis cache configured"), |
|
) |
|
} |
|
#[cfg(all(feature = "redis-cache", not(feature = "memory-cache")))] |
|
{ |
|
log::info!("Listening redis server on {}", &_config.redis_url); |
|
Cache::new( |
|
RedisCache::new(&_config.redis_url, 5) |
|
.await |
|
.expect("Redis cache configured"), |
|
) |
|
} |
|
#[cfg(all(feature = "memory-cache", not(feature = "redis-cache")))] |
|
{ |
|
log::info!("Using an in-memory cache"); |
|
Cache::new_in_memory() |
|
} |
|
#[cfg(not(any(feature = "memory-cache", feature = "redis-cache")))] |
|
{ |
|
log::info!("Caching is disabled"); |
|
Cache::Disabled |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(all(feature = "redis-cache", not(feature = "memory-cache")))] |
|
pub fn new(redis_cache: RedisCache) -> Self { |
|
Cache::Redis(redis_cache) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(all(feature = "memory-cache", not(feature = "redis-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) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(all(feature = "redis-cache", feature = "memory-cache"))] |
|
pub fn new_hybrid(redis_cache: RedisCache) -> Self { |
|
let cache = MokaCache::builder() |
|
.max_capacity(1000) |
|
.time_to_live(Duration::from_secs(60)) |
|
.build(); |
|
Cache::Hybrid(redis_cache, cache) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn cached_json(&mut self, _url: &str) -> Result<SearchResults, Report<CacheError>> { |
|
match self { |
|
Cache::Disabled => Err(Report::new(CacheError::MissingValue)), |
|
#[cfg(all(feature = "redis-cache", not(feature = "memory-cache")))] |
|
Cache::Redis(redis_cache) => { |
|
let json = redis_cache.cached_json(_url).await?; |
|
Ok(serde_json::from_str::<SearchResults>(&json) |
|
.map_err(|_| CacheError::SerializationError)?) |
|
} |
|
#[cfg(all(feature = "memory-cache", not(feature = "redis-cache")))] |
|
Cache::InMemory(in_memory) => match in_memory.get(&_url.to_string()) { |
|
Some(res) => Ok(res), |
|
None => Err(Report::new(CacheError::MissingValue)), |
|
}, |
|
#[cfg(all(feature = "redis-cache", feature = "memory-cache"))] |
|
Cache::Hybrid(redis_cache, in_memory) => match redis_cache.cached_json(_url).await { |
|
Ok(res) => Ok(serde_json::from_str::<SearchResults>(&res) |
|
.map_err(|_| CacheError::SerializationError)?), |
|
Err(_) => match in_memory.get(&_url.to_string()) { |
|
Some(res) => Ok(res), |
|
None => Err(Report::new(CacheError::MissingValue)), |
|
}, |
|
}, |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn cache_results( |
|
&mut self, |
|
_search_results: &SearchResults, |
|
_url: &str, |
|
) -> Result<(), Report<CacheError>> { |
|
match self { |
|
Cache::Disabled => Ok(()), |
|
#[cfg(all(feature = "redis-cache", not(feature = "memory-cache")))] |
|
Cache::Redis(redis_cache) => { |
|
let json = serde_json::to_string(_search_results) |
|
.map_err(|_| CacheError::SerializationError)?; |
|
redis_cache.cache_results(&json, _url).await |
|
} |
|
#[cfg(all(feature = "memory-cache", not(feature = "redis-cache")))] |
|
Cache::InMemory(cache) => { |
|
cache.insert(_url.to_string(), _search_results.clone()); |
|
Ok(()) |
|
} |
|
#[cfg(all(feature = "memory-cache", feature = "redis-cache"))] |
|
Cache::Hybrid(redis_cache, cache) => { |
|
let json = serde_json::to_string(_search_results) |
|
.map_err(|_| CacheError::SerializationError)?; |
|
match redis_cache.cache_results(&json, _url).await { |
|
Ok(_) => Ok(()), |
|
Err(_) => { |
|
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<CacheError>> { |
|
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<CacheError>> { |
|
let mut mut_cache = self.cache.lock().await; |
|
mut_cache.cache_results(search_results, url).await |
|
} |
|
} |
|
|