use reqwest::Client;
use serde_json::json;
use crate::alert_system::{
NotificationHandler,
NotificationError,
AlertNotification,
AlertSeverity,
EscalationLevel
};
use async_trait::async_trait;
#[derive(Clone)]
pub struct SlackNotificationHandler {
client: reqwest::Client,
config: SlackConfig,
}
#[derive(Clone)]
pub struct SlackConfig {
pub webhook_url: String,
pub default_channel: String,
pub emergency_channel: String,
pub username: String,
pub icon_emoji: String,
}
impl SlackNotificationHandler {
pub fn new(config: SlackConfig) -> Self {
Self {
client: Client::new(),
config,
}
}
fn create_slack_message(&self, notification: &AlertNotification) -> serde_json::Value {
let severity = AlertSeverity::from(¬ification.alert.severity);
let color = match severity {
AlertSeverity::Critical => "#ff0000",
AlertSeverity::Warning => "#ffa500",
AlertSeverity::Info => "#0000ff",
};
json!({
"username": self.config.username,
"icon_emoji": self.config.icon_emoji,
"channel": if notification.escalation_level == EscalationLevel::Critical {
self.config.emergency_channel.clone()
} else {
self.config.default_channel.clone()
},
"attachments": [{
"color": color,
"title": format!("Alert: {}", notification.alert.message),
"fields": [
{
"title": "Severity",
"value": format!("{:?}", notification.alert.severity),
"short": true
},
{
"title": "Metric",
"value": notification.alert.metric_name,
"short": true
},
{
"title": "Current Value",
"value": notification.alert.current_value.to_string(),
"short": true
},
{
"title": "Threshold",
"value": notification.alert.threshold.to_string(),
"short": true
},
{
"title": "Incident ID",
"value": notification.context.incident_id,
"short": true
}
],
"footer": format!("Alert generated at {}", notification.context.created_at.to_rfc3339())
}]
})
}
}
#[async_trait]
impl NotificationHandler for SlackNotificationHandler {
async fn send_notification(&self, notification: &AlertNotification) -> Result<(), NotificationError> {
let payload = self.create_slack_message(notification);
let response = self.client
.post(&self.config.webhook_url)
.json(&payload)
.send()
.await
.map_err(|e| NotificationError::SendError(e.to_string()))?;
if !response.status().is_success() {
return Err(NotificationError::SendError(
format!("Slack API error: {}", response.status())
));
}
Ok(())
}
}