use std::{ net::SocketAddr, collections::HashMap, sync::{Arc, Mutex}, }; use axum::{ extract::State, routing::post, http::StatusCode, response::{IntoResponse, Response}, Json, Router, }; use serde::Deserialize; mod jabber; #[derive(Deserialize, Clone, Debug)] struct Alert { generatorURL: String, startsAt: String, annotations: AlertAnnotations, labels: HashMap, } #[derive(Deserialize, Clone, Debug)] struct AlertAnnotations { summary: String, } #[derive(Clone)] struct AppState { jabber: jabber::Handle, alerts: Arc>>, } async fn alerts( State(state): State, Json(payload): Json>, ) -> Response { let mut message = "".to_string(); let mut alerts = state.alerts.lock().unwrap(); for alert in payload.into_iter() { let is_old = if let Some(old_alert) = alerts.get(&alert.generatorURL) { old_alert.startsAt == alert.startsAt } else { false }; if ! is_old { if message != "" { message += "\n"; } message += &format!("{}: {}", alert.annotations.summary, alert.generatorURL); alerts.insert(alert.generatorURL.clone(), alert); } } drop(alerts); if message != "" { let jabber = state.jabber.clone(); tokio::spawn(async move { jabber.send_message(message).await; }); } StatusCode::OK.into_response() } #[tokio::main] async fn main() { // initialize tracing tracing_subscriber::fmt::init(); let jabber = jabber::run(/*secret*/).await; let state = AppState { jabber, alerts: Arc::new(Mutex::new(HashMap::new())), }; // build our application with a route let app = Router::new() .route("/", post(alerts)) .with_state(state); let addr = SocketAddr::from(([127, 0, 0, 1], 9022)); tracing::debug!("listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); }