Really-amin's picture
Upload 317 files
eebf5c4 verified
"""
Feature Flags System
Allows dynamic toggling of application modules and features
"""
from typing import Dict, Any
import json
from pathlib import Path
from datetime import datetime
import logging
logger = logging.getLogger(__name__)
class FeatureFlagManager:
"""Manage application feature flags"""
DEFAULT_FLAGS = {
"enableWhaleTracking": True,
"enableMarketOverview": True,
"enableFearGreedIndex": True,
"enableNewsFeed": True,
"enableSentimentAnalysis": True,
"enableMlPredictions": False, # Disabled by default (requires HF setup)
"enableProxyAutoMode": True,
"enableDefiProtocols": True,
"enableTrendingCoins": True,
"enableGlobalStats": True,
"enableProviderRotation": True,
"enableWebSocketStreaming": True,
"enableDatabaseLogging": True,
"enableRealTimeAlerts": False, # New feature - not yet implemented
"enableAdvancedCharts": True,
"enableExportFeatures": True,
"enableCustomProviders": True,
"enablePoolManagement": True,
"enableHFIntegration": True,
}
def __init__(self, storage_path: str = "data/feature_flags.json"):
"""
Initialize feature flag manager
Args:
storage_path: Path to persist feature flags
"""
self.storage_path = Path(storage_path)
self.flags = self.DEFAULT_FLAGS.copy()
self.load_flags()
def load_flags(self):
"""Load feature flags from storage"""
try:
if self.storage_path.exists():
with open(self.storage_path, 'r', encoding='utf-8') as f:
saved_flags = json.load(f)
# Merge saved flags with defaults (in case new flags were added)
self.flags.update(saved_flags.get('flags', {}))
logger.info(f"Loaded feature flags from {self.storage_path}")
else:
# Create storage directory if it doesn't exist
self.storage_path.parent.mkdir(parents=True, exist_ok=True)
self.save_flags()
logger.info("Initialized default feature flags")
except Exception as e:
logger.error(f"Error loading feature flags: {e}")
self.flags = self.DEFAULT_FLAGS.copy()
def save_flags(self):
"""Save feature flags to storage"""
try:
self.storage_path.parent.mkdir(parents=True, exist_ok=True)
data = {
'flags': self.flags,
'last_updated': datetime.now().isoformat()
}
with open(self.storage_path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2)
logger.info("Feature flags saved successfully")
except Exception as e:
logger.error(f"Error saving feature flags: {e}")
def get_all_flags(self) -> Dict[str, bool]:
"""Get all feature flags"""
return self.flags.copy()
def get_flag(self, flag_name: str) -> bool:
"""
Get a specific feature flag value
Args:
flag_name: Name of the flag
Returns:
bool: Flag value (defaults to False if not found)
"""
return self.flags.get(flag_name, False)
def set_flag(self, flag_name: str, value: bool) -> bool:
"""
Set a feature flag value
Args:
flag_name: Name of the flag
value: New value (True/False)
Returns:
bool: Success status
"""
try:
self.flags[flag_name] = bool(value)
self.save_flags()
logger.info(f"Feature flag '{flag_name}' set to {value}")
return True
except Exception as e:
logger.error(f"Error setting feature flag: {e}")
return False
def update_flags(self, updates: Dict[str, bool]) -> bool:
"""
Update multiple flags at once
Args:
updates: Dictionary of flag name -> value pairs
Returns:
bool: Success status
"""
try:
for flag_name, value in updates.items():
self.flags[flag_name] = bool(value)
self.save_flags()
logger.info(f"Updated {len(updates)} feature flags")
return True
except Exception as e:
logger.error(f"Error updating feature flags: {e}")
return False
def reset_to_defaults(self) -> bool:
"""Reset all flags to default values"""
try:
self.flags = self.DEFAULT_FLAGS.copy()
self.save_flags()
logger.info("Feature flags reset to defaults")
return True
except Exception as e:
logger.error(f"Error resetting feature flags: {e}")
return False
def is_enabled(self, flag_name: str) -> bool:
"""
Check if a feature is enabled (alias for get_flag)
Args:
flag_name: Name of the flag
Returns:
bool: True if enabled, False otherwise
"""
return self.get_flag(flag_name)
def get_enabled_features(self) -> Dict[str, bool]:
"""Get only enabled features"""
return {k: v for k, v in self.flags.items() if v is True}
def get_disabled_features(self) -> Dict[str, bool]:
"""Get only disabled features"""
return {k: v for k, v in self.flags.items() if v is False}
def get_flag_count(self) -> Dict[str, int]:
"""Get count of enabled/disabled flags"""
enabled = sum(1 for v in self.flags.values() if v)
disabled = len(self.flags) - enabled
return {
'total': len(self.flags),
'enabled': enabled,
'disabled': disabled
}
def get_feature_info(self) -> Dict[str, Any]:
"""Get comprehensive feature flag information"""
counts = self.get_flag_count()
return {
'flags': self.flags,
'counts': counts,
'enabled_features': list(self.get_enabled_features().keys()),
'disabled_features': list(self.get_disabled_features().keys()),
'storage_path': str(self.storage_path),
'last_loaded': datetime.now().isoformat()
}
# Global instance
feature_flags = FeatureFlagManager()
# Convenience functions
def is_feature_enabled(flag_name: str) -> bool:
"""Check if a feature is enabled"""
return feature_flags.is_enabled(flag_name)
def get_all_feature_flags() -> Dict[str, bool]:
"""Get all feature flags"""
return feature_flags.get_all_flags()
def set_feature_flag(flag_name: str, value: bool) -> bool:
"""Set a feature flag"""
return feature_flags.set_flag(flag_name, value)
def update_feature_flags(updates: Dict[str, bool]) -> bool:
"""Update multiple feature flags"""
return feature_flags.update_flags(updates)