Skip to main content

ferrox_feature_flags/
lib.rs

1//! # Ferrox Feature Flags (`ferrox-feature-flags`)
2//!
3//! `ferrox-feature-flags` provides feature toggle evaluation for enabling or disabling features dynamically in production without redeploying code.
4
5use redis::AsyncCommands;
6use ferrox_errors::AppError;
7
8#[derive(Clone)]
9pub struct FeatureFlagsClient {
10    redis_client: redis::Client,
11}
12
13impl FeatureFlagsClient {
14    pub fn new(redis_url: &str) -> Result<Self, AppError> {
15        let redis_client = redis::Client::open(redis_url)
16            .map_err(|e| AppError::InternalServerError(Box::new(e)))?;
17        Ok(Self { redis_client })
18    }
19
20    /// Checks if a feature flag is globally enabled
21    pub async fn is_enabled(&self, feature_name: &str) -> Result<bool, AppError> {
22        let mut con = self.redis_client.get_multiplexed_async_connection().await
23            .map_err(|e| AppError::InternalServerError(Box::new(e)))?;
24
25        let key = format!("feature_flag:{}", feature_name);
26        
27        let is_enabled: Option<bool> = con.get(&key)
28            .await
29            .map_err(|e| AppError::InternalServerError(Box::new(e)))?;
30
31        Ok(is_enabled.unwrap_or(false))
32    }
33
34    /// Enables or disables a feature flag globally
35    pub async fn set_flag(&self, feature_name: &str, enabled: bool) -> Result<(), AppError> {
36        let mut con = self.redis_client.get_multiplexed_async_connection().await
37            .map_err(|e| AppError::InternalServerError(Box::new(e)))?;
38
39        let key = format!("feature_flag:{}", feature_name);
40        
41        con.set::<_, _, ()>(&key, enabled)
42            .await
43            .map_err(|e| AppError::InternalServerError(Box::new(e)))?;
44
45        Ok(())
46    }
47}