use super::Alert;
use crate::error::Result;
use parking_lot::RwLock;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum Destination {
Email {
addresses: Vec<String>,
},
Webhook {
url: String,
},
PagerDuty {
service_key: String,
},
Slack {
webhook_url: String,
},
}
pub struct Route {
pub matcher: Box<dyn Fn(&Alert) -> bool + Send + Sync>,
pub destinations: Vec<Destination>,
}
pub struct AlertRouter {
routes: Arc<RwLock<Vec<Route>>>,
client: reqwest::Client,
}
impl AlertRouter {
pub fn new() -> Self {
Self {
routes: Arc::new(RwLock::new(Vec::new())),
client: reqwest::Client::new(),
}
}
pub fn add_route(&mut self, route: Route) {
self.routes.write().push(route);
}
pub async fn route(&self, alert: &Alert) -> Result<()> {
let destinations: Vec<Destination> = {
let routes = self.routes.read();
routes
.iter()
.filter(|route| (route.matcher)(alert))
.flat_map(|route| route.destinations.iter().cloned())
.collect()
};
for destination in &destinations {
self.send_to_destination(alert, destination).await?;
}
Ok(())
}
async fn send_to_destination(&self, alert: &Alert, destination: &Destination) -> Result<()> {
match destination {
Destination::Webhook { url } => {
let _ = self.client.post(url).json(alert).send().await?;
}
Destination::Slack { webhook_url } => {
let payload = serde_json::json!({
"text": format!("{}: {}", alert.name, alert.message),
});
let _ = self.client.post(webhook_url).json(&payload).send().await?;
}
Destination::Email { .. } | Destination::PagerDuty { .. } => {
}
}
Ok(())
}
}
impl Default for AlertRouter {
fn default() -> Self {
Self::new()
}
}