spawn_access_control/notification/
slack.rs1use reqwest::Client;
2use serde_json::json;
3use crate::alert_system::{
4 NotificationHandler,
5 NotificationError,
6 AlertNotification,
7 AlertSeverity,
8 EscalationLevel
9};
10use async_trait::async_trait;
11
12#[derive(Clone)]
13pub struct SlackNotificationHandler {
14 client: reqwest::Client,
15 config: SlackConfig,
16}
17
18#[derive(Clone)]
19pub struct SlackConfig {
20 pub webhook_url: String,
21 pub default_channel: String,
22 pub emergency_channel: String,
23 pub username: String,
24 pub icon_emoji: String,
25}
26
27impl SlackNotificationHandler {
28 pub fn new(config: SlackConfig) -> Self {
29 Self {
30 client: Client::new(),
31 config,
32 }
33 }
34
35 fn create_slack_message(&self, notification: &AlertNotification) -> serde_json::Value {
36 let severity = AlertSeverity::from(¬ification.alert.severity);
37 let color = match severity {
38 AlertSeverity::Critical => "#ff0000",
39 AlertSeverity::Warning => "#ffa500",
40 AlertSeverity::Info => "#0000ff",
41 };
42
43 json!({
44 "username": self.config.username,
45 "icon_emoji": self.config.icon_emoji,
46 "channel": if notification.escalation_level == EscalationLevel::Critical {
47 self.config.emergency_channel.clone()
48 } else {
49 self.config.default_channel.clone()
50 },
51 "attachments": [{
52 "color": color,
53 "title": format!("Alert: {}", notification.alert.message),
54 "fields": [
55 {
56 "title": "Severity",
57 "value": format!("{:?}", notification.alert.severity),
58 "short": true
59 },
60 {
61 "title": "Metric",
62 "value": notification.alert.metric_name,
63 "short": true
64 },
65 {
66 "title": "Current Value",
67 "value": notification.alert.current_value.to_string(),
68 "short": true
69 },
70 {
71 "title": "Threshold",
72 "value": notification.alert.threshold.to_string(),
73 "short": true
74 },
75 {
76 "title": "Incident ID",
77 "value": notification.context.incident_id,
78 "short": true
79 }
80 ],
81 "footer": format!("Alert generated at {}", notification.context.created_at.to_rfc3339())
82 }]
83 })
84 }
85}
86
87#[async_trait]
88impl NotificationHandler for SlackNotificationHandler {
89 async fn send_notification(&self, notification: &AlertNotification) -> Result<(), NotificationError> {
90 let payload = self.create_slack_message(notification);
91
92 let response = self.client
93 .post(&self.config.webhook_url)
94 .json(&payload)
95 .send()
96 .await
97 .map_err(|e| NotificationError::SendError(e.to_string()))?;
98
99 if !response.status().is_success() {
100 return Err(NotificationError::SendError(
101 format!("Slack API error: {}", response.status())
102 ));
103 }
104
105 Ok(())
106 }
107}