1use crate::environment::Environment;
11use crate::store::CacheStore;
12use crate::{MemoryStore, NamespacedStore};
13use doido_core::Result;
14use serde::Deserialize;
15use std::sync::Arc;
16
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
19#[serde(rename_all = "snake_case")]
20pub enum CacheBackend {
21 #[default]
23 Memory,
24 Redis,
26 Memcache,
28}
29
30#[derive(Debug, Clone, Default, Deserialize)]
39pub struct CacheConfig {
40 #[serde(default, rename = "type")]
42 pub backend: CacheBackend,
43 #[serde(default)]
46 pub endpoint: Option<String>,
47 #[serde(default)]
49 pub namespace: Option<String>,
50}
51
52impl CacheConfig {
53 pub async fn build(&self) -> Result<Arc<dyn CacheStore>> {
57 let base: Arc<dyn CacheStore> = match self.backend {
58 CacheBackend::Memory => Arc::new(MemoryStore::new()),
59 CacheBackend::Redis => self.build_redis().await?,
60 CacheBackend::Memcache => self.build_memcache().await?,
61 };
62 Ok(match &self.namespace {
63 Some(prefix) if !prefix.is_empty() => {
64 Arc::new(NamespacedStore::new(base, prefix.clone()))
65 }
66 _ => base,
67 })
68 }
69
70 #[cfg(feature = "cache-redis")]
71 async fn build_redis(&self) -> Result<Arc<dyn CacheStore>> {
72 let endpoint = self
73 .endpoint
74 .clone()
75 .unwrap_or_else(|| "redis://127.0.0.1:6379".to_string());
76 Ok(Arc::new(
77 crate::redis_store::RedisStore::connect(&endpoint).await?,
78 ))
79 }
80
81 #[cfg(not(feature = "cache-redis"))]
82 async fn build_redis(&self) -> Result<Arc<dyn CacheStore>> {
83 Err(doido_core::anyhow::anyhow!(
84 "cache backend 'redis' selected in config but doido-cache was built \
85 without the `cache-redis` feature"
86 ))
87 }
88
89 #[cfg(feature = "cache-memcache")]
90 async fn build_memcache(&self) -> Result<Arc<dyn CacheStore>> {
91 let endpoint = self
92 .endpoint
93 .clone()
94 .unwrap_or_else(|| "memcache://127.0.0.1:11211".to_string());
95 Ok(Arc::new(
96 crate::memcache_store::MemcacheStore::connect(endpoint).await?,
97 ))
98 }
99
100 #[cfg(not(feature = "cache-memcache"))]
101 async fn build_memcache(&self) -> Result<Arc<dyn CacheStore>> {
102 Err(doido_core::anyhow::anyhow!(
103 "cache backend 'memcache' selected in config but doido-cache was \
104 built without the `cache-memcache` feature"
105 ))
106 }
107}
108
109#[derive(Debug, Clone, Default, Deserialize)]
112pub struct YamlConfig {
113 #[serde(default)]
114 pub cache: CacheConfig,
115}
116
117impl YamlConfig {
118 pub fn load() -> std::io::Result<Self> {
120 Self::load_env(Environment::get_env())
121 }
122
123 pub fn load_env(env: Environment) -> std::io::Result<Self> {
125 let path = format!("config/{}.yml", env.as_str());
126 let contents = std::fs::read_to_string(&path)?;
127 Self::from_yaml(&contents)
128 }
129
130 pub fn from_yaml(yaml: &str) -> std::io::Result<Self> {
132 serde_norway::from_str(yaml)
133 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
134 }
135}
136
137pub fn load() -> CacheConfig {
140 YamlConfig::load().map(|c| c.cache).unwrap_or_default()
141}