elif_http/
server_with_middleware.rs

1//! # HTTP Server with Middleware Support
2//!
3//! Enhanced HTTP server that demonstrates middleware pipeline integration.
4
5use std::sync::Arc;
6use axum::{
7    Router,
8    routing::get,
9    response::Json,
10};
11use serde_json::{json, Value};
12use tokio::signal;
13use tracing::info;
14use elif_core::Container;
15
16use crate::{
17    HttpConfig, HttpError, HttpResult,
18    MiddlewarePipeline, LoggingMiddleware, TimingMiddleware,
19};
20
21/// HTTP server with middleware support
22pub struct MiddlewareHttpServer {
23    container: Arc<Container>,
24    config: HttpConfig,
25    middleware: MiddlewarePipeline,
26}
27
28impl MiddlewareHttpServer {
29    /// Create new server with default middleware
30    pub fn new(container: Arc<Container>, config: HttpConfig) -> HttpResult<Self> {
31        let server = Self {
32            container,
33            config,
34            middleware: MiddlewarePipeline::new(),
35        };
36        
37        Ok(server)
38    }
39    
40    /// Create server with custom middleware pipeline
41    pub fn with_middleware(
42        container: Arc<Container>, 
43        config: HttpConfig,
44        middleware: MiddlewarePipeline
45    ) -> HttpResult<Self> {
46        Ok(Self {
47            container,
48            config,
49            middleware,
50        })
51    }
52    
53    /// Add default middleware (logging + timing)
54    pub fn with_default_middleware(mut self) -> Self {
55        self.middleware = self.middleware
56            .add(LoggingMiddleware::new())
57            .add(TimingMiddleware::new());
58        self
59    }
60    
61    /// Get reference to middleware pipeline
62    pub fn middleware(&self) -> &MiddlewarePipeline {
63        &self.middleware
64    }
65    
66    /// Get mutable reference to middleware pipeline
67    pub fn middleware_mut(&mut self) -> &mut MiddlewarePipeline {
68        &mut self.middleware
69    }
70    
71    /// Start the server
72    pub async fn run(&self) -> HttpResult<()> {
73        let addr = "127.0.0.1:3000".to_string(); // Default address
74        
75        // Create router with middleware-aware handlers
76        let router = Router::new()
77            .route("/health", get(middleware_health_check))
78            .route("/middleware/info", get(middleware_info_handler))
79            .with_state((self.container.clone(), self.middleware.len()));
80
81        let listener = tokio::net::TcpListener::bind(&addr)
82            .await
83            .map_err(|e| HttpError::startup(format!("Failed to bind to {}: {}", addr, e)))?;
84
85        info!("HTTP server with middleware listening on {}", addr);
86        info!("Middleware pipeline: {:?}", self.middleware.names());
87
88        axum::serve(listener, router)
89            .with_graceful_shutdown(shutdown_signal())
90            .await
91            .map_err(|e| HttpError::startup(format!("Server failed: {}", e)))?;
92
93        info!("HTTP server stopped gracefully");
94        Ok(())
95    }
96}
97
98/// Health check endpoint that can be enhanced with middleware
99pub async fn middleware_health_check() -> Json<Value> {
100    Json(json!({
101        "status": "healthy",
102        "timestamp": chrono::Utc::now().to_rfc3339(),
103        "version": "0.1.0",
104        "server": "middleware-enabled",
105        "middleware": "active"
106    }))
107}
108
109/// Endpoint that provides middleware information
110pub async fn middleware_info_handler(
111    axum::extract::State((container, middleware_count)): axum::extract::State<(Arc<Container>, usize)>
112) -> Json<Value> {
113    Json(json!({
114        "middleware_count": middleware_count,
115        "container_registered": true, // container.services().len(), - method doesn't exist yet
116        "timestamp": chrono::Utc::now().to_rfc3339(),
117    }))
118}
119
120/// Graceful shutdown signal handler
121async fn shutdown_signal() {
122    let ctrl_c = async {
123        signal::ctrl_c()
124            .await
125            .expect("failed to install Ctrl+C handler");
126    };
127
128    #[cfg(unix)]
129    let terminate = async {
130        let mut signal = signal::unix::signal(signal::unix::SignalKind::terminate())
131            .expect("failed to install signal handler");
132        signal.recv().await;
133    };
134
135    #[cfg(not(unix))]
136    let terminate = std::future::pending::<()>();
137
138    tokio::select! {
139        _ = ctrl_c => {},
140        _ = terminate => {},
141    }
142
143    info!("Shutdown signal received, starting graceful shutdown");
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149    use crate::{LoggingMiddleware, TimingMiddleware};
150    
151    // Mock container for testing (since the real Container requires builder pattern)
152    struct MockContainer;
153    
154    #[tokio::test]
155    async fn test_middleware_pipeline() {
156        let pipeline = MiddlewarePipeline::new()
157            .add(LoggingMiddleware::new())
158            .add(TimingMiddleware::new());
159        
160        assert_eq!(pipeline.len(), 2);
161        assert_eq!(
162            pipeline.names(),
163            vec!["LoggingMiddleware", "TimingMiddleware"]
164        );
165    }
166    
167    #[tokio::test]
168    async fn test_custom_middleware_pipeline() {
169        let pipeline = MiddlewarePipeline::new()
170            .add(TimingMiddleware::new())
171            .add(LoggingMiddleware::new().with_body_logging());
172        
173        assert_eq!(pipeline.len(), 2);
174        assert_eq!(
175            pipeline.names(),
176            vec!["TimingMiddleware", "LoggingMiddleware"]
177        );
178    }
179}