rat_congestion 0.1.0

High-performance congestion control algorithms for network protocols
Documentation
//! Unified congestion control API with automatic platform optimization.
//!
//! This module provides a simplified, unified interface that automatically
//! detects the platform and configures optimal settings without requiring
//! the user to make platform-specific choices.

use crate::algorithms::{CongestionControlAlgorithm, Bbr, Cubic};
use crate::constants::perf;
use crate::events::CongestionEvent;
use crate::manager::{CongestionManager, CongestionConfig, AlgorithmType};
// Metrics will be provided by external implementations
use crate::platform;
use std::time::Duration;

/// Configuration builder for the congestion controller.
#[derive(Debug, Clone)]
pub struct ControllerConfigBuilder {
    initial_algorithm: Option<String>,
    auto_switching: Option<bool>,
    platform_optimized: Option<bool>,
    metrics_window_size: Option<usize>,
    switch_cooldown: Option<Duration>,
}

impl ControllerConfigBuilder {
    /// Create a new configuration builder.
    pub fn new() -> Self {
        Self {
            initial_algorithm: None,
            auto_switching: None,
            platform_optimized: None,
            metrics_window_size: None,
            switch_cooldown: None,
        }
    }
    
    /// Set the initial algorithm ("bbr", "cubic", or "auto").
    pub fn initial_algorithm<S: Into<String>>(mut self, algorithm: S) -> Self {
        self.initial_algorithm = Some(algorithm.into());
        self
    }
    
    /// Enable or disable automatic algorithm switching.
    pub fn auto_switching(mut self, enabled: bool) -> Self {
        self.auto_switching = Some(enabled);
        self
    }
    
    /// Enable or disable platform-specific optimizations.
    pub fn platform_optimized(mut self, enabled: bool) -> Self {
        self.platform_optimized = Some(enabled);
        self
    }
    
    /// Set the metrics window size for analysis.
    pub fn metrics_window_size(mut self, size: usize) -> Self {
        self.metrics_window_size = Some(size);
        self
    }
    
    /// Set the cooldown period between algorithm switches.
    pub fn switch_cooldown(mut self, duration: Duration) -> Self {
        self.switch_cooldown = Some(duration);
        self
    }
    
    /// Build the configuration with platform-optimized defaults.
    pub fn build(self) -> ControllerConfig {
        ControllerConfig {
            initial_algorithm: self.initial_algorithm.unwrap_or_else(|| {
                // Auto-select based on platform
                match platform::detection::PLATFORM {
                    "linux" => "bbr".to_string(),
                    "freebsd" => "cubic".to_string(),
                    "macos" => "cubic".to_string(),
                    "windows" => "cubic".to_string(),
                    _ => "auto".to_string(),
                }
            }),
            auto_switching: self.auto_switching.unwrap_or(true),
            platform_optimized: self.platform_optimized.unwrap_or(true),
            metrics_window_size: self.metrics_window_size.unwrap_or_else(|| {
                // Platform-optimized window size
                match platform::detection::PLATFORM {
                    "linux" => 64,
                    "freebsd" => 32,
                    "macos" => 32,
                    "windows" => 16,
                    _ => 32,
                }
            }),
            switch_cooldown: self.switch_cooldown.unwrap_or(perf::SWITCH_COOLDOWN),
        }
    }
}

impl Default for ControllerConfigBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Configuration for the congestion controller.
#[derive(Debug, Clone)]
pub struct ControllerConfig {
    /// Initial algorithm to use
    pub initial_algorithm: String,
    /// Enable automatic algorithm switching
    pub auto_switching: bool,
    /// Enable platform-specific optimizations
    pub platform_optimized: bool,
    /// Metrics window size for analysis
    pub metrics_window_size: usize,
    /// Cooldown period between algorithm switches
    pub switch_cooldown: Duration,
}

impl ControllerConfig {
    /// Create a new configuration builder.
    pub fn builder() -> ControllerConfigBuilder {
        ControllerConfigBuilder::new()
    }
    
    /// Create a configuration with platform-optimized defaults.
    pub fn platform_optimized() -> Self {
        Self::builder().build()
    }
    
