omni_director/api_clean/
server.rs

1//! # API Server
2//!
3//! HTTP server with clean routing and middleware.
4
5use super::handlers::*;
6use super::middleware::*;
7use crate::routing::Router;
8use crate::providers::{ProviderRegistry, EventRegistry};
9use axum::{
10    middleware,
11    routing::{get, post},
12    Router as AxumRouter,
13};
14use std::sync::Arc;
15use std::time::SystemTime;
16use tower_http::cors::CorsLayer;
17use tower_http::trace::TraceLayer;
18
19/// API server configuration
20#[derive(Debug, Clone)]
21pub struct ServerConfig {
22    /// Server bind address
23    pub bind_address: String,
24    /// Enable CORS
25    pub enable_cors: bool,
26    /// Enable request logging
27    pub enable_logging: bool,
28    /// Request timeout in seconds
29    pub request_timeout_seconds: u64,
30}
31
32impl Default for ServerConfig {
33    fn default() -> Self {
34        Self {
35            bind_address: "127.0.0.1:8080".to_string(),
36            enable_cors: true,
37            enable_logging: true,
38            request_timeout_seconds: 30,
39        }
40    }
41}
42
43/// Create the API server with all routes configured
44pub fn create_server(
45    registry: Arc<ProviderRegistry>,
46    router: Arc<Router>,
47    event_registry: Arc<EventRegistry>,
48    config: ServerConfig,
49) -> AxumRouter {
50    let state = AppState {
51        router,
52        registry,
53        event_registry,
54        start_time: SystemTime::now(),
55    };
56
57    let mut app = AxumRouter::new()
58        // Health and system endpoints
59        .route("/health", get(health))
60        .route("/stats", get(get_stats))
61        .route("/routes", get(list_routes))
62        
63        // Provider discovery
64        .route("/providers", get(discover_providers))
65        .route("/providers/:provider", get(get_provider))
66        
67        // Feature information
68        .route("/providers/:provider/features/:feature", get(get_feature))
69        
70        // Operation information and execution
71        .route(
72            "/providers/:provider/features/:feature/operations/:operation",
73            get(get_operation).post(execute_operation),
74        )
75        
76        // Unified action execution endpoint
77        .route("/exec_action", post(exec_action))
78        
79        // Add application state
80        .with_state(state);
81
82    // Add middleware layers
83    if config.enable_logging {
84        app = app.layer(TraceLayer::new_for_http());
85    }
86
87    if config.enable_cors {
88        app = app.layer(CorsLayer::permissive());
89    }
90
91    // Add custom middleware
92    app = app.layer(middleware::from_fn(request_logging_middleware));
93    app = app.layer(middleware::from_fn(error_handling_middleware));
94
95    app
96}
97
98/// Start the API server
99pub async fn start_server(
100    registry: Arc<ProviderRegistry>,
101    router: Arc<Router>,
102    event_registry: Arc<EventRegistry>,
103    config: ServerConfig,
104) -> Result<(), Box<dyn std::error::Error>> {
105    let app = create_server(registry, router, event_registry, config.clone());
106
107    println!("🚀 Starting OmniDirector API server on {}", config.bind_address);
108    println!("📚 API Documentation:");
109    print_api_routes();
110
111    let listener = tokio::net::TcpListener::bind(&config.bind_address).await?;
112    
113    axum::serve(listener, app).await?;
114    
115    Ok(())
116}
117
118/// Print available API routes for documentation
119fn print_api_routes() {
120    println!("  GET  /health                     - Health check");
121    println!("  GET  /stats                      - Registry statistics");
122    println!("  GET  /routes                     - List all available routes");
123    println!("  GET  /providers                  - Discover all providers");
124    println!("  GET  /providers/{{provider}}       - Get provider information");
125    println!("  GET  /providers/{{provider}}/features/{{feature}} - Get feature information");
126    println!("  GET  /providers/{{provider}}/features/{{feature}}/operations/{{operation}} - Get operation information");
127    println!("  POST /providers/{{provider}}/features/{{feature}}/operations/{{operation}} - Execute operation");
128    println!();
129    println!("🔗 Example URLs:");
130    println!("  http://127.0.0.1:8080/health");
131    println!("  http://127.0.0.1:8080/providers");
132    println!("  http://127.0.0.1:8080/providers/worker-management/features/worker_management/operations/list-workers");
133    println!();
134}