use std::{process::Command, sync::Arc};
use axum::{
Json, Router,
extract::{Path, State},
routing::get,
};
use serde::{Deserialize, Serialize};
use tokio::net::TcpListener;
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
#[serde(default = "default_webhook_listen_address")]
addr: String,
hooks: Vec<Entry>,
}
fn default_webhook_listen_address() -> String {
format!("0.0.0.0:1234")
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Entry {
path: String,
command: String,
args: Vec<String>,
}
pub async fn run_server(cfg: Config) {
let listener = TcpListener::bind(cfg.addr.clone()).await.unwrap();
let state = Arc::new(cfg);
let app: Router = Router::new()
.route("/{*key}", get(handle_url))
.with_state(state);
axum::serve(listener, app).await.unwrap();
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
enum Response {
Success,
Failed,
}
#[axum::debug_handler]
async fn handle_url(Path(key): Path<String>, State(cfg): State<Arc<Config>>) -> Json<Response> {
if let Some(entry) = cfg.hooks.iter().find(|it| it.path == key) {
println!("Running entry {}", key);
let mut command = Command::new(&entry.command);
command.args(entry.args.iter());
let res = command.status();
match res {
Ok(o) if o.success() => Json(Response::Success),
_ => Json(Response::Failed),
}
} else {
Json(Response::Failed)
}
}