use async_trait::async_trait;
use std::collections::HashMap;
use std::time::Duration;
use super::alert::{AuditAlertEvent, AuditAlertHook};
pub struct WebhookAlertHook {
client: reqwest::Client,
url: String,
headers: HashMap<String, String>,
}
impl WebhookAlertHook {
pub fn new(url: String, timeout: Duration, headers: HashMap<String, String>) -> Self {
let client = reqwest::Client::builder()
.timeout(timeout)
.build()
.unwrap_or_default();
Self {
client,
url,
headers,
}
}
}
#[async_trait]
impl AuditAlertHook for WebhookAlertHook {
async fn on_alert(&self, event: AuditAlertEvent) {
let mut request = self.client.post(&self.url).json(&event);
for (key, value) in &self.headers {
request = request.header(key.as_str(), value.as_str());
}
match request.send().await {
Ok(response) => {
if !response.status().is_success() {
tracing::warn!(
url = %self.url,
status = %response.status(),
"Audit alert webhook returned non-success status"
);
}
}
Err(e) => {
tracing::warn!(
url = %self.url,
error = %e,
"Failed to send audit alert webhook"
);
}
}
}
}