use crate::{
AutoTuner, AutoTunerConfig, ComponentHealth, ComponentType, ConcurrentPeerManager,
ConcurrentWantList, DiagnosticConfig, DiagnosticEngine, DiagnosticReport, HealthMonitor,
HealthMonitorConfig, NetworkMetrics, PeerScoringConfig, StatsCollector, WantListConfig,
};
use std::sync::{Arc, RwLock};
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TransportPreset {
LowLatency,
HighThroughput,
Balanced,
EdgeDevice,
FederatedLearning,
}
#[derive(Debug, Clone)]
pub struct TransportFacadeConfig {
pub want_list_config: WantListConfig,
pub peer_scoring_config: PeerScoringConfig,
pub enable_monitoring: bool,
pub monitor_config: Option<HealthMonitorConfig>,
pub enable_diagnostics: bool,
pub diagnostic_config: Option<DiagnosticConfig>,
pub enable_auto_tuning: bool,
pub auto_tuner_config: Option<AutoTunerConfig>,
pub enable_stats: bool,
pub max_stats_history: usize,
}
impl Default for TransportFacadeConfig {
fn default() -> Self {
Self::from_preset(TransportPreset::Balanced)
}
}
impl TransportFacadeConfig {
pub fn from_preset(preset: TransportPreset) -> Self {
let (want_list_config, peer_scoring_config) = match preset {
TransportPreset::LowLatency => (
WantListConfig {
max_wants: 1000,
default_timeout: Duration::from_secs(30),
max_retries: 3,
base_retry_delay: Duration::from_millis(10),
max_retry_delay: Duration::from_secs(5),
},
PeerScoringConfig {
latency_weight: 0.6,
bandwidth_weight: 0.2,
reliability_weight: 0.2,
ewma_alpha: 0.3,
inactivity_decay: 0.05,
min_score: 0.1,
max_failures: 3,
},
),
TransportPreset::HighThroughput => (
WantListConfig {
max_wants: 10000,
default_timeout: Duration::from_secs(120),
max_retries: 5,
base_retry_delay: Duration::from_millis(50),
max_retry_delay: Duration::from_secs(10),
},
PeerScoringConfig {
latency_weight: 0.2,
bandwidth_weight: 0.6,
reliability_weight: 0.2,
ewma_alpha: 0.2,
inactivity_decay: 0.01,
min_score: 0.05,
max_failures: 5,
},
),
TransportPreset::Balanced => (
WantListConfig {
max_wants: 5000,
default_timeout: Duration::from_secs(60),
max_retries: 3,
base_retry_delay: Duration::from_millis(100),
max_retry_delay: Duration::from_secs(5),
},
PeerScoringConfig {
latency_weight: 0.4,
bandwidth_weight: 0.4,
reliability_weight: 0.2,
ewma_alpha: 0.2,
inactivity_decay: 0.01,
min_score: 0.1,
max_failures: 5,
},
),
TransportPreset::EdgeDevice => (
WantListConfig {
max_wants: 500,
default_timeout: Duration::from_secs(90),
max_retries: 5,
base_retry_delay: Duration::from_millis(200),
max_retry_delay: Duration::from_secs(10),
},
PeerScoringConfig {
latency_weight: 0.3,
bandwidth_weight: 0.4,
reliability_weight: 0.3,
ewma_alpha: 0.1,
inactivity_decay: 0.005,
min_score: 0.2,
max_failures: 7,
},
),
TransportPreset::FederatedLearning => (
WantListConfig {
max_wants: 2000,
default_timeout: Duration::from_secs(180),
max_retries: 7,
base_retry_delay: Duration::from_millis(500),
max_retry_delay: Duration::from_secs(30),
},
PeerScoringConfig {
latency_weight: 0.3,
bandwidth_weight: 0.3,
reliability_weight: 0.4,
ewma_alpha: 0.15,
inactivity_decay: 0.002,
min_score: 0.3,
max_failures: 10,
},
),
};
Self {
want_list_config,
peer_scoring_config,
enable_monitoring: true,
monitor_config: Some(HealthMonitorConfig::default()),
enable_diagnostics: true,
diagnostic_config: Some(DiagnosticConfig::default()),
enable_auto_tuning: true,
auto_tuner_config: Some(AutoTunerConfig::default()),
enable_stats: true,
max_stats_history: 1000,
}
}
}
pub struct TransportFacadeBuilder {
config: TransportFacadeConfig,
}
impl TransportFacadeBuilder {
pub fn new() -> Self {
Self {
config: TransportFacadeConfig::default(),
}
}
pub fn from_preset(preset: TransportPreset) -> Self {
Self {
config: TransportFacadeConfig::from_preset(preset),
}
}
pub fn want_list_config(mut self, config: WantListConfig) -> Self {
self.config.want_list_config = config;
self
}
pub fn peer_scoring_config(mut self, config: PeerScoringConfig) -> Self {
self.config.peer_scoring_config = config;
self
}
pub fn with_monitoring(mut self) -> Self {
self.config.enable_monitoring = true;
if self.config.monitor_config.is_none() {
self.config.monitor_config = Some(HealthMonitorConfig::default());
}
self
}
pub fn with_monitoring_config(mut self, config: HealthMonitorConfig) -> Self {
self.config.enable_monitoring = true;
self.config.monitor_config = Some(config);
self
}
pub fn with_diagnostics(mut self) -> Self {
self.config.enable_diagnostics = true;
if self.config.diagnostic_config.is_none() {
self.config.diagnostic_config = Some(DiagnosticConfig::default());
}
self
}
pub fn with_diagnostics_config(mut self, config: DiagnosticConfig) -> Self {
self.config.enable_diagnostics = true;
self.config.diagnostic_config = Some(config);
self
}
pub fn with_auto_tuning(mut self) -> Self {
self.config.enable_auto_tuning = true;
if self.config.auto_tuner_config.is_none() {
self.config.auto_tuner_config = Some(AutoTunerConfig::default());
}
self
}
pub fn with_auto_tuning_config(mut self, config: AutoTunerConfig) -> Self {
self.config.enable_auto_tuning = true;
self.config.auto_tuner_config = Some(config);
self
}
pub fn with_stats(mut self, max_history: usize) -> Self {
self.config.enable_stats = true;
self.config.max_stats_history = max_history;
self
}
pub fn without_monitoring(mut self) -> Self {
self.config.enable_monitoring = false;
self
}
pub fn without_diagnostics(mut self) -> Self {
self.config.enable_diagnostics = false;
self
}
pub fn without_auto_tuning(mut self) -> Self {
self.config.enable_auto_tuning = false;
self
}
pub fn build(self) -> TransportFacade {
TransportFacade::new(self.config)
}
}
impl Default for TransportFacadeBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct TransportFacade {
want_list: ConcurrentWantList,
peer_manager: ConcurrentPeerManager,
health_monitor: Option<Arc<HealthMonitor>>,
diagnostic_engine: Option<DiagnosticEngine>,
auto_tuner: Option<Arc<RwLock<AutoTuner>>>,
stats_collector: Option<Arc<RwLock<StatsCollector>>>,
config: TransportFacadeConfig,
}
impl TransportFacade {
pub fn new(config: TransportFacadeConfig) -> Self {
let want_list = ConcurrentWantList::new(config.want_list_config.clone());
let peer_manager = ConcurrentPeerManager::new(config.peer_scoring_config.clone());
let health_monitor = if config.enable_monitoring {
let monitor = HealthMonitor::new(config.monitor_config.clone().unwrap_or_default());
monitor.register_component(ComponentType::WantList, 100);
monitor.register_component(ComponentType::PeerManager, 100);
Some(Arc::new(monitor))
} else {
None
};
let diagnostic_engine = if config.enable_diagnostics {
Some(DiagnosticEngine::with_config(
config.diagnostic_config.clone().unwrap_or_default(),
))
} else {
None
};
let auto_tuner = if config.enable_auto_tuning {
Some(Arc::new(RwLock::new(AutoTuner::with_config(
config.auto_tuner_config.clone().unwrap_or_default(),
))))
} else {
None
};
let stats_collector = if config.enable_stats {
Some(Arc::new(RwLock::new(StatsCollector::new(
config.max_stats_history,
))))
} else {
None
};
Self {
want_list,
peer_manager,
health_monitor,
diagnostic_engine,
auto_tuner,
stats_collector,
config,
}
}
pub fn builder() -> TransportFacadeBuilder {
TransportFacadeBuilder::new()
}
pub fn want_list(&self) -> &ConcurrentWantList {
&self.want_list
}
pub fn peer_manager(&self) -> &ConcurrentPeerManager {
&self.peer_manager
}
pub fn overall_health(&self) -> ComponentHealth {
self.health_monitor
.as_ref()
.map(|m| m.overall_health())
.unwrap_or(ComponentHealth::Unknown)
}
pub fn component_health(&self, component: ComponentType) -> ComponentHealth {
self.health_monitor
.as_ref()
.map(|m| m.get_health(component))
.unwrap_or(ComponentHealth::Unknown)
}
pub fn run_diagnostics(&self) -> Option<DiagnosticReport> {
self.diagnostic_engine
.as_ref()
.map(|engine| engine.generate_report(&self.want_list, &self.peer_manager, &[]))
}
pub fn update_network_metrics(&self, metrics: NetworkMetrics) -> bool {
if let Some(tuner) = &self.auto_tuner {
let mut tuner = tuner.write().unwrap_or_else(|e| e.into_inner());
tuner.update_metrics(metrics)
} else {
false
}
}
pub fn get_tuning_recommendations(&self) -> Option<Vec<String>> {
self.auto_tuner.as_ref().map(|tuner| {
let tuner = tuner.read().unwrap_or_else(|e| e.into_inner());
tuner.get_recommendations()
})
}
pub fn record_stats(&self) {
if let Some(collector) = &self.stats_collector {
let aggregated = crate::AggregatedStatsBuilder::new()
.peer_stats(self.peer_manager.stats())
.build();
let mut collector = collector.write().unwrap_or_else(|e| e.into_inner());
collector.record(aggregated);
}
}
pub fn latest_stats(&self) -> Option<crate::AggregatedStats> {
self.stats_collector.as_ref().and_then(|collector| {
let collector = collector.read().unwrap_or_else(|e| e.into_inner());
collector.latest().cloned()
})
}
pub fn avg_throughput(&self) -> u64 {
self.stats_collector
.as_ref()
.map(|collector| {
let collector = collector.read().unwrap_or_else(|e| e.into_inner());
collector.avg_throughput()
})
.unwrap_or(0)
}
pub fn health_monitor(&self) -> Option<Arc<HealthMonitor>> {
self.health_monitor.clone()
}
pub fn auto_tuner(&self) -> Option<Arc<RwLock<AutoTuner>>> {
self.auto_tuner.clone()
}
pub fn stats_collector(&self) -> Option<Arc<RwLock<StatsCollector>>> {
self.stats_collector.clone()
}
pub fn config(&self) -> &TransportFacadeConfig {
&self.config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_default() {
let facade = TransportFacade::builder().build();
assert!(matches!(
facade.overall_health(),
ComponentHealth::Healthy | ComponentHealth::Unknown
));
}
#[test]
fn test_builder_with_monitoring() {
let facade = TransportFacade::builder().with_monitoring().build();
assert!(facade.health_monitor.is_some());
assert_ne!(facade.overall_health(), ComponentHealth::Unknown);
}
#[test]
fn test_builder_with_diagnostics() {
let facade = TransportFacade::builder().with_diagnostics().build();
assert!(facade.diagnostic_engine.is_some());
let report = facade.run_diagnostics();
assert!(report.is_some());
}
#[test]
fn test_builder_with_auto_tuning() {
let facade = TransportFacade::builder().with_auto_tuning().build();
assert!(facade.auto_tuner.is_some());
let recommendations = facade.get_tuning_recommendations();
assert!(recommendations.is_some());
}
#[test]
fn test_builder_with_stats() {
let facade = TransportFacade::builder().with_stats(100).build();
assert!(facade.stats_collector.is_some());
facade.record_stats();
assert!(facade.latest_stats().is_some());
}
#[test]
fn test_builder_without_monitoring() {
let facade = TransportFacade::builder().without_monitoring().build();
assert!(facade.health_monitor.is_none());
assert_eq!(facade.overall_health(), ComponentHealth::Unknown);
}
#[test]
fn test_preset_low_latency() {
let facade = TransportFacadeBuilder::from_preset(TransportPreset::LowLatency).build();
assert_eq!(facade.config.want_list_config.max_wants, 1000);
assert_eq!(facade.config.peer_scoring_config.latency_weight, 0.6);
}
#[test]
fn test_preset_high_throughput() {
let facade = TransportFacadeBuilder::from_preset(TransportPreset::HighThroughput).build();
assert_eq!(facade.config.want_list_config.max_wants, 10000);
assert_eq!(facade.config.peer_scoring_config.bandwidth_weight, 0.6);
}
#[test]
fn test_preset_edge_device() {
let facade = TransportFacadeBuilder::from_preset(TransportPreset::EdgeDevice).build();
assert_eq!(facade.config.want_list_config.max_wants, 500);
assert_eq!(facade.config.peer_scoring_config.max_failures, 7);
}
#[test]
fn test_update_network_metrics() {
let facade = TransportFacade::builder().with_auto_tuning().build();
let metrics = NetworkMetrics {
avg_latency: Duration::from_millis(100),
latency_stddev: Duration::from_millis(10),
avg_bandwidth: 1_000_000,
packet_loss_rate: 0.01,
success_rate: 0.95,
active_peers: 5,
};
facade.update_network_metrics(metrics);
let recommendations = facade.get_tuning_recommendations();
assert!(recommendations.is_some());
assert!(!recommendations
.expect("test: tuning recommendations should be present after metrics update")
.is_empty());
}
#[test]
fn test_record_and_get_stats() {
let facade = TransportFacade::builder().with_stats(100).build();
facade.record_stats();
facade.record_stats();
let stats = facade.latest_stats();
assert!(stats.is_some());
let avg = facade.avg_throughput();
assert_eq!(avg, 0); }
#[test]
fn test_all_features_enabled() {
let facade = TransportFacade::builder()
.with_monitoring()
.with_diagnostics()
.with_auto_tuning()
.with_stats(100)
.build();
assert!(facade.health_monitor.is_some());
assert!(facade.diagnostic_engine.is_some());
assert!(facade.auto_tuner.is_some());
assert!(facade.stats_collector.is_some());
facade.record_stats();
let _health = facade.overall_health();
let _report = facade.run_diagnostics();
let _recommendations = facade.get_tuning_recommendations();
}
}