flags_rs/
cache.rs

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)), // Initialize directly
40        };
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}