Skip to main content

fukurow_api/
server.rs

1//! HTTP server implementation
2
3use axum::{serve, Router};
4use std::net::SocketAddr;
5use std::time::Instant;
6use tokio::net::TcpListener;
7use tracing::{info, error};
8
9use crate::{routes::create_router, handlers::AppState};
10use fukurow_engine::ReasonerEngine;
11use fukurow_domain_cyber::threat_intelligence::ThreatProcessor;
12
13/// Server configuration
14#[derive(Debug, Clone)]
15pub struct ServerConfig {
16    pub host: String,
17    pub port: u16,
18    pub max_connections: usize,
19}
20
21impl Default for ServerConfig {
22    fn default() -> Self {
23        Self {
24            host: "0.0.0.0".to_string(),
25            port: 3000,
26            max_connections: 100,
27        }
28    }
29}
30
31/// Reasoner API server
32pub struct ReasonerServer {
33    config: ServerConfig,
34    app_state: AppState,
35}
36
37impl ReasonerServer {
38    /// Create new server with default configuration
39    pub fn new() -> Self {
40        Self::with_config(ServerConfig::default())
41    }
42
43    /// Create new server with custom configuration
44    pub fn with_config(config: ServerConfig) -> Self {
45        let reasoner = ReasonerEngine::new();
46        let threat_processor = ThreatProcessor::new();
47
48        // Initialize reasoner with default cyber security rules
49        // TODO: Implement rule initialization for new fukurow architecture
50
51        let app_state = AppState {
52            reasoner: std::sync::Arc::new(reasoner),
53            threat_processor: std::sync::Arc::new(tokio::sync::RwLock::new(threat_processor)),
54            start_time: Instant::now(),
55        };
56
57        Self { config, app_state }
58    }
59
60    /// Get the server address
61    pub fn address(&self) -> SocketAddr {
62        format!("{}:{}", self.config.host, self.config.port)
63            .parse()
64            .expect("Invalid server address")
65    }
66
67    /// Create the application router
68    pub fn create_app(&self) -> Router {
69        create_router(self.app_state.clone())
70    }
71
72    /// Start the server
73    pub async fn serve(self) -> anyhow::Result<()> {
74        let addr = self.address();
75        let app = self.create_app();
76
77        info!("Starting Reasoner API server on {}", addr);
78
79        let listener = TcpListener::bind(addr).await?;
80        info!("Server listening on {}", addr);
81
82        serve(listener, app)
83            .await
84            .map_err(|e| {
85                error!("Server error: {}", e);
86                e.into()
87            })
88    }
89
90    /// Run the server with graceful shutdown
91    pub async fn run_with_shutdown(self, shutdown_signal: impl std::future::Future<Output = ()> + Send + 'static) -> anyhow::Result<()> {
92        let addr = self.address();
93        let app = self.create_app();
94
95        info!("Starting Reasoner API server on {} with graceful shutdown", addr);
96
97        let listener = TcpListener::bind(addr).await?;
98        info!("Server listening on {}", addr);
99
100        let server = serve(listener, app);
101        let graceful = server.with_graceful_shutdown(shutdown_signal);
102
103        // Note: Axum's WithGracefulShutdown doesn't implement Future directly
104        // This is a simplified version - in production, use proper graceful shutdown
105        graceful.await.map_err(|e| {
106            error!("Server error: {}", e);
107            e.into()
108        })
109    }
110}
111
112impl Default for ReasonerServer {
113    fn default() -> Self {
114        Self::new()
115    }
116}
117
118/// Create a server with custom reasoner engine
119pub fn create_server_with_reasoner(reasoner: ReasonerEngine, config: ServerConfig) -> ReasonerServer {
120    let threat_processor = ThreatProcessor::new();
121
122    let app_state = AppState {
123        reasoner: std::sync::Arc::new(reasoner),
124        threat_processor: std::sync::Arc::new(tokio::sync::RwLock::new(threat_processor)),
125        start_time: Instant::now(),
126    };
127
128    ReasonerServer { config, app_state }
129}
130
131/// Utility function to create a shutdown signal
132pub async fn shutdown_signal() {
133    use tokio::signal;
134
135    let ctrl_c = async {
136        signal::ctrl_c()
137            .await
138            .expect("failed to install Ctrl+C handler");
139    };
140
141    #[cfg(unix)]
142    let terminate = async {
143        signal::unix::signal(signal::unix::SignalKind::terminate())
144            .expect("failed to install signal handler")
145            .recv()
146            .await;
147    };
148
149    #[cfg(not(unix))]
150    let terminate = std::future::pending::<()>();
151
152    tokio::select! {
153        _ = ctrl_c => {},
154        _ = terminate => {},
155    }
156
157    info!("Shutdown signal received, starting graceful shutdown...");
158}