use std::net::SocketAddr; use askama::Template; use axum::{ extract::State, routing::post, http::StatusCode, response::{IntoResponse, Response}, Json, Router, }; use serde::Deserialize; mod jabber; mod prometheus_alert; enum Payload { Prometheus(prometheus_alert::Payload), } impl Payload { fn render(&self) -> Result { match self { Payload::Prometheus(payload) => payload.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 alerts( State(jabber): State, Json(payload): Json, ) -> Response { Payload::Prometheus(payload) .handle_payload(jabber) .await } #[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(alerts)) .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(); }