use crate::error::AmberError;
use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Feature {
V8Optimization,
PythonRuntime,
GoRuntime,
RustNative,
WebAssembly,
IOSRuntime,
AndroidRuntime,
KubernetesIntegration,
ServiceMesh,
SecurityManager,
ComplianceManager,
EdgeComputing,
OfflineMode,
DistributedCoordination,
PerformanceOptimizer,
NetworkOptimizer,
}
impl fmt::Display for Feature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Feature::V8Optimization => write!(f, "V8 Optimization"),
Feature::PythonRuntime => write!(f, "Python Runtime"),
Feature::GoRuntime => write!(f, "Go Runtime"),
Feature::RustNative => write!(f, "Rust Native"),
Feature::WebAssembly => write!(f, "WebAssembly"),
Feature::IOSRuntime => write!(f, "iOS Runtime"),
Feature::AndroidRuntime => write!(f, "Android Runtime"),
Feature::KubernetesIntegration => write!(f, "Kubernetes Integration"),
Feature::ServiceMesh => write!(f, "Service Mesh"),
Feature::SecurityManager => write!(f, "Security Manager"),
Feature::ComplianceManager => write!(f, "Compliance Manager"),
Feature::EdgeComputing => write!(f, "Edge Computing"),
Feature::OfflineMode => write!(f, "Offline Mode"),
Feature::DistributedCoordination => write!(f, "Distributed Coordination"),
Feature::PerformanceOptimizer => write!(f, "Performance Optimizer"),
Feature::NetworkOptimizer => write!(f, "Network Optimizer"),
}
}
}
#[derive(Debug, Clone)]
pub enum FallbackStrategy {
DisableFeature,
UseAlternative(String),
RetryLater(Duration),
Ignore,
DegradeToBasic,
SwitchToBackup(String),
LogAndContinue,
}
#[derive(Debug, Clone)]
pub struct FallbackEvent {
pub feature: Feature,
pub strategy: FallbackStrategy,
pub timestamp: Instant,
pub error: Option<AmberError>,
pub recovery_time: Option<Duration>,
}
#[derive(Debug, Clone, Default)]
pub struct FallbackStats {
pub total_fallbacks: u64,
pub successful_recoveries: u64,
pub failed_recoveries: u64,
pub feature_fallback_counts: HashMap<Feature, u64>,
pub strategy_usage_counts: HashMap<String, u64>,
pub avg_recovery_time: Duration,
pub last_fallback_time: Option<Instant>,
}
impl FallbackStats {
pub fn success_rate(&self) -> f64 {
if self.total_fallbacks == 0 {
0.0
} else {
self.successful_recoveries as f64 / self.total_fallbacks as f64
}
}
}
pub struct FallbackManager {
strategies: Arc<RwLock<HashMap<Feature, Vec<FallbackStrategy>>>>,
stats: Arc<RwLock<FallbackStats>>,
event_history: Arc<RwLock<Vec<FallbackEvent>>>,
active_features: Arc<RwLock<HashMap<Feature, bool>>>,
}
impl FallbackManager {
pub fn new() -> Self {
let mut active_features = HashMap::new();
active_features.insert(Feature::V8Optimization, true);
active_features.insert(Feature::PythonRuntime, true);
active_features.insert(Feature::GoRuntime, true);
active_features.insert(Feature::RustNative, true);
active_features.insert(Feature::WebAssembly, true);
Self {
strategies: Arc::new(RwLock::new(HashMap::new())),
stats: Arc::new(RwLock::new(FallbackStats::default())),
event_history: Arc::new(RwLock::new(Vec::new())),
active_features: Arc::new(RwLock::new(active_features)),
}
}
pub async fn register_strategy(&mut self, feature: Feature, strategy: FallbackStrategy) {
let mut strategies = self.strategies.write().await;
strategies
.entry(feature)
.or_insert_with(Vec::new)
.push(strategy);
}
pub async fn register_strategies(&mut self, strategies: Vec<(Feature, FallbackStrategy)>) {
let mut strategies_map = self.strategies.write().await;
for (feature, strategy) in strategies {
strategies_map
.entry(feature)
.or_insert_with(Vec::new)
.push(strategy);
}
}
pub async fn handle_feature_failure(&self, feature: Feature) -> Result<String, AmberError> {
let start_time: _ = Instant::now();
{
let mut stats = self.stats.write().await;
stats.total_fallbacks += 1;
stats
.feature_fallback_counts
.entry(feature.clone())
.and_modify(|count| *count += 1)
.or_insert(1);
stats.last_fallback_time = Some(Instant::now());
}
let strategies: _ = self.strategies.read().await;
let feature_strategies: _ = strategies.get(&feature);
if let Some(strategies_list) = feature_strategies {
for strategy in strategies_list {
match self.apply_strategy(feature.clone(), strategy.clone()).await {
Ok(message) => {
let duration: _ = start_time.elapsed();
self.record_success(feature.clone(), strategy.clone(), duration)
.await;
self.record_event(FallbackEvent {
feature: feature.clone(),
strategy: strategy.clone(),
timestamp: Instant::now(),
error: None,
recovery_time: Some(duration),
})
.await;
return Ok(message);
}
Err(_) => {
continue;
}
}
}
}
let duration: _ = start_time.elapsed();
self.record_failure(feature.clone(), duration).await;
Err(AmberError::RuntimeError(format!(
"All fallback strategies failed for feature: {}",
feature
)))
}
async fn apply_strategy(
&self,
feature: Feature,
strategy: FallbackStrategy,
) -> Result<String, AmberError> {
match strategy {
FallbackStrategy::DisableFeature => {
{
let mut active_features = self.active_features.write().await;
active_features.insert(feature.clone(), false);
}
Ok(format!("Feature {} disabled", feature))
}
FallbackStrategy::UseAlternative(alternative) => {
Ok(format!("Using alternative: {}", alternative))
}
FallbackStrategy::RetryLater(delay) => {
tokio::time::sleep(delay).await;
Ok(format!("Retried after {:?}", delay))
}
FallbackStrategy::Ignore => {
Ok("Error ignored, continuing execution".to_string())
}
FallbackStrategy::DegradeToBasic => {
Ok("Degraded to basic mode".to_string())
}
FallbackStrategy::SwitchToBackup(backup) => {
Ok(format!("Switched to backup: {}", backup))
}
FallbackStrategy::LogAndContinue => {
Ok("Error logged, continuing execution".to_string())
}
}
}
async fn record_success(
&self,
_feature: Feature,
strategy: FallbackStrategy,
recovery_time: Duration,
) {
{
let mut stats = self.stats.write().await;
stats.successful_recoveries += 1;
stats.avg_recovery_time = Duration::from_nanos(
(stats.avg_recovery_time.as_nanos() as u64 + recovery_time.as_nanos() as u64) / 2,
);
let strategy_name: _ = format!("{:?}", strategy);
stats
.strategy_usage_counts
.entry(strategy_name)
.and_modify(|count| *count += 1)
.or_insert(1);
}
}
async fn record_failure(&self, _feature: Feature, _duration: Duration) {
let mut stats = self.stats.write().await;
stats.failed_recoveries += 1;
}
async fn record_event(&self, event: FallbackEvent) {
let mut event_history = self.event_history.write().await;
event_history.push(event);
if event_history.len() > 1000 {
event_history.remove(0);
}
}
pub async fn is_feature_active(&self, feature: &Feature) -> bool {
let active_features: _ = self.active_features.read().await;
active_features.get(feature).copied().unwrap_or(false)
}
pub async fn enable_feature(&self, feature: Feature) {
let mut active_features = self.active_features.write().await;
active_features.insert(feature, true);
}
pub async fn disable_feature(&self, feature: Feature) {
let mut active_features = self.active_features.write().await;
active_features.insert(feature, false);
}
pub async fn get_stats(&self) -> FallbackStats {
self.stats.read().await.clone()
}
pub async fn get_event_history(&self) -> Vec<FallbackEvent> {
self.event_history.read().await.clone()
}
pub async fn get_strategies(&self, feature: &Feature) -> Option<Vec<FallbackStrategy>> {
let strategies: _ = self.strategies.read().await;
strategies.get(feature).cloned()
}
pub async fn reset_stats(&self) {
*self.stats.write().await = FallbackStats::default();
self.event_history.write().await.clear();
}
pub async fn get_fallback_rate(&self) -> f64 {
let stats: _ = self.stats.read().await;
if stats.total_fallbacks == 0 {
0.0
} else {
stats.total_fallbacks as f64
/ (stats.successful_recoveries + stats.failed_recoveries) as f64
}
}
pub async fn cleanup_retry_strategies(&self) {
let mut strategies = self.strategies.write().await;
for (_, strategy_list) in strategies.iter_mut() {
strategy_list.retain(|strategy| !matches!(strategy, FallbackStrategy::RetryLater(_)));
}
}
}
impl Default for FallbackManager {
fn default() -> Self {
Self::new()
}
}