diff --git a/lib/actors/system_monitor/src/alert_formatter.rs b/lib/actors/system_monitor/src/alert_formatter.rs deleted file mode 100644 index 2b35dcb..0000000 --- a/lib/actors/system_monitor/src/alert_formatter.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::{Severity, SystemMonitor, ThresholdViolation}; - -pub struct AlertFormatter; - -impl AlertFormatter { - pub fn format_violation(&self, violation: &ThresholdViolation) -> String { - let emoji = match violation.severity { - Severity::Warning => "⚠️", - Severity::Critical => "🚨", - }; - - let level = match violation.severity { - Severity::Warning => "ALERTE", - Severity::Critical => "CRITIQUE", - }; - - format!( - "{} **{}** - {}\n\n**Valeur actuelle:** {:.2}%\n**Seuil:** {:.2}%", - emoji, - level, - self.get_message_for_metric(&violation.metric_name, &violation.severity), - violation.current_value, - violation.threshold - ) - } - - fn get_message_for_metric(&self, metric: &str, severity: &Severity) -> String { - match (metric, severity) { - ("CPU", Severity::Warning) => "Utilisation CPU élevée détectée".to_string(), - ("CPU", Severity::Critical) => "CPU en surchauffe - Intervention requise !".to_string(), - ("Memory", Severity::Warning) => "Utilisation mémoire élevée".to_string(), - ("Memory", Severity::Critical) => "Mémoire saturée - Risque de crash !".to_string(), - ("Swap", Severity::Warning) => "Utilisation swap élevée".to_string(), - ("Swap", Severity::Critical) => "Swap saturé - Performance dégradée !".to_string(), - ("Disk", Severity::Warning) => "Espace disque faible".to_string(), - ("Disk", Severity::Critical) => "Disque presque plein - Nettoyage urgent !".to_string(), - (metric, _) => format!("Problème détecté sur {metric}"), - } - } - - pub fn format_summary(&self, monitor: &SystemMonitor) -> String { - let metrics = monitor.get_metrics(); - - let mut result = "📊 **Rapport Système**\n\n```\n".to_string(); - - for (key, value) in &metrics { - result.push_str(&format!("{}: {:.1}%\n", key, value)); - } - - result.push_str("```\n\n*Surveillance automatique*"); - - result - } -} diff --git a/lib/actors/system_monitor/src/lib.rs b/lib/actors/system_monitor/src/lib.rs index f7ce3ef..eac8011 100644 --- a/lib/actors/system_monitor/src/lib.rs +++ b/lib/actors/system_monitor/src/lib.rs @@ -1,10 +1,9 @@ use crate::resource_threshold::ResourceThreshold; -use std::collections::HashMap; +use std::{collections::HashMap, fmt}; use sysinfo::{Disks, System}; mod get_info; pub mod resource_threshold; -pub mod alert_formatter; #[derive(Debug, Clone)] pub struct ThresholdViolation { @@ -20,6 +19,15 @@ pub enum Severity { Critical, } +impl fmt::Display for Severity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Severity::Warning => write!(f, "Warning"), + Severity::Critical => write!(f, "Critical"), + } + } +} + pub struct SystemMonitor { pub system: System, pub disks: Disks, diff --git a/src/actors/driven/for_formatting_message/alert_formatter.rs b/src/actors/driven/for_formatting_message/alert_formatter.rs new file mode 100644 index 0000000..bdd55fc --- /dev/null +++ b/src/actors/driven/for_formatting_message/alert_formatter.rs @@ -0,0 +1,56 @@ +use std::collections::HashMap; + +use crate::app::ports::driven::{ForFormattingMessage, ForGettingViolationData}; + +pub struct AlertFormatter; + +impl AlertFormatter { + fn get_message_for_metric(&self, metric: &str, level: &str) -> String { + match (metric, level) { + ("CPU", "AVERTISSEMENT") => "Utilisation CPU élevée détectée".to_string(), + ("CPU", "CRITIQUE") => "CPU trop sollicité - Intervention requise !".to_string(), + ("Memory", "AVERTISSEMENT") => "Utilisation mémoire élevée".to_string(), + ("Memory", "CRITIQUE") => "Mémoire saturée - Risque de crash !".to_string(), + ("Swap", "AVERTISSEMENT") => "Utilisation du swap élevé".to_string(), + ("Swap", "CRITIQUE") => "Swap saturé - Performance dégradée !".to_string(), + ("Disk", "AVERTISSEMENT") => "Espace disque faible".to_string(), + ("Disk", "CRITIQUE") => "Disque presque plein - Nettoyage urgent !".to_string(), + (metric, _) => format!("Problème de niveau '{}' détecté sur {}", level, metric), + } + } +} + +impl ForFormattingMessage for AlertFormatter { + fn format_violation(&self, violation: Box) -> String { + let (emoji, level) = if violation.is_critical() { + ("🚨", "CRITIQUE") + } else { + ("⚠️", "AVERTISSEMENT") + }; + + format!( + "{} **{}** - {}\n\n**Valeur actuelle:** {:.2}%\n**Seuil:** {:.2}%", + emoji, + level, + self.get_message_for_metric(&violation.get_metric_name(), level), + violation.get_metric_value(), + violation.get_threshold() + ) + } + + fn format_summary(&self, metrics: &HashMap) -> String { + let mut result = "📊 **Rapport Système**\n\n```\n".to_string(); + + result.push_str( + &metrics + .iter() + .map(|(key, value)| format!("{}: {:.1}%", key, value)) + .collect::>() + .join("\n"), + ); + + result.push_str("\n```\n\n*Surveillance automatique*"); + + result + } +} diff --git a/src/adapters/driven/for_getting_violation_data.rs b/src/adapters/driven/for_getting_violation_data.rs new file mode 100644 index 0000000..d3e8f43 --- /dev/null +++ b/src/adapters/driven/for_getting_violation_data.rs @@ -0,0 +1 @@ +pub mod violation; diff --git a/src/adapters/driven/for_getting_violation_data/violation.rs b/src/adapters/driven/for_getting_violation_data/violation.rs new file mode 100644 index 0000000..11181e9 --- /dev/null +++ b/src/adapters/driven/for_getting_violation_data/violation.rs @@ -0,0 +1,35 @@ +pub struct Violation { + name: String, + is_critical: bool, + metric_value: f32, + threshold: f32, +} + +impl Violation { + pub fn new(name: String, is_critical: bool, metric_value: f32, threshold: f32) -> Self { + Violation { + name, + is_critical, + metric_value, + threshold, + } + } +} + +impl crate::app::ports::driven::ForGettingViolationData for Violation { + fn get_metric_name(&self) -> String { + self.name.clone() + } + + fn is_critical(&self) -> bool { + self.is_critical + } + + fn get_metric_value(&self) -> f32 { + self.metric_value + } + + fn get_threshold(&self) -> f32 { + self.threshold + } +} diff --git a/src/adapters/driven/for_monitoring_system.rs b/src/adapters/driven/for_monitoring_system.rs new file mode 100644 index 0000000..1a45d7e --- /dev/null +++ b/src/adapters/driven/for_monitoring_system.rs @@ -0,0 +1 @@ +pub mod system_monitor; diff --git a/src/adapters/driven/for_monitoring_system/system_monitor.rs b/src/adapters/driven/for_monitoring_system/system_monitor.rs new file mode 100644 index 0000000..ef8b5a4 --- /dev/null +++ b/src/adapters/driven/for_monitoring_system/system_monitor.rs @@ -0,0 +1,40 @@ +use crate::{ + adapters::driven::for_getting_violation_data::violation::Violation, + app::ports::driven::ForMonitoringSystem, +}; + +pub struct SystemMonitorAdapter { + system_monitor: system_monitor::SystemMonitor, +} + +impl SystemMonitorAdapter { + pub fn new(system_monitor: system_monitor::SystemMonitor) -> Self { + SystemMonitorAdapter { system_monitor } + } + + fn threshold_violation_to_for_getting_violation_data( + &self, + threshold_violation: &system_monitor::ThresholdViolation, + ) -> Box { + Box::new(Violation::new( + threshold_violation.metric_name.clone(), + threshold_violation.severity == system_monitor::Severity::Critical, + threshold_violation.current_value, + threshold_violation.threshold, + )) + } +} + +impl ForMonitoringSystem for SystemMonitorAdapter { + fn check_thresholds(&self) -> Vec> { + let thresholds = self.system_monitor.check_thresholds(); + thresholds + .into_iter() + .map(|t| self.threshold_violation_to_for_getting_violation_data(&t)) + .collect() + } + + fn get_metrics(&self) -> std::collections::HashMap { + self.system_monitor.get_metrics() + } +} diff --git a/src/adapters/driven/for_sending_notification.rs b/src/adapters/driven/for_sending_notification.rs new file mode 100644 index 0000000..ad9d442 --- /dev/null +++ b/src/adapters/driven/for_sending_notification.rs @@ -0,0 +1 @@ +pub mod discord_client; diff --git a/src/adapters/driven/for_sending_notification/discord_client.rs b/src/adapters/driven/for_sending_notification/discord_client.rs new file mode 100644 index 0000000..74c6207 --- /dev/null +++ b/src/adapters/driven/for_sending_notification/discord_client.rs @@ -0,0 +1,17 @@ +use crate::app::ports::driven::ForSendingNotification; + +pub struct DiscordAdapter { + discord_client: discord_client::DiscordNotifier, +} + +impl DiscordAdapter { + pub fn new(discord_client: discord_client::DiscordNotifier) -> Self { + DiscordAdapter { discord_client } + } +} + +impl ForSendingNotification for DiscordAdapter { + fn send_notification(&self, message: &str) -> Result<(), Box> { + self.discord_client.send_notification(message) + } +} diff --git a/src/app/ports.rs b/src/app/ports.rs new file mode 100644 index 0000000..a8378da --- /dev/null +++ b/src/app/ports.rs @@ -0,0 +1 @@ +pub mod driven; diff --git a/src/app/ports/driven.rs b/src/app/ports/driven.rs new file mode 100644 index 0000000..ebdb5a5 --- /dev/null +++ b/src/app/ports/driven.rs @@ -0,0 +1,22 @@ +use std::collections::HashMap; + +pub trait ForSendingNotification { + fn send_notification(&self, message: &str) -> Result<(), Box>; +} + +pub trait ForMonitoringSystem { + fn check_thresholds(&self) -> Vec>; + fn get_metrics(&self) -> HashMap; +} + +pub trait ForFormattingMessage { + fn format_violation(&self, violation: Box) -> String; + fn format_summary(&self, metrics: &HashMap) -> String; +} + +pub trait ForGettingViolationData { + fn is_critical(&self) -> bool; + fn get_metric_name(&self) -> String; + fn get_metric_value(&self) -> f32; + fn get_threshold(&self) -> f32; +} diff --git a/src/app/service.rs b/src/app/service.rs index f5e4d37..4f390b8 100644 --- a/src/app/service.rs +++ b/src/app/service.rs @@ -1,15 +1,17 @@ -use discord_client::DiscordNotifier; -use system_monitor::{SystemMonitor, alert_formatter::AlertFormatter}; +use crate::app::ports::driven::{ + ForFormattingMessage, ForMonitoringSystem, ForSendingNotification, +}; + pub struct Service { - notifier: DiscordNotifier, - monitor: SystemMonitor, - formatter: AlertFormatter, + notifier: Box, + monitor: Box, + formatter: Box, } pub fn new( - notifier: DiscordNotifier, - monitor: SystemMonitor, - formatter: AlertFormatter, + notifier: Box, + monitor: Box, + formatter: Box, ) -> Service { Service { notifier, @@ -23,14 +25,14 @@ impl Service { // Check for threshold violations and send alerts let violations = self.monitor.check_thresholds(); for violation in violations { - let message = self.formatter.format_violation(&violation); + let message = self.formatter.format_violation(violation); self.notifier .send_notification(&message) .expect("Failed to send notification"); } // Send a final notification with all system information - let summary = self.formatter.format_summary(&self.monitor); + let summary = self.formatter.format_summary(&self.monitor.get_metrics()); self.notifier .send_notification(&summary) .expect("Failed to send final notification"); diff --git a/src/main.rs b/src/main.rs index 91f44fc..aa441ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,26 @@ use dotenvy::dotenv; use system_monitor::SystemMonitor; mod app { + pub mod ports; pub mod service; } +mod adapters { + pub mod driven { + pub mod for_getting_violation_data; + pub mod for_monitoring_system; + pub mod for_sending_notification; + } +} + +mod actors { + pub mod driven { + pub mod for_formatting_message { + pub mod alert_formatter; + } + } +} + fn main() { dotenv().ok(); @@ -14,12 +31,19 @@ fn main() { "System Monitor".to_string(), "https://cdn.shopify.com/s/files/1/0262/1423/6212/files/Lord_of_the_Rings_eye_of_Sauron_-_Ghtic.com_-_Blog.png?v=1579680018".to_string(), ); - let monitor = SystemMonitor::new(system_monitor::resource_threshold::get_default_resource_thresholds()); - let formatter = system_monitor::alert_formatter::AlertFormatter; + let discord_adapter = + adapters::driven::for_sending_notification::discord_client::DiscordAdapter::new(notifier); + let system_monitor_adapter = + adapters::driven::for_monitoring_system::system_monitor::SystemMonitorAdapter::new(monitor); + let formatter = actors::driven::for_formatting_message::alert_formatter::AlertFormatter; - let service = app::service::new(notifier, monitor, formatter); + let service = app::service::new( + Box::new(discord_adapter), + Box::new(system_monitor_adapter), + Box::new(formatter), + ); service.run(); }