use std::net::SocketAddr; use askama::Template; use axum::{ extract::State, routing::{get, post}, http::StatusCode, response::{IntoResponse, Response}, Json, Router, }; use serde::Deserialize; mod jabber; mod prometheus_alert; mod apprise_notify; enum Payload { Prometheus(prometheus_alert::Payload), Apprise(apprise_notify::Notification), } impl Payload { fn render(&self) -> Result { match self { Payload::Prometheus(payload) => payload.render(), Payload::Apprise(notification) => notification.render(), } } async fn handle_payload(&self, jabber: jabber::Handle) -> Response { let mut error_message = None; match self.render() { Ok(message) => { jabber.send_message(message).await; } Err(e) => { error_message = Some(format!("{}", e)); } } match error_message { None => StatusCode::OK.into_response(), Some(error_message) => (StatusCode::INTERNAL_SERVER_ERROR, error_message ).into_response() } } } async fn prometheus_alerts( State(jabber): State, Json(payload): Json, ) -> Response { Payload::Prometheus(payload) .handle_payload(jabber) .await } async fn apprise_notification( State(jabber): State, Json(notification): Json, ) -> Response { Payload::Apprise(notification) .handle_payload(jabber) .await } async fn apprise_ok( ) -> Response { ([("content-type", "application/json")], "{}") .into_response() } #[derive(Deserialize)] struct Config { listen_port: u16, jid: String, password: String, muc: String, } #[tokio::main] async fn main() { // initialize tracing tracing_subscriber::fmt::init(); let config: Config = serde_json::from_str( &std::fs::read_to_string( std::env::args().nth(1) .expect("Call with config.json") ).expect("read config") ).expect("parse config"); let jabber = jabber::run(config.jid, config.password, config.muc).await; // build our application with a route let app = Router::new() .route("/alert", post(prometheus_alerts)) .route("/api/v2/alerts", post(prometheus_alerts)) .route("/notify", get(apprise_ok).post(apprise_notification)) .with_state(jabber); let addr = SocketAddr::from(([127, 0, 0, 1], config.listen_port)); tracing::debug!("listening on {}", addr); let server = axum::Server::bind(&addr) .serve(app.into_make_service()); systemd::daemon::notify(false, [(systemd::daemon::STATE_READY, "1")].iter()) .unwrap(); server.await .unwrap(); }