1use std::collections::HashMap;
2use std::sync::Mutex;
3
4use async_trait::async_trait;
5use chrono::{DateTime, Utc};
6use tokio::sync::RwLock;
7use crate::flag::FeatureFlag;
8
9#[async_trait]
10pub trait Cache {
11 async fn get(&self, name: &str) -> Result<(bool, bool), Box<dyn std::error::Error + Send + Sync>>;
12 async fn get_all(&self) -> Result<Vec<FeatureFlag>, Box<dyn std::error::Error + Send + Sync>>;
13 async fn refresh(&mut self, flags: &[FeatureFlag], interval_allowed: i32) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
14 async fn should_refresh_cache(&self) -> bool;
15 async fn init(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
16}
17
18pub struct CacheSystem {
19 cache: Box<dyn Cache + Send + Sync>,
20}
21
22impl CacheSystem {
23 pub fn new(cache: Box<dyn Cache + Send + Sync>) -> Self {
24 Self { cache }
25 }
26}
27
28pub struct MemoryCache {
29 flags: RwLock<HashMap<String, FeatureFlag>>,
30 cache_ttl: i64,
31 next_refresh: RwLock<DateTime<Utc>>,
32}
33
34impl MemoryCache {
35 pub fn new() -> Self {
36 let cache = Self {
37 flags: RwLock::new(HashMap::new()),
38 cache_ttl: 60,
39 next_refresh: RwLock::new(Utc::now() - chrono::Duration::seconds(90)), };
41
42 cache
43 }
44}
45
46
47#[async_trait]
48impl Cache for MemoryCache {
49 async fn get(&self, name: &str) -> Result<(bool, bool), Box<dyn std::error::Error + Send + Sync>> {
50 let flags = self.flags.read().await;
51 if let Some(flag) = flags.get(name) {
52 Ok((flag.enabled, true))
53 } else {
54 Ok((false, false))
55 }
56 }
57
58 async fn get_all(&self) -> Result<Vec<FeatureFlag>, Box<dyn std::error::Error + Send + Sync>> {
59 let flags = self.flags.read().await;
60 let all_flags: Vec<FeatureFlag> = flags.values().cloned().collect();
61 Ok(all_flags)
62 }
63
64 async fn refresh(&mut self, flags: &[FeatureFlag], interval_allowed: i32) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
65 let mut flag_map = self.flags.write().await;
66 flag_map.clear();
67
68 for flag in flags {
69 flag_map.insert(flag.details.name.clone(), flag.clone());
70 }
71
72 self.cache_ttl = interval_allowed as i64;
73 let mut next_refresh = self.next_refresh.write().await;
74 *next_refresh = Utc::now() + chrono::Duration::seconds(self.cache_ttl);
75
76 Ok(())
77 }
78
79 async fn should_refresh_cache(&self) -> bool {
80 let next_refresh = self.next_refresh.read().await;
81 Utc::now() > *next_refresh
82 }
83
84 async fn init(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
85 self.cache_ttl = 60;
86 let mut next_refresh = self.next_refresh.write().await;
87 *next_refresh = Utc::now() - chrono::Duration::seconds(90);
88 Ok(())
89 }
90}