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)), };
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}