use rat_congestion::{
CongestionController, ControllerConfig, NetworkMetrics, MetricsWindow,
CongestionEvent, PLATFORM
};
use std::time::{Duration, Instant};
use std::collections::VecDeque;
#[derive(Debug)]
struct MockNetworkMetrics {
packets_sent: u64,
packets_acked: u64,
packets_lost: u64,
bytes_sent: u64,
bytes_acked: u64,
bytes_lost: u64,
current_rtt: Duration,
min_rtt: Duration,
bandwidth_estimate: u64,
loss_rate: f64,
bw_ratio: f64,
rtt_cv: f64,
last_update: Instant,
}
impl MockNetworkMetrics {
fn new() -> Self {
let now = Instant::now();
Self {
packets_sent: 0,
packets_acked: 0,
packets_lost: 0,
bytes_sent: 0,
bytes_acked: 0,
bytes_lost: 0,
current_rtt: Duration::from_millis(50),
min_rtt: Duration::from_millis(50),
bandwidth_estimate: 1_000_000, loss_rate: 0.0,
bw_ratio: 1.0,
rtt_cv: 0.1,
last_update: now,
}
}
fn print_stats(&self) {
println!("📊 Network Metrics:");
println!(" Packets: sent={}, acked={}, lost={}",
self.packets_sent, self.packets_acked, self.packets_lost);
println!(" Bytes: sent={}, acked={}, lost={}",
self.bytes_sent, self.bytes_acked, self.bytes_lost);
println!(" RTT: current={:?}, min={:?}", self.current_rtt, self.min_rtt);
println!(" Bandwidth: {} bps ({:.2} Mbps)",
self.bandwidth_estimate, self.bandwidth_estimate as f64 / 1_000_000.0);
println!(" Loss rate: {:.4}%", self.loss_rate * 100.0);
println!(" BW ratio: {:.2}, RTT CV: {:.3}", self.bw_ratio, self.rtt_cv);
}
}
impl NetworkMetrics for MockNetworkMetrics {
fn on_packet_sent(&mut self, bytes: u32) {
self.packets_sent += 1;
self.bytes_sent += bytes as u64;
}
fn on_packet_acked(&mut self, bytes: u32, rtt: Duration) {
self.packets_acked += 1;
self.bytes_acked += bytes as u64;
let alpha = 0.125; let rtt_ms = rtt.as_millis() as f64;
let current_ms = self.current_rtt.as_millis() as f64;
let new_rtt_ms = (1.0 - alpha) * current_ms + alpha * rtt_ms;
self.current_rtt = Duration::from_millis(new_rtt_ms as u64);
if rtt < self.min_rtt {
self.min_rtt = rtt;
}
let elapsed = self.last_update.elapsed();
if elapsed > Duration::from_millis(100) {
let throughput = (bytes as u64 * 8 * 1000) / elapsed.as_millis() as u64;
self.bandwidth_estimate = (self.bandwidth_estimate * 7 + throughput) / 8;
self.last_update = Instant::now();
}
}
fn on_packet_lost(&mut self, bytes: u32) {
self.packets_lost += 1;
self.bytes_lost += bytes as u64;
let total_packets = self.packets_sent;
if total_packets > 0 {
self.loss_rate = self.packets_lost as f64 / total_packets as f64;
}
}
fn rtt(&self) -> Duration { self.current_rtt }
fn min_rtt(&self) -> Duration { self.min_rtt }
fn bandwidth(&self) -> u64 { self.bandwidth_estimate }
fn loss_rate(&self) -> f64 { self.loss_rate }
fn bw_ratio(&self) -> f64 { self.bw_ratio }
fn set_bw_ratio(&mut self, ratio: f64) { self.bw_ratio = ratio; }
fn rtt_cv(&self) -> f64 { self.rtt_cv }
fn set_rtt_cv(&mut self, cv: f64) { self.rtt_cv = cv; }
fn has_variable_rtt(&self) -> bool { self.rtt_cv > 0.2 }
fn has_low_bandwidth_utilization(&self) -> bool { self.bw_ratio < 0.8 }
fn has_high_loss(&self) -> bool { self.loss_rate > 0.01 }
fn update(&mut self, rtt: Duration, loss_rate: f64, throughput: u64, _cwnd: u32) {
self.current_rtt = rtt;
self.loss_rate = loss_rate;
self.bandwidth_estimate = throughput;
}
fn reset(&mut self) {
*self = Self::new();
}
}
#[derive(Debug)]
struct MockMetricsWindow {
samples: VecDeque<(Duration, f64, u64)>, max_size: usize,
}
impl MockMetricsWindow {
fn new(max_size: usize) -> Self {
Self {
samples: VecDeque::with_capacity(max_size),
max_size,
}
}
fn print_stats(&self) {
println!("📈 Metrics Window ({} samples):", self.samples.len());
if !self.samples.is_empty() {
println!(" Avg RTT: {:?}", self.avg_rtt());
println!(" Avg Bandwidth: {} bps ({:.2} Mbps)",
self.avg_bandwidth(), self.avg_bandwidth() as f64 / 1_000_000.0);
println!(" Avg Loss Rate: {:.4}%", self.avg_loss_rate() * 100.0);
if let Some(cv) = self.rtt_coefficient_of_variation() {
println!(" RTT CV: {:.3}", cv);
}
println!(" Network Stable: {}", self.is_stable());
}
}
}
impl MetricsWindow for MockMetricsWindow {
fn add_sample(&mut self, rtt: Duration, loss_rate: f64, bandwidth: u64) {
if self.samples.len() >= self.max_size {
self.samples.pop_front();
}
self.samples.push_back((rtt, loss_rate, bandwidth));
}
fn avg_rtt(&self) -> Duration {
if self.samples.is_empty() {
return Duration::from_millis(50);
}
let sum: u128 = self.samples.iter().map(|(rtt, _, _)| rtt.as_millis()).sum();
Duration::from_millis((sum / self.samples.len() as u128) as u64)
}
fn avg_bandwidth(&self) -> u64 {
if self.samples.is_empty() {
return 1_000_000;
}
self.samples.iter().map(|(_, _, bw)| *bw).sum::<u64>() / self.samples.len() as u64
}
fn avg_loss_rate(&self) -> f64 {
if self.samples.is_empty() {
return 0.0;
}
self.samples.iter().map(|(_, loss, _)| *loss).sum::<f64>() / self.samples.len() as f64
}
fn rtt_coefficient_of_variation(&self) -> Option<f64> {
if self.samples.len() < 2 {
return None;
}
let rtts: Vec<f64> = self.samples.iter()
.map(|(rtt, _, _)| rtt.as_millis() as f64)
.collect();
let mean = rtts.iter().sum::<f64>() / rtts.len() as f64;
let variance = rtts.iter()
.map(|x| (x - mean).powi(2))
.sum::<f64>() / rtts.len() as f64;
let std_dev = variance.sqrt();
Some(std_dev / mean)
}
fn is_stable(&self) -> bool {
if let Some(cv) = self.rtt_coefficient_of_variation() {
cv < 0.2 && self.avg_loss_rate() < 0.005
} else {
true
}
}
fn clear(&mut self) {
self.samples.clear();
}
}
struct NetworkSimulator {
base_rtt: Duration,
base_bandwidth: u64,
packet_size: u32,
time: Instant,
}
impl NetworkSimulator {
fn new() -> Self {
Self {
base_rtt: Duration::from_millis(50),
base_bandwidth: 10_000_000, packet_size: 1460, time: Instant::now(),
}
}
fn simulate_network_event(&mut self, step: usize) -> (Duration, bool) {
let (rtt_variation, loss_probability) = match step {
0..=50 => {
(0.1, 0.001)
},
51..=100 => {
(0.3, 0.01)
},
101..=150 => {
(0.5, 0.03)
},
151..=200 => {
(0.2, 0.005)
},
_ => {
(0.1, 0.001)
}
};
let rtt_factor = 1.0 + (fastrand::f64() - 0.5) * rtt_variation;
let current_rtt = Duration::from_millis(
(self.base_rtt.as_millis() as f64 * rtt_factor) as u64
);
let is_lost = fastrand::f64() < loss_probability;
(current_rtt, is_lost)
}
}
fn main() {
println!("🚀 RAT Congestion Control Library Demo");
println!("=====================================\n");
println!("🖥️ Platform: {}", PLATFORM);
println!();
let metrics = MockNetworkMetrics::new();
let metrics_window = MockMetricsWindow::new(32);
println!("🔧 Creating Controllers...");
let bbr_config = ControllerConfig::builder()
.initial_algorithm("bbr")
.auto_switching(false)
.build();
let mut bbr_controller = CongestionController::with_config(
bbr_config,
MockNetworkMetrics::new(),
MockMetricsWindow::new(32)
);
let cubic_config = ControllerConfig::builder()
.initial_algorithm("cubic")
.auto_switching(false)
.build();
let mut cubic_controller = CongestionController::with_config(
cubic_config,
MockNetworkMetrics::new(),
MockMetricsWindow::new(32)
);
let mut adaptive_controller = CongestionController::adaptive(
MockNetworkMetrics::new(),
MockMetricsWindow::new(32)
);
println!("✅ Controllers created:");
println!(" - BBR Controller (algorithm: {})", bbr_controller.current_algorithm());
println!(" - CUBIC Controller (algorithm: {})", cubic_controller.current_algorithm());
println!(" - Adaptive Controller (algorithm: {})", adaptive_controller.current_algorithm());
println!();
let mut simulator = NetworkSimulator::new();
println!("🌐 Starting Network Simulation...");
println!("==================================\n");
for step in 0..250 {
let (rtt, is_lost) = simulator.simulate_network_event(step);
let packet_size = simulator.packet_size;
if is_lost {
bbr_controller.on_packet_lost(packet_size as u64);
cubic_controller.on_packet_lost(packet_size as u64);
adaptive_controller.on_packet_lost(packet_size as u64);
} else {
bbr_controller.on_packet_acked(packet_size as u64, rtt);
cubic_controller.on_packet_acked(packet_size as u64, rtt);
adaptive_controller.on_packet_acked(packet_size as u64, rtt);
}
if step % 50 == 0 {
println!("📊 Step {}: Network Conditions", step);
println!(" RTT: {:?}, Packet Lost: {}", rtt, is_lost);
println!();
println!("🔵 BBR Controller Status:");
println!(" Algorithm: {}", bbr_controller.current_algorithm());
println!(" Window Size: {} bytes ({:.1} KB)",
bbr_controller.window_size(),
bbr_controller.window_size() as f64 / 1024.0);
println!(" Pacing Rate: {} bps ({:.2} Mbps)",
bbr_controller.pacing_rate(),
bbr_controller.pacing_rate() as f64 / 1_000_000.0);
println!(" SSThresh: {}", bbr_controller.slow_start_threshold());
println!(" Can Send 10KB: {}", bbr_controller.can_send(10240));
println!();
println!("🟠 CUBIC Controller Status:");
println!(" Algorithm: {}", cubic_controller.current_algorithm());
println!(" Window Size: {} bytes ({:.1} KB)",
cubic_controller.window_size(),
cubic_controller.window_size() as f64 / 1024.0);
println!(" Pacing Rate: {} bps ({:.2} Mbps)",
cubic_controller.pacing_rate(),
cubic_controller.pacing_rate() as f64 / 1_000_000.0);
println!(" SSThresh: {}", cubic_controller.slow_start_threshold());
println!(" Can Send 10KB: {}", cubic_controller.can_send(10240));
println!();
println!("🟢 Adaptive Controller Status:");
println!(" Algorithm: {}", adaptive_controller.current_algorithm());
println!(" Window Size: {} bytes ({:.1} KB)",
adaptive_controller.window_size(),
adaptive_controller.window_size() as f64 / 1024.0);
println!(" Pacing Rate: {} bps ({:.2} Mbps)",
adaptive_controller.pacing_rate(),
adaptive_controller.pacing_rate() as f64 / 1_000_000.0);
println!(" SSThresh: {}", adaptive_controller.slow_start_threshold());
println!(" Can Send 10KB: {}", adaptive_controller.can_send(10240));
println!();
println!("{}", "=".repeat(60));
println!();
}
if step % 10 == 0 && step % 50 != 0 {
println!("Step {}: BBR={:.1}KB, CUBIC={:.1}KB, Adaptive={:.1}KB ({})",
step,
bbr_controller.window_size() as f64 / 1024.0,
cubic_controller.window_size() as f64 / 1024.0,
adaptive_controller.window_size() as f64 / 1024.0,
adaptive_controller.current_algorithm());
}
}
println!();
println!("🏁 Simulation Complete!");
println!("======================\n");
println!("📈 Final Performance Comparison:");
println!("BBR Controller:");
println!(" Final Window: {:.1} KB", bbr_controller.window_size() as f64 / 1024.0);
println!(" Final Pacing Rate: {:.2} Mbps", bbr_controller.pacing_rate() as f64 / 1_000_000.0);
println!();
println!("CUBIC Controller:");
println!(" Final Window: {:.1} KB", cubic_controller.window_size() as f64 / 1024.0);
println!(" Final Pacing Rate: {:.2} Mbps", cubic_controller.pacing_rate() as f64 / 1_000_000.0);
println!();
println!("Adaptive Controller:");
println!(" Final Algorithm: {}", adaptive_controller.current_algorithm());
println!(" Final Window: {:.1} KB", adaptive_controller.window_size() as f64 / 1024.0);
println!(" Final Pacing Rate: {:.2} Mbps", adaptive_controller.pacing_rate() as f64 / 1_000_000.0);
println!();
println!("🔄 Demonstrating Batch Processing:");
let ack_batch = vec![
(1460, Duration::from_millis(45)),
(1460, Duration::from_millis(47)),
(1460, Duration::from_millis(52)),
(1460, Duration::from_millis(49)),
(1460, Duration::from_millis(51)),
];
println!("Processing batch of {} ACKs...", ack_batch.len());
adaptive_controller.process_ack_batch(&ack_batch);
println!("✅ Batch processed. New window size: {:.1} KB",
adaptive_controller.window_size() as f64 / 1024.0);
println!();
println!("🔀 Demonstrating Manual Algorithm Switching:");
let current = adaptive_controller.current_algorithm();
let target = if current == "BBR" { "cubic" } else { "bbr" };
println!("Switching from {} to {}...", current, target);
adaptive_controller.switch_algorithm(target);
println!("✅ Switched to: {}", adaptive_controller.current_algorithm());
println!();
println!("🖥️ Platform Information:");
println!("Platform: {}", adaptive_controller.platform());
println!();
println!("🎉 Demo completed successfully!");
println!("This example showed:");
println!(" ✓ Different controller configurations");
println!(" ✓ Network simulation with varying conditions");
println!(" ✓ Real-time performance monitoring");
println!(" ✓ Algorithm comparison");
println!(" ✓ Batch processing capabilities");
println!(" ✓ Dynamic algorithm switching");
}