use crate::monitoring::types::{AlertRuleKind, FiredAlert}; use crate::webhooks::{self, WebhookEvent, WebhookPayload}; use std::path::Path; use std::sync::Arc; use tracing::info; /// Push fired alerts as notifications to the state manager (broadcast via WebSocket). pub(crate) async fn push_alert_notifications( state_mgr: &Arc, alerts: &[FiredAlert], ) { let (mut data, _rev) = state_mgr.get_snapshot().await; for alert in alerts { let level = match alert.kind { AlertRuleKind::DiskUsage | AlertRuleKind::RamUsage => { if alert.value > 95.0 { crate::data_model::NotificationLevel::Error } else { crate::data_model::NotificationLevel::Warning } } AlertRuleKind::ContainerCrash => crate::data_model::NotificationLevel::Error, _ => crate::data_model::NotificationLevel::Warning, }; let notification = crate::data_model::Notification { id: alert.id.clone(), level, title: format!("{:?} Alert", alert.kind), message: alert.message.clone(), timestamp: chrono::Utc::now().to_rfc3339(), app_id: None, }; data.notifications.push(notification); } // Keep max 20 notifications while data.notifications.len() > 20 { data.notifications.remove(0); } state_mgr.update_data(data).await; info!("Fired {} alert(s)", alerts.len()); } /// Deliver webhook notifications for alerts that map to webhook events. pub(crate) async fn deliver_alert_webhooks(data_dir: &Path, alerts: &[FiredAlert]) { for alert in alerts { let event = match alert.kind { AlertRuleKind::DiskUsage => Some(WebhookEvent::DiskWarning), AlertRuleKind::ContainerCrash => Some(WebhookEvent::ContainerCrash), _ => None, }; if let Some(event) = event { let payload = WebhookPayload { event, title: format!("{:?} Alert", alert.kind), message: alert.message.clone(), timestamp: chrono::Utc::now().to_rfc3339(), node_id: String::new(), details: Some(serde_json::json!({ "value": alert.value, "threshold": alert.threshold, })), }; webhooks::send_webhook(data_dir, payload).await; } } }