static_gen.rs
1 //! Static traffic generator with fixed jitter range 2 //! 3 //! This is the default, zero-dependency generator that provides 4 //! basic traffic obfuscation through random jitter. 5 6 use crate::traits::TrafficGenerator; 7 use rand::Rng; 8 use std::time::Duration; 9 10 /// Static generator configuration 11 #[derive(Debug, Clone)] 12 pub struct StaticConfig { 13 /// Minimum delay in milliseconds 14 pub min_delay_ms: u32, 15 /// Maximum delay in milliseconds 16 pub max_delay_ms: u32, 17 /// Preferred size bucket (0-5) 18 pub preferred_bucket: usize, 19 } 20 21 impl Default for StaticConfig { 22 fn default() -> Self { 23 Self { 24 min_delay_ms: 50, 25 max_delay_ms: 500, 26 preferred_bucket: 2, // 1024 bytes 27 } 28 } 29 } 30 31 /// Simple generator with fixed random jitter 32 /// 33 /// Uses uniform distribution within configured range. 34 /// No learning, no adaptation, minimal overhead. 35 #[derive(Debug, Clone)] 36 pub struct StaticGenerator { 37 config: StaticConfig, 38 } 39 40 impl Default for StaticGenerator { 41 fn default() -> Self { 42 Self::new(StaticConfig::default()) 43 } 44 } 45 46 impl StaticGenerator { 47 /// Create with custom configuration 48 pub fn new(config: StaticConfig) -> Self { 49 Self { config } 50 } 51 52 /// Create with specified jitter range 53 pub fn with_jitter(min_ms: u32, max_ms: u32) -> Self { 54 Self::new(StaticConfig { 55 min_delay_ms: min_ms, 56 max_delay_ms: max_ms, 57 ..Default::default() 58 }) 59 } 60 } 61 62 impl TrafficGenerator for StaticGenerator { 63 fn next_delay(&mut self) -> Duration { 64 let mut rng = rand::thread_rng(); 65 let ms = rng.gen_range(self.config.min_delay_ms..=self.config.max_delay_ms); 66 Duration::from_millis(ms as u64) 67 } 68 69 fn next_size_bucket(&mut self) -> usize { 70 let mut rng = rand::thread_rng(); 71 // Slight variation around preferred bucket 72 let offset: i32 = rng.gen_range(-1..=1); 73 let bucket = (self.config.preferred_bucket as i32 + offset).clamp(0, 5); 74 bucket as usize 75 } 76 77 fn name(&self) -> &'static str { 78 "static" 79 } 80 } 81 82 #[cfg(test)] 83 mod tests { 84 use super::*; 85 86 #[test] 87 fn test_delay_in_range() { 88 let mut generator = StaticGenerator::default(); 89 for _ in 0..100 { 90 let delay = generator.next_delay(); 91 assert!(delay >= Duration::from_millis(50)); 92 assert!(delay <= Duration::from_millis(500)); 93 } 94 } 95 96 #[test] 97 fn test_size_bucket_valid() { 98 let mut generator = StaticGenerator::default(); 99 for _ in 0..100 { 100 let bucket = generator.next_size_bucket(); 101 assert!(bucket <= 5); 102 } 103 } 104 105 #[test] 106 fn test_custom_jitter() { 107 let mut generator = StaticGenerator::with_jitter(10, 20); 108 for _ in 0..100 { 109 let delay = generator.next_delay(); 110 assert!(delay >= Duration::from_millis(10)); 111 assert!(delay <= Duration::from_millis(20)); 112 } 113 } 114 }