ruvector_scipix/api/
mod.rs1pub mod handlers;
2pub mod jobs;
3pub mod middleware;
4pub mod requests;
5pub mod responses;
6pub mod routes;
7pub mod state;
8
9use anyhow::Result;
10use axum::Router;
11use std::net::SocketAddr;
12use tokio::signal;
13use tracing::{info, warn};
14
15use self::state::AppState;
16
17pub struct ApiServer {
19 state: AppState,
20 addr: SocketAddr,
21}
22
23impl ApiServer {
24 pub fn new(state: AppState, addr: SocketAddr) -> Self {
26 Self { state, addr }
27 }
28
29 pub async fn start(self) -> Result<()> {
31 let app = self.create_router();
32
33 info!("Starting Scipix API server on {}", self.addr);
34
35 let listener = tokio::net::TcpListener::bind(self.addr).await?;
36
37 axum::serve(listener, app)
38 .with_graceful_shutdown(shutdown_signal())
39 .await?;
40
41 info!("Server shutdown complete");
42 Ok(())
43 }
44
45 fn create_router(&self) -> Router {
47 routes::router(self.state.clone())
48 }
49}
50
51async fn shutdown_signal() {
53 let ctrl_c = async {
54 signal::ctrl_c()
55 .await
56 .expect("failed to install Ctrl+C handler");
57 };
58
59 #[cfg(unix)]
60 let terminate = async {
61 signal::unix::signal(signal::unix::SignalKind::terminate())
62 .expect("failed to install signal handler")
63 .recv()
64 .await;
65 };
66
67 #[cfg(not(unix))]
68 let terminate = std::future::pending::<()>();
69
70 tokio::select! {
71 _ = ctrl_c => {
72 warn!("Received Ctrl+C, shutting down...");
73 },
74 _ = terminate => {
75 warn!("Received terminate signal, shutting down...");
76 },
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[tokio::test]
85 async fn test_server_creation() {
86 let state = AppState::new();
87 let addr = "127.0.0.1:3000".parse().unwrap();
88 let server = ApiServer::new(state, addr);
89 assert_eq!(server.addr, addr);
90 }
91}