diff options
| author | soryu <soryu@soryu.co> | 2025-12-20 15:36:04 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2025-12-23 14:47:18 +0000 |
| commit | 01088f4f1915e36a7d0d8d8756f62f8207a48911 (patch) | |
| tree | 8fdbba900f3f4bba32bae76e2e0378848a90cf93 /makima/src/server/mod.rs | |
| parent | ab9166170043ba5e0ce974e5b7accf0939d686e3 (diff) | |
| download | soryu-01088f4f1915e36a7d0d8d8756f62f8207a48911.tar.gz soryu-01088f4f1915e36a7d0d8d8756f62f8207a48911.zip | |
Implement makima listen websockets server
Diffstat (limited to 'makima/src/server/mod.rs')
| -rw-r--r-- | makima/src/server/mod.rs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/makima/src/server/mod.rs b/makima/src/server/mod.rs new file mode 100644 index 0000000..c33eeef --- /dev/null +++ b/makima/src/server/mod.rs @@ -0,0 +1,88 @@ +//! Web server module for the makima audio API. + +pub mod handlers; +pub mod messages; +pub mod openapi; +pub mod state; + +use axum::{ + routing::{get, post}, + Router, +}; +use tower_http::cors::{Any, CorsLayer}; +use tower_http::trace::TraceLayer; +use utoipa::OpenApi; +use utoipa_swagger_ui::SwaggerUi; + +use crate::server::handlers::{listen, tts}; +use crate::server::openapi::ApiDoc; +use crate::server::state::SharedState; + +/// Create the axum Router with all routes configured. +pub fn make_router(state: SharedState) -> Router { + // API v1 routes + let api_v1 = Router::new() + .route("/listen", get(listen::websocket_handler)) + .route("/tts/synthesize", post(tts::synthesize_handler)) + .with_state(state); + + let swagger = SwaggerUi::new("/swagger-ui") + .url("/api-docs/openapi.json", ApiDoc::openapi()); + + Router::new() + .nest("/api/v1", api_v1) + .merge(swagger) + .layer( + CorsLayer::new() + .allow_origin(Any) + .allow_methods(Any) + .allow_headers(Any), + ) + .layer(TraceLayer::new_for_http()) +} + +/// Run the HTTP server with graceful shutdown support. +/// +/// # Arguments +/// * `state` - Shared application state containing ML models +/// * `addr` - Address to bind to (e.g., "0.0.0.0:8080") +pub async fn run_server(state: SharedState, addr: &str) -> anyhow::Result<()> { + let app = make_router(state); + let listener = tokio::net::TcpListener::bind(addr).await?; + + tracing::info!("Server listening on {}", addr); + tracing::info!("Swagger UI available at http://{}/swagger-ui", addr); + + axum::serve(listener, app) + .with_graceful_shutdown(shutdown_signal()) + .await?; + + Ok(()) +} + +/// Wait for shutdown signals (Ctrl+C or SIGTERM). +async fn shutdown_signal() { + let ctrl_c = async { + tokio::signal::ctrl_c() + .await + .expect("Failed to install Ctrl+C handler"); + }; + + #[cfg(unix)] + let terminate = async { + tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) + .expect("Failed to install signal handler") + .recv() + .await; + }; + + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); + + tokio::select! { + _ = ctrl_c => {}, + _ = terminate => {}, + } + + tracing::info!("Shutdown signal received, starting graceful shutdown"); +} |