    /// Create a configuration optimized for high-performance scenarios.
    pub fn high_performance() -> Self {
        Self::builder()
            .initial_algorithm("bbr")
            .auto_switching(true)
            .platform_optimized(true)
            .metrics_window_size(128)
            .switch_cooldown(Duration::from_secs(1))
            .build()
    }
    
    /// Create a configuration optimized for stable networks.
    pub fn stable_network() -> Self {
        Self::builder()
            .initial_algorithm("cubic")
            .auto_switching(false)
            .platform_optimized(true)
            .metrics_window_size(32)
            .build()
    }
    
    /// Create a configuration for variable network conditions.
    pub fn adaptive() -> Self {
        Self::builder()
            .initial_algorithm("auto")
            .auto_switching(true)
            .platform_optimized(true)
            .switch_cooldown(Duration::from_millis(500))
            .build()
    }
}

impl Default for ControllerConfig {
    fn default() -> Self {
        Self::platform_optimized()
    }
}

/// Unified congestion control interface with automatic platform optimization.
///
/// This is the main entry point for the library, providing a simplified API
/// that automatically detects the platform and applies optimal configurations.
pub struct CongestionController<M: crate::manager::NetworkMetrics, W: crate::manager::MetricsWindow> {
    /// Internal congestion manager
    manager: CongestionManager<M, W>,
    /// Configuration
    config: ControllerConfig,
    /// Packet sequence counter
    packet_sequence: u64,
}

impl<M: crate::manager::NetworkMetrics, W: crate::manager::MetricsWindow> CongestionController<M, W> {
    /// Create a new congestion controller with platform-optimized defaults.
    ///
    /// This automatically detects the current platform and selects the most
    /// appropriate algorithm and settings.
    pub fn new(metrics: M, metrics_window: W) -> Self {
        Self::with_config(ControllerConfig::default(), metrics, metrics_window)
    }
    
    /// Create a congestion controller with custom configuration.
    pub fn with_config(config: ControllerConfig, metrics: M, metrics_window: W) -> Self {
        let algorithm: Box<dyn CongestionControlAlgorithm> = match config.initial_algorithm.as_str() {
            "bbr" => Box::new(Bbr::new()),
            "cubic" => Box::new(Cubic::new()),
            "auto" => {
                // Auto-select based on platform capabilities
                if platform::detection::has_advanced_networking() {
                    Box::new(Bbr::new())
                } else {
                    Box::new(Cubic::new())
                }
            },
            _ => {
                // Default to platform recommendation
                match platform::network::recommended_tcp_algorithm() {
                    "bbr" => Box::new(Bbr::new()),
                    _ => Box::new(Cubic::new()),
                }
            }
        };
        
        let manager_config = CongestionConfig {
            auto_switch: config.auto_switching,
            switch_cooldown: config.switch_cooldown,
            metrics_window_size: config.metrics_window_size,
            platform_optimized: config.platform_optimized,
        };
        
        let manager = CongestionManager::with_config(algorithm, manager_config, metrics, metrics_window);
        
        Self {
            manager,
            config,
            packet_sequence: 0,
        }
    }
    
    /// Create a controller optimized for high-performance scenarios.
    pub fn high_performance(metrics: M, metrics_window: W) -> Self {
        Self::with_config(ControllerConfig::high_performance(), metrics, metrics_window)
    }
    
    /// Create a controller optimized for stable networks.
    pub fn stable_network(metrics: M, metrics_window: W) -> Self {
        Self::with_config(ControllerConfig::stable_network(), metrics, metrics_window)
    }
    
    /// Create a controller for adaptive network conditions.
    pub fn adaptive(metrics: M, metrics_window: W) -> Self {
        Self::with_config(ControllerConfig::adaptive(), metrics, metrics_window)
    }
    
    /// Process a packet acknowledgment.
    ///
    /// # Arguments
    /// * `bytes` - Number of bytes acknowledged
    /// * `rtt` - Round-trip time for this packet
    #[inline(always)]
    pub fn on_packet_acked(&mut self, bytes: u64, rtt: Duration) {
        self.packet_sequence += 1;
        self.manager.on_congestion_event(CongestionEvent::PacketAcked {
            packet_number: self.packet_sequence,
            bytes,
            rtt,
        });
    }
    
