pjson_rs/application/services/
optimization_service.rs

1//! Service responsible for use case optimization strategies
2//!
3//! This service focuses on applying different optimization strategies
4//! based on specific streaming use cases and requirements.
5
6use crate::{application::ApplicationResult, domain::value_objects::Priority};
7
8/// Service for optimization strategies and use case handling
9#[derive(Debug)]
10pub struct OptimizationService {
11    default_strategy: OptimizationStrategy,
12    custom_strategies: std::collections::HashMap<String, OptimizationStrategy>,
13}
14
15/// Supported streaming use cases
16#[derive(Debug, Clone, PartialEq)]
17pub enum StreamingUseCase {
18    /// Real-time dashboard updates requiring low latency
19    RealTimeDashboard,
20    /// Bulk data transfer prioritizing throughput
21    BulkDataTransfer,
22    /// Mobile application with network constraints
23    MobileApp,
24    /// Progressive web application balancing UX and performance
25    ProgressiveWebApp,
26    /// IoT device streaming with power constraints
27    IoTDevice,
28    /// Live streaming with audience interaction
29    LiveStreaming,
30    /// Custom use case with specific requirements
31    Custom(String),
32}
33
34/// Optimization strategy configuration
35#[derive(Debug, Clone)]
36pub struct OptimizationStrategy {
37    pub priority_threshold: Priority,
38    pub max_frame_size: usize,
39    pub batch_size: usize,
40    pub compression_enabled: bool,
41    pub adaptive_quality: bool,
42    pub description: String,
43    pub target_latency_ms: f64,
44    pub target_throughput_mbps: f64,
45}
46
47/// Result of use case optimization
48#[derive(Debug, Clone)]
49pub struct UseCaseOptimizationResult {
50    pub use_case: StreamingUseCase,
51    pub strategy_applied: OptimizationStrategy,
52    pub frames_generated: Vec<crate::domain::entities::Frame>,
53    pub optimization_metrics: OptimizationMetrics,
54}
55
56/// Metrics about the optimization performance
57#[derive(Debug, Clone)]
58pub struct OptimizationMetrics {
59    pub efficiency_score: f64,
60    pub latency_improvement: f64,
61    pub throughput_improvement: f64,
62    pub resource_utilization: f64,
63    pub quality_score: f64,
64}
65
66impl OptimizationService {
67    pub fn new() -> Self {
68        Self {
69            default_strategy: Self::create_balanced_strategy(),
70            custom_strategies: std::collections::HashMap::new(),
71        }
72    }
73
74    /// Get optimization strategy for a specific use case
75    pub fn get_strategy_for_use_case(
76        &self,
77        use_case: &StreamingUseCase,
78    ) -> ApplicationResult<OptimizationStrategy> {
79        match use_case {
80            StreamingUseCase::RealTimeDashboard => Ok(Self::create_realtime_dashboard_strategy()),
81            StreamingUseCase::BulkDataTransfer => Ok(Self::create_bulk_transfer_strategy()),
82            StreamingUseCase::MobileApp => Ok(Self::create_mobile_app_strategy()),
83            StreamingUseCase::ProgressiveWebApp => Ok(Self::create_pwa_strategy()),
84            StreamingUseCase::IoTDevice => Ok(Self::create_iot_device_strategy()),
85            StreamingUseCase::LiveStreaming => Ok(Self::create_live_streaming_strategy()),
86            StreamingUseCase::Custom(name) => {
87                self.custom_strategies.get(name).cloned().ok_or_else(|| {
88                    crate::application::ApplicationError::Logic(format!(
89                        "Custom strategy '{name}' not found"
90                    ))
91                })
92            }
93        }
94    }
95
96    /// Register a custom optimization strategy
97    pub fn register_custom_strategy(
98        &mut self,
99        name: String,
100        strategy: OptimizationStrategy,
101    ) -> ApplicationResult<()> {
102        self.custom_strategies.insert(name, strategy);
103        Ok(())
104    }
105
106    /// Optimize strategy based on performance context
107    pub fn optimize_strategy_for_context(
108        &self,
109        base_strategy: OptimizationStrategy,
110        context: &crate::application::services::prioritization_service::PerformanceContext,
111    ) -> ApplicationResult<OptimizationStrategy> {
112        let mut optimized = base_strategy;
113
114        // Adjust priority threshold based on performance
115        if context.error_rate > 0.05 {
116            optimized.priority_threshold = optimized.priority_threshold.increase_by(20);
117        } else if context.error_rate < 0.01 && context.average_latency_ms < 100.0 {
118            optimized.priority_threshold = optimized.priority_threshold.decrease_by(10);
119        }
120
121        // Adjust batch size based on latency and bandwidth
122        if context.average_latency_ms > 1000.0 {
123            optimized.batch_size = (optimized.batch_size as f64 * 0.7) as usize;
124        } else if context.average_latency_ms < 100.0 && context.available_bandwidth_mbps > 10.0 {
125            optimized.batch_size = (optimized.batch_size as f64 * 1.3) as usize;
126        }
127
128        // Adjust frame size based on bandwidth
129        if context.available_bandwidth_mbps < 2.0 {
130            optimized.max_frame_size = (optimized.max_frame_size as f64 * 0.8) as usize;
131        } else if context.available_bandwidth_mbps > 20.0 {
132            optimized.max_frame_size = (optimized.max_frame_size as f64 * 1.2) as usize;
133        }
134
135        // Enable compression for low bandwidth
136        if context.available_bandwidth_mbps < 5.0 {
137            optimized.compression_enabled = true;
138        }
139
140        // Adjust adaptive quality based on CPU usage
141        if context.cpu_usage > 0.8 {
142            optimized.adaptive_quality = false; // Disable to reduce CPU load
143        }
144
145        Ok(optimized)
146    }
147
148    /// Calculate optimization metrics for a given strategy and results
149    pub fn calculate_optimization_metrics(
150        &self,
151        strategy: &OptimizationStrategy,
152        frames: &[crate::domain::entities::Frame],
153        context: &crate::application::services::prioritization_service::PerformanceContext,
154    ) -> ApplicationResult<OptimizationMetrics> {
155        // Calculate efficiency score based on frame priority distribution
156        let efficiency_score = self.calculate_efficiency_score(frames, strategy);
157
158        // Estimate latency improvement
159        let latency_improvement = self.estimate_latency_improvement(strategy, context);
160
161        // Estimate throughput improvement
162        let throughput_improvement = self.estimate_throughput_improvement(strategy, context);
163
164        // Calculate resource utilization score
165        let resource_utilization = self.calculate_resource_utilization(strategy, context);
166
167        // Calculate quality score based on frame completeness
168        let quality_score = self.calculate_quality_score(frames, strategy);
169
170        Ok(OptimizationMetrics {
171            efficiency_score,
172            latency_improvement,
173            throughput_improvement,
174            resource_utilization,
175            quality_score,
176        })
177    }
178
179    /// Recommend strategy adjustments based on analysis
180    pub fn recommend_strategy_adjustments(
181        &self,
182        current_strategy: &OptimizationStrategy,
183        performance_report: &crate::application::services::performance_analysis_service::PerformanceAnalysisReport,
184    ) -> ApplicationResult<Vec<StrategyAdjustmentRecommendation>> {
185        let mut recommendations = Vec::new();
186
187        // Analyze latency performance
188        if performance_report.latency_analysis.average > current_strategy.target_latency_ms * 1.5 {
189            recommendations.push(StrategyAdjustmentRecommendation {
190                adjustment_type: AdjustmentType::PriorityIncrease,
191                description: "Increase priority threshold to reduce latency".to_string(),
192                expected_impact: "Reduce latency by 20-40%".to_string(),
193                confidence: 0.8,
194                urgency: AdjustmentUrgency::High,
195            });
196        }
197
198        // Analyze throughput performance
199        if performance_report.throughput_analysis.average_mbps
200            < current_strategy.target_throughput_mbps * 0.7
201        {
202            recommendations.push(StrategyAdjustmentRecommendation {
203                adjustment_type: AdjustmentType::BatchSizeIncrease,
204                description: "Increase batch size to improve throughput".to_string(),
205                expected_impact: "Improve throughput by 15-30%".to_string(),
206                confidence: 0.7,
207                urgency: AdjustmentUrgency::Medium,
208            });
209        }
210
211        // Analyze error rate
212        if performance_report.error_analysis.error_rate > 0.05 {
213            recommendations.push(StrategyAdjustmentRecommendation {
214                adjustment_type: AdjustmentType::QualityReduction,
215                description: "Enable adaptive quality to reduce errors".to_string(),
216                expected_impact: "Reduce error rate by 30-50%".to_string(),
217                confidence: 0.9,
218                urgency: AdjustmentUrgency::High,
219            });
220        }
221
222        // Analyze resource usage
223        if performance_report.resource_analysis.current_cpu_usage > 0.8 {
224            recommendations.push(StrategyAdjustmentRecommendation {
225                adjustment_type: AdjustmentType::CompressionDisable,
226                description: "Disable compression to reduce CPU load".to_string(),
227                expected_impact: "Reduce CPU usage by 10-20%".to_string(),
228                confidence: 0.8,
229                urgency: AdjustmentUrgency::Medium,
230            });
231        }
232
233        Ok(recommendations)
234    }
235
236    // Private implementation methods for creating specific strategies
237
238    fn create_realtime_dashboard_strategy() -> OptimizationStrategy {
239        OptimizationStrategy {
240            priority_threshold: Priority::HIGH,
241            max_frame_size: 16 * 1024, // 16KB for low latency
242            batch_size: 5,
243            compression_enabled: false, // Avoid compression latency
244            adaptive_quality: true,
245            description: "Optimized for real-time dashboard updates with minimal latency"
246                .to_string(),
247            target_latency_ms: 100.0,
248            target_throughput_mbps: 5.0,
249        }
250    }
251
252    fn create_bulk_transfer_strategy() -> OptimizationStrategy {
253        OptimizationStrategy {
254            priority_threshold: Priority::MEDIUM,
255            max_frame_size: 256 * 1024, // 256KB for throughput
256            batch_size: 20,
257            compression_enabled: true,
258            adaptive_quality: false, // Consistent quality for bulk
259            description: "Optimized for bulk data transfer with maximum throughput".to_string(),
260            target_latency_ms: 1000.0,
261            target_throughput_mbps: 50.0,
262        }
263    }
264
265    fn create_mobile_app_strategy() -> OptimizationStrategy {
266        OptimizationStrategy {
267            priority_threshold: Priority::HIGH,
268            max_frame_size: 8 * 1024, // 8KB for mobile networks
269            batch_size: 3,
270            compression_enabled: true, // Important for mobile data usage
271            adaptive_quality: true,
272            description: "Optimized for mobile network constraints and battery life".to_string(),
273            target_latency_ms: 300.0,
274            target_throughput_mbps: 2.0,
275        }
276    }
277
278    fn create_pwa_strategy() -> OptimizationStrategy {
279        OptimizationStrategy {
280            priority_threshold: Priority::CRITICAL,
281            max_frame_size: 32 * 1024, // 32KB balanced
282            batch_size: 8,
283            compression_enabled: true,
284            adaptive_quality: true,
285            description: "Optimized for progressive web app user experience".to_string(),
286            target_latency_ms: 200.0,
287            target_throughput_mbps: 10.0,
288        }
289    }
290
291    fn create_iot_device_strategy() -> OptimizationStrategy {
292        OptimizationStrategy {
293            priority_threshold: Priority::CRITICAL,
294            max_frame_size: 4 * 1024, // 4KB for constrained devices
295            batch_size: 2,
296            compression_enabled: true, // Critical for bandwidth savings
297            adaptive_quality: false,   // Consistent behavior
298            description: "Optimized for IoT devices with power and bandwidth constraints"
299                .to_string(),
300            target_latency_ms: 500.0,
301            target_throughput_mbps: 1.0,
302        }
303    }
304
305    fn create_live_streaming_strategy() -> OptimizationStrategy {
306        OptimizationStrategy {
307            priority_threshold: Priority::HIGH,
308            max_frame_size: 64 * 1024, // 64KB for video frames
309            batch_size: 10,
310            compression_enabled: true,
311            adaptive_quality: true, // Important for varying network conditions
312            description: "Optimized for live streaming with audience interaction".to_string(),
313            target_latency_ms: 500.0,
314            target_throughput_mbps: 20.0,
315        }
316    }
317
318    fn create_balanced_strategy() -> OptimizationStrategy {
319        OptimizationStrategy {
320            priority_threshold: Priority::MEDIUM,
321            max_frame_size: 32 * 1024,
322            batch_size: 10,
323            compression_enabled: true,
324            adaptive_quality: true,
325            description: "Balanced strategy for general use cases".to_string(),
326            target_latency_ms: 500.0,
327            target_throughput_mbps: 10.0,
328        }
329    }
330
331    // Private calculation methods
332
333    fn calculate_efficiency_score(
334        &self,
335        frames: &[crate::domain::entities::Frame],
336        strategy: &OptimizationStrategy,
337    ) -> f64 {
338        if frames.is_empty() {
339            return 0.0;
340        }
341
342        // Calculate how well the frames align with the strategy
343        let target_priority = strategy.priority_threshold.value();
344        let mut efficiency_sum = 0.0;
345
346        for frame in frames {
347            let priority = frame.priority();
348            // Score based on how close the frame priority is to target
349            let priority_diff = (priority.value() as i32 - target_priority as i32).abs() as f64;
350            let priority_score = 1.0 - (priority_diff / 255.0).min(1.0);
351
352            // Score based on frame size efficiency
353            let size_score = if frame.estimated_size() <= strategy.max_frame_size {
354                1.0
355            } else {
356                strategy.max_frame_size as f64 / frame.estimated_size() as f64
357            };
358
359            efficiency_sum += (priority_score + size_score) / 2.0;
360        }
361
362        (efficiency_sum / frames.len() as f64).min(1.0)
363    }
364
365    fn estimate_latency_improvement(
366        &self,
367        strategy: &OptimizationStrategy,
368        context: &crate::application::services::prioritization_service::PerformanceContext,
369    ) -> f64 {
370        // Estimate improvement based on strategy parameters
371        let mut improvement = 0.0;
372
373        // Higher priority threshold should reduce latency
374        let priority_factor = strategy.priority_threshold.value() as f64 / 255.0;
375        improvement += priority_factor * 0.3;
376
377        // Smaller batch sizes reduce latency
378        let batch_factor = 1.0 - (strategy.batch_size as f64 / 50.0).min(1.0);
379        improvement += batch_factor * 0.2;
380
381        // Smaller frame sizes reduce processing time
382        let frame_size_factor = 1.0 - (strategy.max_frame_size as f64 / (1024.0 * 1024.0)).min(1.0);
383        improvement += frame_size_factor * 0.2;
384
385        // Consider current performance
386        if context.average_latency_ms > strategy.target_latency_ms {
387            improvement *= 1.5; // Higher improvement potential
388        }
389
390        improvement.min(1.0)
391    }
392
393    fn estimate_throughput_improvement(
394        &self,
395        strategy: &OptimizationStrategy,
396        context: &crate::application::services::prioritization_service::PerformanceContext,
397    ) -> f64 {
398        let mut improvement = 0.0;
399
400        // Larger batch sizes improve throughput
401        let batch_factor = (strategy.batch_size as f64 / 50.0).min(1.0);
402        improvement += batch_factor * 0.4;
403
404        // Compression can improve effective throughput
405        if strategy.compression_enabled {
406            improvement += 0.2;
407        }
408
409        // Larger frame sizes can improve efficiency
410        let frame_size_factor = (strategy.max_frame_size as f64 / (1024.0 * 1024.0)).min(1.0);
411        improvement += frame_size_factor * 0.3;
412
413        // Consider current performance
414        if context.available_bandwidth_mbps < strategy.target_throughput_mbps {
415            improvement *= 1.3; // Higher improvement potential
416        }
417
418        improvement.min(1.0)
419    }
420
421    fn calculate_resource_utilization(
422        &self,
423        strategy: &OptimizationStrategy,
424        context: &crate::application::services::prioritization_service::PerformanceContext,
425    ) -> f64 {
426        let mut utilization = context.cpu_usage;
427
428        // Compression increases CPU usage
429        if strategy.compression_enabled {
430            utilization += 0.1;
431        }
432
433        // Adaptive quality increases CPU usage
434        if strategy.adaptive_quality {
435            utilization += 0.05;
436        }
437
438        // Larger batch sizes reduce relative overhead
439        let batch_efficiency = (strategy.batch_size as f64 / 20.0).min(1.0);
440        utilization -= batch_efficiency * 0.1;
441
442        utilization.clamp(0.0, 1.0)
443    }
444
445    fn calculate_quality_score(
446        &self,
447        frames: &[crate::domain::entities::Frame],
448        strategy: &OptimizationStrategy,
449    ) -> f64 {
450        if frames.is_empty() {
451            return 0.0;
452        }
453
454        let mut quality_sum = 0.0;
455
456        for frame in frames {
457            let mut frame_quality = 1.0;
458
459            // Penalize frames that are too large
460            if frame.estimated_size() > strategy.max_frame_size {
461                frame_quality *= 0.8;
462            }
463
464            // Reward frames with appropriate priority
465            let priority = frame.priority();
466            if priority.value() >= strategy.priority_threshold.value() {
467                frame_quality *= 1.1;
468            }
469
470            quality_sum += frame_quality;
471        }
472
473        (quality_sum / frames.len() as f64).min(1.0)
474    }
475}
476
477impl Default for OptimizationService {
478    fn default() -> Self {
479        Self::new()
480    }
481}
482
483// Supporting types
484
485#[derive(Debug, Clone)]
486pub struct StrategyAdjustmentRecommendation {
487    pub adjustment_type: AdjustmentType,
488    pub description: String,
489    pub expected_impact: String,
490    pub confidence: f64,
491    pub urgency: AdjustmentUrgency,
492}
493
494#[derive(Debug, Clone, PartialEq)]
495pub enum AdjustmentType {
496    PriorityIncrease,
497    PriorityDecrease,
498    BatchSizeIncrease,
499    BatchSizeDecrease,
500    FrameSizeIncrease,
501    FrameSizeDecrease,
502    CompressionEnable,
503    CompressionDisable,
504    QualityIncrease,
505    QualityReduction,
506}
507
508// Use shared AdjustmentUrgency type
509use crate::application::shared::AdjustmentUrgency;
510
511#[cfg(test)]
512mod tests {
513    use super::*;
514
515    #[test]
516    fn test_optimization_service_creation() {
517        let service = OptimizationService::new();
518        assert!(service.custom_strategies.is_empty());
519    }
520
521    #[test]
522    fn test_strategy_selection_based_on_use_case() {
523        let service = OptimizationService::new();
524
525        // Test real-time dashboard strategy selection
526        let dashboard_strategy = service
527            .get_strategy_for_use_case(&StreamingUseCase::RealTimeDashboard)
528            .unwrap();
529        assert_eq!(dashboard_strategy.priority_threshold, Priority::HIGH);
530        assert_eq!(dashboard_strategy.batch_size, 5);
531        assert!(dashboard_strategy.adaptive_quality);
532
533        // Test mobile app strategy selection
534        let mobile_strategy = service
535            .get_strategy_for_use_case(&StreamingUseCase::MobileApp)
536            .unwrap();
537        assert_eq!(mobile_strategy.priority_threshold, Priority::HIGH);
538        assert!(mobile_strategy.compression_enabled);
539        assert_eq!(mobile_strategy.max_frame_size, 8 * 1024);
540    }
541
542    #[test]
543    fn test_custom_strategy_registration() {
544        let mut service = OptimizationService::new();
545
546        let custom_strategy = OptimizationStrategy {
547            priority_threshold: Priority::CRITICAL,
548            max_frame_size: 8 * 1024,
549            batch_size: 3,
550            compression_enabled: false,
551            adaptive_quality: false,
552            description: "Ultra low-latency gaming strategy".to_string(),
553            target_latency_ms: 50.0,
554            target_throughput_mbps: 30.0,
555        };
556
557        service
558            .register_custom_strategy("ultra_gaming".to_string(), custom_strategy.clone())
559            .unwrap();
560
561        let retrieved = service
562            .get_strategy_for_use_case(&StreamingUseCase::Custom("ultra_gaming".to_string()))
563            .unwrap();
564        assert_eq!(retrieved.priority_threshold, Priority::CRITICAL);
565        assert_eq!(retrieved.max_frame_size, 8 * 1024);
566        assert_eq!(retrieved.target_latency_ms, 50.0);
567    }
568}