use crate::{HttpConfig, HttpError, HttpResult};
use elif_core::Container;
use axum::{
Router,
routing::get,
response::Json,
};
use serde_json::{json, Value};
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::signal;
use tracing::info;
pub struct MinimalHttpServer {
addr: SocketAddr,
}
impl MinimalHttpServer {
pub fn new(container: Arc<Container>, config: HttpConfig) -> HttpResult<Self> {
let app_config = container.config();
let addr = format!("{}:{}", app_config.server.host, app_config.server.port)
.parse::<SocketAddr>()
.map_err(|e| HttpError::config(format!("Invalid server address: {}", e)))?;
Ok(Self { addr })
}
pub async fn run(self) -> HttpResult<()> {
info!("Starting minimal HTTP server on {}", self.addr);
let router = Router::new()
.route("/health", get(minimal_health_check));
let listener = tokio::net::TcpListener::bind(self.addr)
.await
.map_err(|e| HttpError::startup(format!("Failed to bind to {}: {}", self.addr, e)))?;
info!("Minimal HTTP server listening on {}", self.addr);
axum::serve(listener, router)
.with_graceful_shutdown(minimal_shutdown_signal())
.await
.map_err(|e| HttpError::startup(format!("Server failed: {}", e)))?;
info!("Minimal HTTP server stopped gracefully");
Ok(())
}
}
pub async fn minimal_health_check() -> Json<Value> {
Json(json!({
"status": "healthy",
"timestamp": chrono::Utc::now().to_rfc3339(),
"version": "0.1.0",
"server": "minimal"
}))
}
async fn minimal_shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {
info!("Received Ctrl+C, initiating graceful shutdown");
},
_ = terminate => {
info!("Received terminate signal, initiating graceful shutdown");
},
}
}