refactor(app): implement ports & adapters
* also move alertFormatter into internal actor
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
56
src/actors/driven/for_formatting_message/alert_formatter.rs
Normal file
56
src/actors/driven/for_formatting_message/alert_formatter.rs
Normal file
@@ -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<dyn ForGettingViolationData>) -> 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, f32>) -> 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::<Vec<_>>()
|
||||
.join("\n"),
|
||||
);
|
||||
|
||||
result.push_str("\n```\n\n*Surveillance automatique*");
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
1
src/adapters/driven/for_getting_violation_data.rs
Normal file
1
src/adapters/driven/for_getting_violation_data.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod violation;
|
||||
35
src/adapters/driven/for_getting_violation_data/violation.rs
Normal file
35
src/adapters/driven/for_getting_violation_data/violation.rs
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
1
src/adapters/driven/for_monitoring_system.rs
Normal file
1
src/adapters/driven/for_monitoring_system.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod system_monitor;
|
||||
40
src/adapters/driven/for_monitoring_system/system_monitor.rs
Normal file
40
src/adapters/driven/for_monitoring_system/system_monitor.rs
Normal file
@@ -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<dyn crate::app::ports::driven::ForGettingViolationData> {
|
||||
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<Box<dyn crate::app::ports::driven::ForGettingViolationData>> {
|
||||
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<String, f32> {
|
||||
self.system_monitor.get_metrics()
|
||||
}
|
||||
}
|
||||
1
src/adapters/driven/for_sending_notification.rs
Normal file
1
src/adapters/driven/for_sending_notification.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod discord_client;
|
||||
@@ -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<dyn std::error::Error>> {
|
||||
self.discord_client.send_notification(message)
|
||||
}
|
||||
}
|
||||
1
src/app/ports.rs
Normal file
1
src/app/ports.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod driven;
|
||||
22
src/app/ports/driven.rs
Normal file
22
src/app/ports/driven.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub trait ForSendingNotification {
|
||||
fn send_notification(&self, message: &str) -> Result<(), Box<dyn std::error::Error>>;
|
||||
}
|
||||
|
||||
pub trait ForMonitoringSystem {
|
||||
fn check_thresholds(&self) -> Vec<Box<dyn ForGettingViolationData>>;
|
||||
fn get_metrics(&self) -> HashMap<String, f32>;
|
||||
}
|
||||
|
||||
pub trait ForFormattingMessage {
|
||||
fn format_violation(&self, violation: Box<dyn ForGettingViolationData>) -> String;
|
||||
fn format_summary(&self, metrics: &HashMap<String, f32>) -> 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;
|
||||
}
|
||||
@@ -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<dyn ForSendingNotification>,
|
||||
monitor: Box<dyn ForMonitoringSystem>,
|
||||
formatter: Box<dyn ForFormattingMessage>,
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
notifier: DiscordNotifier,
|
||||
monitor: SystemMonitor,
|
||||
formatter: AlertFormatter,
|
||||
notifier: Box<dyn ForSendingNotification>,
|
||||
monitor: Box<dyn ForMonitoringSystem>,
|
||||
formatter: Box<dyn ForFormattingMessage>,
|
||||
) -> 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");
|
||||
|
||||
30
src/main.rs
30
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user