use crate::environment::Environment;
use crate::store::CacheStore;
use crate::{MemoryStore, NamespacedStore};
use doido_core::Result;
use serde::Deserialize;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CacheBackend {
#[default]
Memory,
Redis,
Memcache,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct CacheConfig {
#[serde(default, rename = "type")]
pub backend: CacheBackend,
#[serde(default)]
pub endpoint: Option<String>,
#[serde(default)]
pub namespace: Option<String>,
}
impl CacheConfig {
pub async fn build(&self) -> Result<Arc<dyn CacheStore>> {
let base: Arc<dyn CacheStore> = match self.backend {
CacheBackend::Memory => Arc::new(MemoryStore::new()),
CacheBackend::Redis => self.build_redis().await?,
CacheBackend::Memcache => self.build_memcache().await?,
};
Ok(match &self.namespace {
Some(prefix) if !prefix.is_empty() => {
Arc::new(NamespacedStore::new(base, prefix.clone()))
}
_ => base,
})
}
#[cfg(feature = "cache-redis")]
async fn build_redis(&self) -> Result<Arc<dyn CacheStore>> {
let endpoint = self
.endpoint
.clone()
.unwrap_or_else(|| "redis://127.0.0.1:6379".to_string());
Ok(Arc::new(
crate::redis_store::RedisStore::connect(&endpoint).await?,
))
}
#[cfg(not(feature = "cache-redis"))]
async fn build_redis(&self) -> Result<Arc<dyn CacheStore>> {
Err(doido_core::anyhow::anyhow!(
"cache backend 'redis' selected in config but doido-cache was built \
without the `cache-redis` feature"
))
}
#[cfg(feature = "cache-memcache")]
async fn build_memcache(&self) -> Result<Arc<dyn CacheStore>> {
let endpoint = self
.endpoint
.clone()
.unwrap_or_else(|| "memcache://127.0.0.1:11211".to_string());
Ok(Arc::new(
crate::memcache_store::MemcacheStore::connect(endpoint).await?,
))
}
#[cfg(not(feature = "cache-memcache"))]
async fn build_memcache(&self) -> Result<Arc<dyn CacheStore>> {
Err(doido_core::anyhow::anyhow!(
"cache backend 'memcache' selected in config but doido-cache was \
built without the `cache-memcache` feature"
))
}
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct YamlConfig {
#[serde(default)]
pub cache: CacheConfig,
}
impl YamlConfig {
pub fn load() -> std::io::Result<Self> {
Self::load_env(Environment::get_env())
}
pub fn load_env(env: Environment) -> std::io::Result<Self> {
let path = format!("config/{}.yml", env.as_str());
let contents = std::fs::read_to_string(&path)?;
Self::from_yaml(&contents)
}
pub fn from_yaml(yaml: &str) -> std::io::Result<Self> {
serde_norway::from_str(yaml)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
}
}
pub fn load() -> CacheConfig {
YamlConfig::load().map(|c| c.cache).unwrap_or_default()
}