1use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::fmt;
10use std::sync::Arc;
11use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
12use thiserror::Error;
13use tokio::sync::RwLock;
14
15#[derive(Debug, Clone, Serialize, Deserialize, Error)]
17#[error("{message}")]
18pub struct AdvancedError {
19 pub category: ErrorCategory,
21 pub severity: ErrorSeverity,
23 pub message: String,
25 pub technical_details: String,
27 pub context: ErrorContext,
29 pub recovery_suggestions: Vec<RecoverySuggestion>,
31 pub related_errors: Vec<String>,
33 pub timestamp: u64,
35 pub error_id: String,
37 pub recoverable: bool,
39 pub retry_info: Option<RetryInfo>,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
45pub enum ErrorCategory {
46 Configuration,
48 Network,
50 FileSystem,
52 Memory,
54 ModelLoading,
56 AudioProcessing,
58 Synthesis,
60 Authentication,
62 Permission,
64 ResourceExhaustion,
66 Dependency,
68 Hardware,
70 UserInput,
72 Internal,
74 ExternalService,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
80pub enum ErrorSeverity {
81 Info,
83 Warning,
85 Error,
87 Critical,
89 Fatal,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct ErrorContext {
96 pub operation: String,
98 pub user: Option<String>,
100 pub session_id: Option<String>,
102 pub request_id: Option<String>,
104 pub component: String,
106 pub function: Option<String>,
108 pub location: Option<String>,
110 pub parameters: HashMap<String, String>,
112 pub system_state: SystemState,
114 pub performance_metrics: Option<ErrorTimeMetrics>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct SystemState {
121 pub available_memory_bytes: u64,
123 pub cpu_usage_percent: f64,
125 pub active_operations: usize,
127 pub queue_depth: usize,
129 pub last_success_time: Option<u64>,
131 pub uptime_seconds: u64,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct ErrorTimeMetrics {
138 pub latency_ms: u64,
140 pub throughput: f64,
142 pub memory_usage_mb: f64,
144 pub recent_error_rate: f64,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct RecoverySuggestion {
151 pub category: RecoveryCategory,
153 pub priority: u8,
155 pub suggestion: String,
157 pub steps: Vec<String>,
159 pub estimated_time: Duration,
161 pub difficulty: DifficultyLevel,
163 pub success_probability: f64,
165 pub requires_user_action: bool,
167 pub automated_actions: Vec<AutomatedAction>,
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
173pub enum RecoveryCategory {
174 AutomaticRecovery,
176 ConfigurationFix,
178 ResourceOptimization,
180 RetryOptimization,
182 SystemRestart,
184 SoftwareUpdate,
186 HardwareCheck,
188 NetworkTroubleshooting,
190 PermissionFix,
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
196pub enum DifficultyLevel {
197 Trivial,
199 Easy,
201 Medium,
203 Hard,
205 Expert,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct AutomatedAction {
212 pub action_type: ActionType,
214 pub description: String,
216 pub parameters: HashMap<String, String>,
218 pub safe_to_automate: bool,
220 pub execution_time: Duration,
222 pub dependencies: Vec<String>,
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
228pub enum ActionType {
229 RestartService,
231 ClearCache,
233 AdjustConfiguration,
235 RetryOperation,
237 ReduceResources,
239 EnableFallback,
241 UpdateSoftware,
243 CheckResources,
245 ValidateConfiguration,
247 RepairData,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct RetryInfo {
254 pub attempt: usize,
256 pub max_attempts: usize,
258 pub retry_delay: Duration,
260 pub backoff_strategy: BackoffStrategy,
262 pub last_retry: Option<u64>,
264 pub success_history: Vec<bool>,
266}
267
268#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
270pub enum BackoffStrategy {
271 Fixed,
273 Linear,
275 Exponential,
277 Fibonacci,
279 Custom(Vec<u64>),
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct ErrorPattern {
286 pub pattern_id: String,
288 pub description: String,
290 pub categories: Vec<ErrorCategory>,
292 pub min_occurrences: usize,
294 pub time_window: Duration,
296 pub recovery_strategy: RecoveryStrategy,
298 pub confidence: f64,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct RecoveryStrategy {
305 pub name: String,
307 pub automatic_actions: Vec<AutomatedAction>,
309 pub manual_steps: Vec<String>,
311 pub conditions: Vec<String>,
313 pub success_rate: f64,
315 pub recovery_time: Duration,
317}
318
319pub struct AdvancedErrorHandler {
321 error_history: Arc<RwLock<Vec<AdvancedError>>>,
323 detected_patterns: Arc<RwLock<HashMap<String, ErrorPattern>>>,
325 recovery_stats: Arc<RwLock<RecoveryStatistics>>,
327 config: ErrorHandlerConfig,
329 pattern_rules: Vec<ErrorPattern>,
331 action_handlers: HashMap<ActionType, Box<dyn ActionHandler>>,
333}
334
335#[derive(Debug, Clone, Default, Serialize, Deserialize)]
337pub struct RecoveryStatistics {
338 pub total_errors: u64,
340 pub recovery_attempts: u64,
342 pub successful_recoveries: u64,
344 pub success_rate: f64,
346 pub avg_recovery_time_ms: f64,
348 pub category_stats: HashMap<ErrorCategory, CategoryStats>,
350 pub pattern_stats: HashMap<String, PatternStats>,
352}
353
354#[derive(Debug, Clone, Default, Serialize, Deserialize)]
356pub struct CategoryStats {
357 pub count: u64,
359 pub recovery_rate: f64,
361 pub avg_recovery_time_ms: f64,
363 pub best_recovery_method: Option<RecoveryCategory>,
365}
366
367#[derive(Debug, Clone, Default, Serialize, Deserialize)]
369pub struct PatternStats {
370 pub detection_count: u64,
372 pub recovery_attempts: u64,
374 pub successful_recoveries: u64,
376 pub success_rate: f64,
378}
379
380#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct ErrorHandlerConfig {
383 pub enable_pattern_detection: bool,
385 pub enable_auto_recovery: bool,
387 pub max_error_history: usize,
389 pub pattern_sensitivity: f64,
391 pub max_auto_recovery_attempts: usize,
393 pub reporting_config: ErrorReportingConfig,
395 pub recovery_timeout: Duration,
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize)]
401pub struct ErrorReportingConfig {
402 pub detailed_logging: bool,
404 pub log_file_path: Option<String>,
406 pub enable_telemetry: bool,
408 pub telemetry_endpoint: Option<String>,
410 pub enable_notifications: bool,
412 pub notification_threshold: ErrorSeverity,
414}
415
416pub trait ActionHandler: Send + Sync {
418 fn execute(&self, action: &AutomatedAction) -> Result<ActionResult, ActionError>;
420
421 fn can_execute(&self, action: &AutomatedAction) -> bool;
423
424 fn estimated_time(&self, action: &AutomatedAction) -> Duration;
426}
427
428#[derive(Debug, Clone, Serialize, Deserialize)]
430pub struct ActionResult {
431 pub success: bool,
433 pub message: String,
435 pub execution_time: Duration,
437 pub data: HashMap<String, String>,
439}
440
441#[derive(Debug, Error)]
443pub enum ActionError {
444 #[error("Action execution failed: {message}")]
445 ExecutionFailed { message: String },
446 #[error("Action not supported: {action_type:?}")]
447 NotSupported { action_type: ActionType },
448 #[error("Action timed out after {timeout:?}")]
449 Timeout { timeout: Duration },
450 #[error("Action dependencies not met: {missing:?}")]
451 DependenciesMissing { missing: Vec<String> },
452}
453
454impl AdvancedErrorHandler {
455 pub fn new(config: ErrorHandlerConfig) -> Self {
457 Self {
458 error_history: Arc::new(RwLock::new(Vec::new())),
459 detected_patterns: Arc::new(RwLock::new(HashMap::new())),
460 recovery_stats: Arc::new(RwLock::new(RecoveryStatistics::default())),
461 config,
462 pattern_rules: Self::default_pattern_rules(),
463 action_handlers: Self::default_action_handlers(),
464 }
465 }
466
467 pub async fn handle_error(&self, error: AdvancedError) -> ErrorHandlingResult {
469 tracing::error!(
470 "Handling advanced error: {} ({})",
471 error.message,
472 error.error_id
473 );
474
475 self.record_error(&error).await;
477
478 self.update_statistics(&error).await;
480
481 let detected_patterns = if self.config.enable_pattern_detection {
483 self.detect_patterns(&error).await
484 } else {
485 Vec::new()
486 };
487
488 let recovery_result = if self.config.enable_auto_recovery && error.recoverable {
490 self.attempt_recovery(&error).await
491 } else {
492 RecoveryResult::NotAttempted
493 };
494
495 let user_report = self
497 .generate_user_report(&error, &detected_patterns, &recovery_result)
498 .await;
499
500 ErrorHandlingResult {
501 error_id: error.error_id.clone(),
502 handled: true,
503 recovery_result,
504 detected_patterns,
505 user_report,
506 automated_actions_taken: self.get_automated_actions(&error).await,
507 recommendations: error.recovery_suggestions.clone(),
508 }
509 }
510
511 async fn record_error(&self, error: &AdvancedError) {
513 let mut history = self.error_history.write().await;
514 history.push(error.clone());
515
516 if history.len() > self.config.max_error_history {
518 history.remove(0);
519 }
520 }
521
522 async fn update_statistics(&self, error: &AdvancedError) {
524 let mut stats = self.recovery_stats.write().await;
525 stats.total_errors += 1;
526
527 let category_stats = stats.category_stats.entry(error.category).or_default();
529 category_stats.count += 1;
530 }
531
532 async fn detect_patterns(&self, current_error: &AdvancedError) -> Vec<String> {
534 let mut detected = Vec::new();
535 let history = self.error_history.read().await;
536
537 for pattern in &self.pattern_rules {
538 if self.matches_pattern(pattern, current_error, &history) {
539 detected.push(pattern.pattern_id.clone());
540
541 let mut patterns = self.detected_patterns.write().await;
543 patterns.insert(pattern.pattern_id.clone(), pattern.clone());
544 }
545 }
546
547 detected
548 }
549
550 fn matches_pattern(
552 &self,
553 pattern: &ErrorPattern,
554 error: &AdvancedError,
555 history: &[AdvancedError],
556 ) -> bool {
557 if !pattern.categories.contains(&error.category) {
559 return false;
560 }
561
562 let cutoff_time = SystemTime::now()
564 .duration_since(SystemTime::UNIX_EPOCH)
565 .unwrap_or_default()
566 .as_secs()
567 .saturating_sub(pattern.time_window.as_secs());
568
569 let recent_similar_errors = history
570 .iter()
571 .filter(|e| e.timestamp >= cutoff_time)
572 .filter(|e| pattern.categories.contains(&e.category))
573 .count();
574
575 recent_similar_errors >= pattern.min_occurrences
576 }
577
578 async fn attempt_recovery(&self, error: &AdvancedError) -> RecoveryResult {
580 tracing::info!(
581 "Attempting automatic recovery for error: {}",
582 error.error_id
583 );
584
585 let mut stats = self.recovery_stats.write().await;
586 stats.recovery_attempts += 1;
587 drop(stats);
588
589 let mut sorted_suggestions = error.recovery_suggestions.clone();
591 sorted_suggestions.sort_by(|a, b| b.priority.cmp(&a.priority));
592
593 for suggestion in sorted_suggestions {
594 if suggestion.category == RecoveryCategory::AutomaticRecovery {
595 match self
596 .execute_recovery_actions(&suggestion.automated_actions)
597 .await
598 {
599 Ok(results) => {
600 if results.iter().all(|r| r.success) {
601 let mut stats = self.recovery_stats.write().await;
602 stats.successful_recoveries += 1;
603 stats.success_rate =
604 stats.successful_recoveries as f64 / stats.recovery_attempts as f64;
605
606 return RecoveryResult::Successful {
607 method: suggestion.category,
608 actions_taken: results,
609 recovery_time: suggestion.estimated_time,
610 };
611 }
612 }
613 Err(e) => {
614 tracing::warn!("Recovery action failed: {}", e);
615 }
616 }
617 }
618 }
619
620 RecoveryResult::Failed {
621 reason: "No successful automatic recovery method found".to_string(),
622 attempted_methods: error
623 .recovery_suggestions
624 .iter()
625 .map(|s| s.category.clone())
626 .collect(),
627 }
628 }
629
630 async fn execute_recovery_actions(
632 &self,
633 actions: &[AutomatedAction],
634 ) -> Result<Vec<ActionResult>, ActionError> {
635 let mut results = Vec::new();
636
637 for action in actions {
638 if let Some(handler) = self.action_handlers.get(&action.action_type) {
639 if handler.can_execute(action) {
640 match handler.execute(action) {
641 Ok(result) => results.push(result),
642 Err(e) => return Err(e),
643 }
644 } else {
645 return Err(ActionError::NotSupported {
646 action_type: action.action_type.clone(),
647 });
648 }
649 }
650 }
651
652 Ok(results)
653 }
654
655 async fn generate_user_report(
657 &self,
658 error: &AdvancedError,
659 patterns: &[String],
660 recovery: &RecoveryResult,
661 ) -> UserErrorReport {
662 UserErrorReport {
663 title: self.generate_user_friendly_title(error),
664 summary: self.generate_error_summary(error),
665 impact: self.assess_user_impact(error),
666 what_happened: self.explain_what_happened(error),
667 why_it_happened: self.explain_why_it_happened(error, patterns),
668 what_we_did: self.explain_recovery_actions(recovery),
669 what_you_can_do: self.generate_user_actions(error),
670 prevention_tips: self.generate_prevention_tips(error),
671 technical_details: if self.config.reporting_config.detailed_logging {
672 Some(error.technical_details.clone())
673 } else {
674 None
675 },
676 support_info: self.generate_support_info(error),
677 }
678 }
679
680 fn generate_user_friendly_title(&self, error: &AdvancedError) -> String {
682 match error.category {
683 ErrorCategory::Network => "Network Connection Issue".to_string(),
684 ErrorCategory::Memory => "Memory Issue Detected".to_string(),
685 ErrorCategory::ModelLoading => "Model Loading Problem".to_string(),
686 ErrorCategory::AudioProcessing => "Audio Processing Error".to_string(),
687 ErrorCategory::Synthesis => "Voice Synthesis Issue".to_string(),
688 ErrorCategory::Configuration => "Configuration Problem".to_string(),
689 ErrorCategory::FileSystem => "File System Error".to_string(),
690 ErrorCategory::Authentication => "Authentication Issue".to_string(),
691 ErrorCategory::Permission => "Permission Error".to_string(),
692 ErrorCategory::ResourceExhaustion => "System Resources Low".to_string(),
693 ErrorCategory::Dependency => "Dependency Issue".to_string(),
694 ErrorCategory::Hardware => "Hardware Problem Detected".to_string(),
695 ErrorCategory::UserInput => "Input Validation Error".to_string(),
696 ErrorCategory::Internal => "Internal System Error".to_string(),
697 ErrorCategory::ExternalService => "External Service Issue".to_string(),
698 }
699 }
700
701 fn generate_error_summary(&self, error: &AdvancedError) -> String {
703 match error.severity {
704 ErrorSeverity::Info => format!("Information: {}", error.message),
705 ErrorSeverity::Warning => {
706 format!("Warning: {} This may affect performance.", error.message)
707 }
708 ErrorSeverity::Error => format!(
709 "Error: {} The current operation could not be completed.",
710 error.message
711 ),
712 ErrorSeverity::Critical => format!(
713 "Critical Issue: {} System functionality may be impaired.",
714 error.message
715 ),
716 ErrorSeverity::Fatal => format!(
717 "Fatal Error: {} System cannot continue normal operation.",
718 error.message
719 ),
720 }
721 }
722
723 fn assess_user_impact(&self, error: &AdvancedError) -> UserImpact {
725 match (error.severity, error.category) {
726 (ErrorSeverity::Fatal, _) => UserImpact::Severe,
727 (ErrorSeverity::Critical, _) => UserImpact::High,
728 (ErrorSeverity::Error, ErrorCategory::Synthesis) => UserImpact::Medium,
729 (ErrorSeverity::Error, ErrorCategory::AudioProcessing) => UserImpact::Medium,
730 (ErrorSeverity::Warning, _) => UserImpact::Low,
731 (ErrorSeverity::Info, _) => UserImpact::None,
732 _ => UserImpact::Medium,
733 }
734 }
735
736 fn explain_what_happened(&self, error: &AdvancedError) -> String {
738 format!(
739 "While performing '{}', an issue occurred in the {} component. {}",
740 error.context.operation,
741 error.context.component,
742 match error.category {
743 ErrorCategory::Network =>
744 "The system could not connect to the required network service.",
745 ErrorCategory::Memory => "The system ran low on available memory.",
746 ErrorCategory::ModelLoading => "The voice model could not be loaded properly.",
747 ErrorCategory::AudioProcessing =>
748 "The audio data could not be processed as expected.",
749 ErrorCategory::Synthesis => "The voice synthesis process encountered an issue.",
750 _ => "An unexpected condition was encountered.",
751 }
752 )
753 }
754
755 fn explain_why_it_happened(&self, error: &AdvancedError, patterns: &[String]) -> String {
757 if !patterns.is_empty() {
758 format!(
759 "This appears to be part of a known pattern: {}. Common causes include resource constraints, network instability, or configuration issues.",
760 patterns.join(", ")
761 )
762 } else {
763 match error.category {
764 ErrorCategory::Network => "This could be due to internet connectivity issues, firewall restrictions, or service outages.".to_string(),
765 ErrorCategory::Memory => "This typically happens when the system is processing large amounts of data or when other applications are using significant memory.".to_string(),
766 ErrorCategory::ModelLoading => "This may occur if model files are corrupted, missing, or incompatible with the current system.".to_string(),
767 _ => "The exact cause is being investigated. This may be a temporary issue.".to_string(),
768 }
769 }
770 }
771
772 fn explain_recovery_actions(&self, recovery: &RecoveryResult) -> String {
774 match recovery {
775 RecoveryResult::Successful {
776 method,
777 actions_taken,
778 ..
779 } => {
780 format!(
781 "We automatically attempted to resolve this issue using {} and took {} recovery actions. The issue appears to be resolved.",
782 Self::recovery_method_description(method),
783 actions_taken.len()
784 )
785 }
786 RecoveryResult::Failed {
787 attempted_methods, ..
788 } => {
789 format!(
790 "We attempted automatic recovery using {} methods, but the issue persists and requires manual intervention.",
791 attempted_methods.len()
792 )
793 }
794 RecoveryResult::NotAttempted => {
795 "No automatic recovery was attempted for this type of issue.".to_string()
796 }
797 }
798 }
799
800 fn generate_user_actions(&self, error: &AdvancedError) -> Vec<String> {
802 let mut actions = Vec::new();
803
804 match error.category {
806 ErrorCategory::Network => {
807 actions.push("Check your internet connection".to_string());
808 actions.push("Try again in a few moments".to_string());
809 actions.push("Check if any firewalls are blocking the connection".to_string());
810 }
811 ErrorCategory::Memory => {
812 actions.push("Close other applications to free up memory".to_string());
813 actions.push("Try processing smaller amounts of data at once".to_string());
814 actions.push("Restart the application if the issue persists".to_string());
815 }
816 ErrorCategory::ModelLoading => {
817 actions.push("Verify that all required model files are present".to_string());
818 actions.push("Try re-downloading the models if available".to_string());
819 actions.push("Check available disk space".to_string());
820 }
821 _ => {
822 actions.push("Try the operation again".to_string());
823 actions.push("Check the system logs for more details".to_string());
824 }
825 }
826
827 for suggestion in &error.recovery_suggestions {
829 if suggestion.requires_user_action && suggestion.difficulty == DifficultyLevel::Easy {
830 actions.push(suggestion.suggestion.clone());
831 }
832 }
833
834 actions
835 }
836
837 fn generate_prevention_tips(&self, error: &AdvancedError) -> Vec<String> {
839 match error.category {
840 ErrorCategory::Network => vec![
841 "Ensure stable internet connection before starting operations".to_string(),
842 "Consider using offline mode when available".to_string(),
843 ],
844 ErrorCategory::Memory => vec![
845 "Close unnecessary applications before processing large tasks".to_string(),
846 "Process data in smaller batches".to_string(),
847 "Consider upgrading system memory if this occurs frequently".to_string(),
848 ],
849 ErrorCategory::ModelLoading => vec![
850 "Regularly verify model file integrity".to_string(),
851 "Keep models updated to the latest versions".to_string(),
852 "Ensure sufficient disk space for model storage".to_string(),
853 ],
854 _ => vec![
855 "Keep the application updated to the latest version".to_string(),
856 "Monitor system resources during heavy operations".to_string(),
857 ],
858 }
859 }
860
861 fn generate_support_info(&self, error: &AdvancedError) -> SupportInfo {
863 SupportInfo {
864 error_id: error.error_id.clone(),
865 timestamp: error.timestamp,
866 component: error.context.component.clone(),
867 severity: error.severity,
868 category: error.category,
869 session_id: error.context.session_id.clone(),
870 request_id: error.context.request_id.clone(),
871 support_url: Some("https://support.voirs.com".to_string()),
872 documentation_links: self.get_relevant_documentation_links(&error.category),
873 }
874 }
875
876 async fn get_automated_actions(&self, error: &AdvancedError) -> Vec<String> {
878 error
879 .recovery_suggestions
880 .iter()
881 .filter(|s| s.category == RecoveryCategory::AutomaticRecovery)
882 .flat_map(|s| s.automated_actions.iter())
883 .map(|a| a.description.clone())
884 .collect()
885 }
886
887 fn get_relevant_documentation_links(&self, category: &ErrorCategory) -> Vec<String> {
889 match category {
890 ErrorCategory::Network => vec![
891 "https://docs.voirs.com/troubleshooting/network".to_string(),
892 "https://docs.voirs.com/configuration/connectivity".to_string(),
893 ],
894 ErrorCategory::Memory => vec![
895 "https://docs.voirs.com/performance/memory-optimization".to_string(),
896 "https://docs.voirs.com/troubleshooting/performance".to_string(),
897 ],
898 ErrorCategory::ModelLoading => vec![
899 "https://docs.voirs.com/models/installation".to_string(),
900 "https://docs.voirs.com/troubleshooting/models".to_string(),
901 ],
902 _ => vec!["https://docs.voirs.com/troubleshooting".to_string()],
903 }
904 }
905
906 fn recovery_method_description(method: &RecoveryCategory) -> &'static str {
908 match method {
909 RecoveryCategory::AutomaticRecovery => "automatic system recovery",
910 RecoveryCategory::ConfigurationFix => "configuration adjustment",
911 RecoveryCategory::ResourceOptimization => "resource optimization",
912 RecoveryCategory::RetryOptimization => "intelligent retry",
913 RecoveryCategory::SystemRestart => "system restart",
914 RecoveryCategory::SoftwareUpdate => "software update",
915 RecoveryCategory::HardwareCheck => "hardware validation",
916 RecoveryCategory::NetworkTroubleshooting => "network diagnostics",
917 RecoveryCategory::PermissionFix => "permission correction",
918 }
919 }
920
921 fn default_pattern_rules() -> Vec<ErrorPattern> {
923 vec![
924 ErrorPattern {
925 pattern_id: "network_instability".to_string(),
926 description: "Repeated network connection failures".to_string(),
927 categories: vec![ErrorCategory::Network, ErrorCategory::ExternalService],
928 min_occurrences: 3,
929 time_window: Duration::from_secs(300), recovery_strategy: RecoveryStrategy {
931 name: "Network Recovery".to_string(),
932 automatic_actions: vec![AutomatedAction {
933 action_type: ActionType::RetryOperation,
934 description: "Retry with exponential backoff".to_string(),
935 parameters: HashMap::new(),
936 safe_to_automate: true,
937 execution_time: Duration::from_secs(30),
938 dependencies: vec![],
939 }],
940 manual_steps: vec!["Check network connection".to_string()],
941 conditions: vec!["Network errors > 3 in 5 minutes".to_string()],
942 success_rate: 0.8,
943 recovery_time: Duration::from_secs(60),
944 },
945 confidence: 0.9,
946 },
947 ErrorPattern {
948 pattern_id: "memory_pressure".to_string(),
949 description: "System running low on memory".to_string(),
950 categories: vec![ErrorCategory::Memory, ErrorCategory::ResourceExhaustion],
951 min_occurrences: 2,
952 time_window: Duration::from_secs(120), recovery_strategy: RecoveryStrategy {
954 name: "Memory Optimization".to_string(),
955 automatic_actions: vec![
956 AutomatedAction {
957 action_type: ActionType::ClearCache,
958 description: "Clear system caches".to_string(),
959 parameters: HashMap::new(),
960 safe_to_automate: true,
961 execution_time: Duration::from_secs(10),
962 dependencies: vec![],
963 },
964 AutomatedAction {
965 action_type: ActionType::ReduceResources,
966 description: "Reduce memory usage".to_string(),
967 parameters: HashMap::new(),
968 safe_to_automate: true,
969 execution_time: Duration::from_secs(5),
970 dependencies: vec![],
971 },
972 ],
973 manual_steps: vec!["Close unnecessary applications".to_string()],
974 conditions: vec!["Memory errors in short timespan".to_string()],
975 success_rate: 0.7,
976 recovery_time: Duration::from_secs(30),
977 },
978 confidence: 0.85,
979 },
980 ]
981 }
982
983 fn default_action_handlers() -> HashMap<ActionType, Box<dyn ActionHandler>> {
985 HashMap::new()
987 }
988}
989
990#[derive(Debug, Clone, Serialize, Deserialize)]
992pub struct ErrorHandlingResult {
993 pub error_id: String,
995 pub handled: bool,
997 pub recovery_result: RecoveryResult,
999 pub detected_patterns: Vec<String>,
1001 pub user_report: UserErrorReport,
1003 pub automated_actions_taken: Vec<String>,
1005 pub recommendations: Vec<RecoverySuggestion>,
1007}
1008
1009#[derive(Debug, Clone, Serialize, Deserialize)]
1011pub enum RecoveryResult {
1012 Successful {
1014 method: RecoveryCategory,
1015 actions_taken: Vec<ActionResult>,
1016 recovery_time: Duration,
1017 },
1018 Failed {
1020 reason: String,
1021 attempted_methods: Vec<RecoveryCategory>,
1022 },
1023 NotAttempted,
1025}
1026
1027#[derive(Debug, Clone, Serialize, Deserialize)]
1029pub struct UserErrorReport {
1030 pub title: String,
1032 pub summary: String,
1034 pub impact: UserImpact,
1036 pub what_happened: String,
1038 pub why_it_happened: String,
1040 pub what_we_did: String,
1042 pub what_you_can_do: Vec<String>,
1044 pub prevention_tips: Vec<String>,
1046 pub technical_details: Option<String>,
1048 pub support_info: SupportInfo,
1050}
1051
1052#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1054pub enum UserImpact {
1055 None,
1057 Low,
1059 Medium,
1061 High,
1063 Severe,
1065}
1066
1067#[derive(Debug, Clone, Serialize, Deserialize)]
1069pub struct SupportInfo {
1070 pub error_id: String,
1072 pub timestamp: u64,
1074 pub component: String,
1076 pub severity: ErrorSeverity,
1078 pub category: ErrorCategory,
1080 pub session_id: Option<String>,
1082 pub request_id: Option<String>,
1084 pub support_url: Option<String>,
1086 pub documentation_links: Vec<String>,
1088}
1089
1090impl Default for ErrorHandlerConfig {
1091 fn default() -> Self {
1092 Self {
1093 enable_pattern_detection: true,
1094 enable_auto_recovery: true,
1095 max_error_history: 1000,
1096 pattern_sensitivity: 0.8,
1097 max_auto_recovery_attempts: 3,
1098 reporting_config: ErrorReportingConfig::default(),
1099 recovery_timeout: Duration::from_secs(60),
1100 }
1101 }
1102}
1103
1104impl Default for ErrorReportingConfig {
1105 fn default() -> Self {
1106 Self {
1107 detailed_logging: true,
1108 log_file_path: Some("voirs-errors.log".to_string()),
1109 enable_telemetry: false,
1110 telemetry_endpoint: None,
1111 enable_notifications: true,
1112 notification_threshold: ErrorSeverity::Error,
1113 }
1114 }
1115}
1116
1117impl fmt::Display for ErrorSeverity {
1118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1119 match self {
1120 ErrorSeverity::Info => write!(f, "INFO"),
1121 ErrorSeverity::Warning => write!(f, "WARNING"),
1122 ErrorSeverity::Error => write!(f, "ERROR"),
1123 ErrorSeverity::Critical => write!(f, "CRITICAL"),
1124 ErrorSeverity::Fatal => write!(f, "FATAL"),
1125 }
1126 }
1127}
1128
1129impl fmt::Display for ErrorCategory {
1130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131 match self {
1132 ErrorCategory::Configuration => write!(f, "Configuration"),
1133 ErrorCategory::Network => write!(f, "Network"),
1134 ErrorCategory::FileSystem => write!(f, "FileSystem"),
1135 ErrorCategory::Memory => write!(f, "Memory"),
1136 ErrorCategory::ModelLoading => write!(f, "ModelLoading"),
1137 ErrorCategory::AudioProcessing => write!(f, "AudioProcessing"),
1138 ErrorCategory::Synthesis => write!(f, "Synthesis"),
1139 ErrorCategory::Authentication => write!(f, "Authentication"),
1140 ErrorCategory::Permission => write!(f, "Permission"),
1141 ErrorCategory::ResourceExhaustion => write!(f, "ResourceExhaustion"),
1142 ErrorCategory::Dependency => write!(f, "Dependency"),
1143 ErrorCategory::Hardware => write!(f, "Hardware"),
1144 ErrorCategory::UserInput => write!(f, "UserInput"),
1145 ErrorCategory::Internal => write!(f, "Internal"),
1146 ErrorCategory::ExternalService => write!(f, "ExternalService"),
1147 }
1148 }
1149}
1150
1151#[cfg(test)]
1152mod tests {
1153 use super::*;
1154
1155 #[tokio::test]
1156 async fn test_error_handler_creation() {
1157 let config = ErrorHandlerConfig::default();
1158 let handler = AdvancedErrorHandler::new(config);
1159
1160 assert!(handler.pattern_rules.len() > 0);
1162 }
1163
1164 #[tokio::test]
1165 async fn test_error_handling() {
1166 let config = ErrorHandlerConfig::default();
1167 let handler = AdvancedErrorHandler::new(config);
1168
1169 let error = AdvancedError {
1170 category: ErrorCategory::Network,
1171 severity: ErrorSeverity::Error,
1172 message: "Connection failed".to_string(),
1173 technical_details: "TCP connection timeout".to_string(),
1174 context: ErrorContext {
1175 operation: "test_operation".to_string(),
1176 user: None,
1177 session_id: None,
1178 request_id: None,
1179 component: "network_client".to_string(),
1180 function: Some("connect".to_string()),
1181 location: None,
1182 parameters: HashMap::new(),
1183 system_state: SystemState {
1184 available_memory_bytes: 1000000,
1185 cpu_usage_percent: 50.0,
1186 active_operations: 1,
1187 queue_depth: 0,
1188 last_success_time: None,
1189 uptime_seconds: 3600,
1190 },
1191 performance_metrics: None,
1192 },
1193 recovery_suggestions: vec![],
1194 related_errors: vec![],
1195 timestamp: SystemTime::now()
1196 .duration_since(SystemTime::UNIX_EPOCH)
1197 .unwrap()
1198 .as_secs(),
1199 error_id: "test_error_123".to_string(),
1200 recoverable: true,
1201 retry_info: Some(RetryInfo {
1202 attempt: 0,
1203 max_attempts: 3,
1204 retry_delay: Duration::from_secs(5),
1205 backoff_strategy: BackoffStrategy::Exponential,
1206 last_retry: None,
1207 success_history: vec![],
1208 }),
1209 };
1210
1211 let result = handler.handle_error(error).await;
1212
1213 assert!(result.handled);
1214 assert_eq!(result.error_id, "test_error_123");
1215 }
1216
1217 #[test]
1218 fn test_error_severity_ordering() {
1219 assert!(ErrorSeverity::Fatal > ErrorSeverity::Critical);
1220 assert!(ErrorSeverity::Critical > ErrorSeverity::Error);
1221 assert!(ErrorSeverity::Error > ErrorSeverity::Warning);
1222 assert!(ErrorSeverity::Warning > ErrorSeverity::Info);
1223 }
1224
1225 #[test]
1226 fn test_backoff_strategy() {
1227 let retry_info = RetryInfo {
1228 attempt: 2,
1229 max_attempts: 5,
1230 retry_delay: Duration::from_secs(10),
1231 backoff_strategy: BackoffStrategy::Exponential,
1232 last_retry: None,
1233 success_history: vec![false, false],
1234 };
1235
1236 assert_eq!(retry_info.backoff_strategy, BackoffStrategy::Exponential);
1237 assert_eq!(retry_info.attempt, 2);
1238 }
1239
1240 #[test]
1241 fn test_user_impact_assessment() {
1242 let config = ErrorHandlerConfig::default();
1243 let handler = AdvancedErrorHandler::new(config);
1244
1245 let fatal_error = AdvancedError {
1246 severity: ErrorSeverity::Fatal,
1247 category: ErrorCategory::Internal,
1248 message: "Fatal error".to_string(),
1250 technical_details: "System crash".to_string(),
1251 context: ErrorContext {
1252 operation: "test".to_string(),
1253 user: None,
1254 session_id: None,
1255 request_id: None,
1256 component: "test".to_string(),
1257 function: None,
1258 location: None,
1259 parameters: HashMap::new(),
1260 system_state: SystemState {
1261 available_memory_bytes: 0,
1262 cpu_usage_percent: 0.0,
1263 active_operations: 0,
1264 queue_depth: 0,
1265 last_success_time: None,
1266 uptime_seconds: 0,
1267 },
1268 performance_metrics: None,
1269 },
1270 recovery_suggestions: vec![],
1271 related_errors: vec![],
1272 timestamp: 0,
1273 error_id: "test".to_string(),
1274 recoverable: false,
1275 retry_info: None,
1276 };
1277
1278 let impact = handler.assess_user_impact(&fatal_error);
1279 assert_eq!(impact, UserImpact::Severe);
1280 }
1281}