karbon_framework/feature/
feature_flags.rs1use std::collections::HashMap;
2use std::sync::Arc;
3use tokio::sync::RwLock;
4use serde::{Serialize, Deserialize};
5use chrono::{DateTime, Utc};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct FeatureFlag {
10 pub name: String,
11 pub enabled: bool,
12 pub description: String,
13 pub updated_at: DateTime<Utc>,
14}
15
16#[derive(Clone)]
34pub struct FeatureFlags {
35 store: Arc<RwLock<HashMap<String, FeatureFlag>>>,
36}
37
38impl FeatureFlags {
39 pub fn new() -> Self {
40 Self {
41 store: Arc::new(RwLock::new(HashMap::new())),
42 }
43 }
44
45 pub async fn register(&self, name: &str, enabled: bool, description: &str) {
47 self.store.write().await.insert(name.to_string(), FeatureFlag {
48 name: name.to_string(),
49 enabled,
50 description: description.to_string(),
51 updated_at: Utc::now(),
52 });
53 }
54
55 pub async fn is_enabled(&self, name: &str) -> bool {
57 self.store.read().await
58 .get(name)
59 .is_some_and(|f| f.enabled)
60 }
61
62 pub async fn enable(&self, name: &str) -> bool {
64 self.set(name, true).await
65 }
66
67 pub async fn disable(&self, name: &str) -> bool {
69 self.set(name, false).await
70 }
71
72 pub async fn toggle(&self, name: &str) -> Option<bool> {
74 let mut store = self.store.write().await;
75 if let Some(flag) = store.get_mut(name) {
76 flag.enabled = !flag.enabled;
77 flag.updated_at = Utc::now();
78 Some(flag.enabled)
79 } else {
80 None
81 }
82 }
83
84 pub async fn set(&self, name: &str, enabled: bool) -> bool {
86 let mut store = self.store.write().await;
87 if let Some(flag) = store.get_mut(name) {
88 flag.enabled = enabled;
89 flag.updated_at = Utc::now();
90 true
91 } else {
92 false
93 }
94 }
95
96 pub async fn get(&self, name: &str) -> Option<FeatureFlag> {
98 self.store.read().await.get(name).cloned()
99 }
100
101 pub async fn list(&self) -> Vec<FeatureFlag> {
103 self.store.read().await.values().cloned().collect()
104 }
105
106 pub async fn remove(&self, name: &str) -> bool {
108 self.store.write().await.remove(name).is_some()
109 }
110
111 pub async fn register_many(&self, flags: &[(&str, bool, &str)]) {
113 let mut store = self.store.write().await;
114 for (name, enabled, description) in flags {
115 store.insert(name.to_string(), FeatureFlag {
116 name: name.to_string(),
117 enabled: *enabled,
118 description: description.to_string(),
119 updated_at: Utc::now(),
120 });
121 }
122 }
123}
124
125impl Default for FeatureFlags {
126 fn default() -> Self {
127 Self::new()
128 }
129}