flags_rs/
cache.rs

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