pub mod config;
pub mod memory;
pub mod redis;
pub mod store;
pub use config::{CacheConfig, CacheConfigBuilder};
pub use memory::InMemoryCache;
pub use redis::RedisCache;
pub use store::CacheStore;
use crate::config::Config;
use crate::container::App;
use crate::error::FrameworkError;
use serde::{de::DeserializeOwned, Serialize};
use std::sync::Arc;
use std::time::Duration;
pub struct Cache;
impl Cache {
pub(crate) async fn bootstrap() {
let config = Config::get::<CacheConfig>().unwrap_or_default();
match RedisCache::connect(&config).await {
Ok(redis_cache) => {
App::bind::<dyn CacheStore>(Arc::new(redis_cache));
}
Err(_) => {
let memory_cache = InMemoryCache::with_prefix(&config.prefix);
App::bind::<dyn CacheStore>(Arc::new(memory_cache));
}
}
}
pub fn store() -> Result<Arc<dyn CacheStore>, FrameworkError> {
App::resolve_make::<dyn CacheStore>()
}
pub fn is_initialized() -> bool {
App::has_binding::<dyn CacheStore>()
}
pub async fn get<T: DeserializeOwned>(key: &str) -> Result<Option<T>, FrameworkError> {
let store = Self::store()?;
match store.get_raw(key).await? {
Some(json) => {
let value = serde_json::from_str(&json).map_err(|e| {
FrameworkError::internal(format!("Cache deserialize error: {e}"))
})?;
Ok(Some(value))
}
None => Ok(None),
}
}
pub async fn put<T: Serialize>(
key: &str,
value: &T,
ttl: Option<Duration>,
) -> Result<(), FrameworkError> {
let store = Self::store()?;
let json = serde_json::to_string(value)
.map_err(|e| FrameworkError::internal(format!("Cache serialize error: {e}")))?;
store.put_raw(key, &json, ttl).await
}
pub async fn forever<T: Serialize>(key: &str, value: &T) -> Result<(), FrameworkError> {
Self::put(key, value, None).await
}
pub async fn has(key: &str) -> Result<bool, FrameworkError> {
let store = Self::store()?;
store.has(key).await
}
pub async fn forget(key: &str) -> Result<bool, FrameworkError> {
let store = Self::store()?;
store.forget(key).await
}
pub async fn flush() -> Result<(), FrameworkError> {
let store = Self::store()?;
store.flush().await
}
pub async fn increment(key: &str, amount: i64) -> Result<i64, FrameworkError> {
let store = Self::store()?;
store.increment(key, amount).await
}
pub async fn decrement(key: &str, amount: i64) -> Result<i64, FrameworkError> {
let store = Self::store()?;
store.decrement(key, amount).await
}
pub async fn expire(key: &str, ttl: Duration) -> Result<bool, FrameworkError> {
let store = Self::store()?;
store.expire(key, ttl).await
}
pub async fn remember<T, F, Fut>(
key: &str,
ttl: Option<Duration>,
default: F,
) -> Result<T, FrameworkError>
where
T: Serialize + DeserializeOwned,
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<T, FrameworkError>>,
{
if let Some(cached) = Self::get::<T>(key).await? {
return Ok(cached);
}
let value = default().await?;
Self::put(key, &value, ttl).await?;
Ok(value)
}
pub async fn remember_forever<T, F, Fut>(key: &str, default: F) -> Result<T, FrameworkError>
where
T: Serialize + DeserializeOwned,
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<T, FrameworkError>>,
{
Self::remember(key, None, default).await
}
}