use axum::Json; use axum::extract::State; use axum::http::StatusCode; use axum::response::IntoResponse; use serde::{Deserialize, Serialize}; use serde_json::{Value, from_value}; use std::sync::Arc; use tracing::warn; use crate::commands::NginxService; #[derive(Serialize, utoipa::ToSchema)] pub struct StatusResp { pub ok: bool, } /// Health check endpoint #[utoipa::path( get, path = "/status", responses( (status = 200, description = "Status response", body = StatusResp) ), tag = crate::openapi::tag::NGINX_TAG )] pub async fn status() -> impl IntoResponse { let resp = StatusResp { ok: true }; (axum::http::StatusCode::OK, axum::Json(resp)) } #[derive(Serialize, utoipa::ToSchema)] pub struct ValidateAndReloadResp { pub rc: i32, pub ro: String, } #[derive(Deserialize, utoipa::ToSchema)] pub struct ValidateBody { config_name: String, timestamp: u64, } #[utoipa::path( post, path = "/validate", request_body = ValidateBody, responses( (status = 200, description = "Validation response", body = serde_json::Value) ), tag = crate::openapi::tag::NGINX_TAG )] pub async fn validate( State(nginx_controller): State>, Json(payload): Json, ) -> impl IntoResponse { let params: ValidateBody = match from_value(payload) { Ok(req) => req, Err(e) => { warn!("Invalid validate request: {}", e); return (StatusCode::BAD_REQUEST).into_response(); } }; let resp = match nginx_controller .validate(¶ms.config_name, params.timestamp) .await { Ok(res) => res, Err(e) => { let resp = serde_json::json!({ "error": e.to_string() }); return (StatusCode::INTERNAL_SERVER_ERROR, axum::Json(resp)).into_response(); } }; (axum::http::StatusCode::OK, axum::Json(resp)).into_response() } #[derive(Deserialize, utoipa::ToSchema)] pub struct ValidateAndReloadBody { config_name: String, timestamp: u64, } #[utoipa::path( post, path = "/validate_and_reload", request_body = ValidateAndReloadBody, responses( (status = 200, description = "Validate and reload response", body = ValidateAndReloadResp) ), tag = crate::openapi::tag::NGINX_TAG )] pub async fn validate_and_reload( State(nginx_controller): State>, Json(payload): Json, ) -> impl IntoResponse { let params: ValidateAndReloadBody = match from_value(payload) { Ok(req) => req, Err(e) => { warn!("Invalid validate_and_reload request: {}", e); return (StatusCode::BAD_REQUEST).into_response(); } }; let (code, output) = match nginx_controller .validate_and_reload(¶ms.config_name, params.timestamp) .await { Ok(res) => res, Err(e) => { let resp = ValidateAndReloadResp { rc: -1, ro: e.to_string(), }; return (StatusCode::INTERNAL_SERVER_ERROR, axum::Json(resp)).into_response(); } }; let resp = ValidateAndReloadResp { rc: code, ro: output, }; (axum::http::StatusCode::OK, axum::Json(resp)).into_response() } #[derive(Deserialize, utoipa::ToSchema)] pub struct WriteConfigBody { config_name: String, timestamp: u64, content: String, } #[utoipa::path( post, path = "/write_config", request_body = WriteConfigBody, responses( (status = 200, description = "Write config response"), (status = 500, description = "Internal server error", body = serde_json::Value) ), tag = crate::openapi::tag::NGINX_TAG )] pub async fn write_config( State(nginx_controller): State>, Json(payload): Json, ) -> impl IntoResponse { let body: WriteConfigBody = match from_value(payload) { Ok(req) => req, Err(e) => { warn!("Invalid write_config request: {}", e); return (StatusCode::BAD_REQUEST).into_response(); } }; match nginx_controller .write_config(&body.config_name, body.timestamp, &body.content) .await { Ok(_) => (), Err(e) => { let resp = serde_json::json!({ "error": e.to_string() }); return (StatusCode::INTERNAL_SERVER_ERROR, axum::Json(resp)).into_response(); } }; (axum::http::StatusCode::OK,).into_response() }