    /// Process a packet loss.
    ///
    /// # Arguments
    /// * `bytes` - Number of bytes lost
    #[inline(always)]
    pub fn on_packet_lost(&mut self, bytes: u64) {
        self.packet_sequence += 1;
        self.manager.on_congestion_event(CongestionEvent::PacketLost {
            packet_number: self.packet_sequence,
            bytes,
        });
    }
    
    /// Process an explicit congestion notification.
    #[inline(always)]
    pub fn on_congestion_notification(&mut self) {
        self.manager.on_congestion_event(CongestionEvent::ExplicitCongestionNotification);
    }
    
    /// Process multiple acknowledgments in batch for better performance.
    ///
    /// # Arguments
    /// * `acks` - Vector of (bytes, rtt) tuples
    pub fn process_ack_batch(&mut self, acks: &[(u64, Duration)]) {
        let batch: Vec<(u64, u64, Duration)> = acks.iter()
            .map(|&(bytes, rtt)| {
                self.packet_sequence += 1;
                (self.packet_sequence, bytes, rtt)
            })
            .collect();
        
        self.manager.process_ack_batch(&batch);
    }
    
    /// Check if more data can be sent.
    ///
    /// # Arguments
    /// * `bytes_in_flight` - Number of bytes currently in flight
    ///
    /// # Returns
    /// `true` if more data can be sent, `false` otherwise
    #[inline(always)]
    pub fn can_send(&self, bytes_in_flight: u64) -> bool {
        self.manager.can_send(bytes_in_flight)
    }
    
    /// Get the current congestion window size in bytes.
    #[inline(always)]
    pub fn window_size(&self) -> u64 {
        self.manager.congestion_window()
    }
    
    /// Get the current pacing rate in bytes per second.
    #[inline(always)]
    pub fn pacing_rate(&self) -> u64 {
        self.manager.pacing_rate()
    }
    
    /// Get the current slow start threshold.
    #[inline(always)]
    pub fn slow_start_threshold(&self) -> u64 {
        self.manager.ssthresh()
    }
    
    /// Get the name of the currently active algorithm.
    pub fn current_algorithm(&self) -> &'static str {
        self.manager.algorithm_name()
    }
    
    /// Get current network metrics.
    pub fn network_metrics(&self) -> &M {
        self.manager.network_metrics()
    }
    
    /// Get the detected platform.
    pub fn platform(&self) -> &'static str {
        platform::detection::PLATFORM
    }
    
    /// Check if platform-specific optimizations are enabled.
    pub fn platform_optimizations_enabled(&self) -> bool {
        self.config.platform_optimized
    }
    
    /// Manually switch to a specific algorithm.
    ///
    /// # Arguments
    /// * `algorithm` - Algorithm name ("bbr", "cubic")
    pub fn switch_algorithm(&mut self, algorithm: &str) {
        let algorithm_type = match algorithm {
            "bbr" => AlgorithmType::Bbr,
            "cubic" => AlgorithmType::Cubic,
            _ => return, // Invalid algorithm, ignore
        };
        
        self.manager.switch_to(algorithm_type);
    }
    
    /// Reset all statistics and metrics.
    pub fn reset(&mut self) {
        self.manager.reset_statistics();
        self.packet_sequence = 0;
    }
    
    /// Get the current configuration.
    pub fn config(&self) -> &ControllerConfig {
        &self.config
    }
    
    /// Update the configuration (some changes require restart).
    pub fn update_config(&mut self, config: ControllerConfig) {
        // Update manager configuration
        let manager_config = CongestionConfig {
            auto_switch: config.auto_switching,
            switch_cooldown: config.switch_cooldown,
            metrics_window_size: config.metrics_window_size,
            platform_optimized: config.platform_optimized,
        };
        
        self.manager.set_config(manager_config);
        self.config = config;
    }
}

// Default implementation removed because CongestionController now requires
// external metrics and metrics_window parameters