dmsc/gateway/
mod.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18#![allow(non_snake_case)]
19
20//! # Gateway Module
21//! 
22//! This module provides a comprehensive API gateway functionality for DMSC, offering routing, middleware support,
23//! load balancing, rate limiting, and circuit breaking capabilities.
24//! 
25//! ## Key Components
26//! 
27//! - **DMSCGateway**: Main gateway struct implementing the DMSCModule trait
28//! - **DMSCGatewayConfig**: Configuration for gateway behavior
29//! - **DMSCGatewayRequest**: Request structure for gateway operations
30//! - **DMSCGatewayResponse**: Response structure for gateway operations
31//! - **DMSCRoute**: Route definition for API endpoints
32//! - **DMSCRouter**: Router for handling request routing
33//! - **DMSCMiddleware**: Middleware interface for request processing
34//! - **DMSCMiddlewareChain**: Chain of middleware for sequential execution
35//! - **DMSCLoadBalancer**: Load balancing for distributing requests across multiple services
36//! - **DMSCLoadBalancerStrategy**: Load balancing strategies (RoundRobin, LeastConnections, etc.)
37//! - **DMSCRateLimiter**: Rate limiting for controlling request rates
38//! - **DMSCRateLimitConfig**: Configuration for rate limiting
39//! - **DMSCCircuitBreaker**: Circuit breaker for preventing cascading failures
40//! - **DMSCCircuitBreakerConfig**: Configuration for circuit breakers
41//! 
42//! ## Design Principles
43//! 
44//! 1. **Modular Design**: Separate components for routing, middleware, load balancing, rate limiting, and circuit breaking
45//! 2. **Async-First**: All gateway operations are asynchronous
46//! 3. **Configurable**: Highly configurable gateway behavior through DMSCGatewayConfig
47//! 4. **Middleware Support**: Extensible middleware system for request processing
48//! 5. **Resilience**: Built-in circuit breaker and rate limiting for service resilience
49//! 6. **Load Balancing**: Support for distributing requests across multiple service instances
50//! 7. **CORS Support**: Built-in CORS configuration for cross-origin requests
51//! 8. **Logging**: Comprehensive logging support
52//! 9. **Service Integration**: Implements DMSCModule trait for seamless integration into DMSC
53//! 10. **Thread-safe**: Uses Arc and RwLock for safe concurrent access
54//! 
55//! ## Usage
56//! 
57//! ```rust
58//! use dmsc::prelude::*;
59//! use dmsc::gateway::{DMSCGateway, DMSCGatewayConfig, DMSCRoute};
60//! use std::collections::HashMap;
61//! 
62//! async fn example() -> DMSCResult<()> {
63//!     // Create gateway configuration
64//!     let gateway_config = DMSCGatewayConfig {
65//!         listen_address: "0.0.0.0".to_string(),
66//!         listen_port: 8080,
67//!         max_connections: 10000,
68//!         request_timeout_seconds: 30,
69//!         enable_rate_limiting: true,
70//!         enable_circuit_breaker: true,
71//!         enable_load_balancing: true,
72//!         cors_enabled: true,
73//!         cors_origins: vec!["*".to_string()],
74//!         cors_methods: vec!["GET".to_string(), "POST".to_string()],
75//!         cors_headers: vec!["Content-Type".to_string(), "Authorization".to_string()],
76//!         enable_logging: true,
77//!         log_level: "info".to_string(),
78//!     };
79//!     
80//!     // Create gateway instance
81//!     let gateway = DMSCGateway::new();
82//!     
83//!     // Get router and add routes
84//!     let router = gateway.router();
85//!     
86//!     // Add a simple GET route
87//!     router.add_route(DMSCRoute {
88//!         path: "/api/v1/health".to_string(),
89//!         method: "GET".to_string(),
90//!         handler: Arc::new(|req| Box::pin(async move {
91//!             Ok(DMSCGatewayResponse::json(200, &serde_json::json!({ "status": "ok" }), req.id.clone())?)
92//!         })),
93//!         ..Default::default()
94//!     }).await?;
95//!     
96//!     // Add middleware
97//!     let middleware_chain = gateway.middleware_chain();
98//!     middleware_chain.add_middleware(Arc::new(|req, next| Box::pin(async move {
99//!         // Log request
100//!         println!("Request: {} {}", req.method, req.path);
101//!         next(req).await
102//!     }))).await;
103//!     
104//!     // Handle a sample request
105//!     let sample_request = DMSCGatewayRequest::new(
106//!         "GET".to_string(),
107//!         "/api/v1/health".to_string(),
108//!         HashMap::new(),
109//!         HashMap::new(),
110//!         None,
111//!         "127.0.0.1:12345".to_string(),
112//!     );
113//!     
114//!     let response = gateway.handle_request(sample_request).await;
115//!     println!("Response: {} {}", response.status_code, String::from_utf8_lossy(&response.body));
116//!     
117//!     Ok(())
118//! }
119//! ```
120
121use crate::core::{DMSCModule, DMSCServiceContext};
122use log;
123use serde::{Deserialize, Serialize};
124use std::collections::HashMap;
125use std::sync::Arc;
126use tokio::sync::RwLock;
127
128pub mod middleware;
129pub mod routing;
130pub mod circuit_breaker;
131pub mod load_balancer;
132pub mod rate_limiter;
133pub mod server;
134
135pub use routing::{DMSCRoute, DMSCRouter};
136pub use middleware::{DMSCMiddleware, DMSCMiddlewareChain};
137pub use load_balancer::{DMSCLoadBalancer, DMSCLoadBalancerStrategy};
138pub use rate_limiter::{DMSCRateLimiter, DMSCRateLimitConfig};
139pub use circuit_breaker::{DMSCCircuitBreaker, DMSCCircuitBreakerConfig};
140
141#[cfg(feature = "gateway")]
142pub use server::{DMSCGatewayServer, load_tls_config};
143
144/// Configuration for the DMSC Gateway.
145/// 
146/// This struct defines the configuration options for the API gateway, including network settings,
147/// feature toggles, and CORS configuration.
148#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct DMSCGatewayConfig {
151    /// Address to listen on
152    pub listen_address: String,
153    /// Port to listen on
154    pub listen_port: u16,
155    /// Maximum number of concurrent connections
156    pub max_connections: usize,
157    /// Request timeout in seconds
158    pub request_timeout_seconds: u64,
159    /// Whether to enable rate limiting
160    pub enable_rate_limiting: bool,
161    /// Whether to enable circuit breaker
162    pub enable_circuit_breaker: bool,
163    /// Whether to enable load balancing
164    pub enable_load_balancing: bool,
165    /// Whether to enable CORS
166    pub cors_enabled: bool,
167    /// Allowed CORS origins
168    pub cors_origins: Vec<String>,
169    /// Allowed CORS methods
170    pub cors_methods: Vec<String>,
171    /// Allowed CORS headers
172    pub cors_headers: Vec<String>,
173    /// Whether to enable logging
174    pub enable_logging: bool,
175    /// Log level for gateway operations
176    pub log_level: String,
177}
178
179#[cfg(feature = "pyo3")]
180/// Python bindings for DMSCGatewayConfig
181#[pyo3::prelude::pymethods]
182impl DMSCGatewayConfig {
183    #[new]
184    fn py_new() -> Self {
185        Self::default()
186    }
187    
188    #[staticmethod]
189    fn py_new_with_address(listen_address: String, listen_port: u16) -> Self {
190        Self {
191            listen_address,
192            listen_port,
193            ..Self::default()
194        }
195    }
196}
197
198impl DMSCGatewayConfig {
199    /// Creates a new DMSCGatewayConfig with default values.
200    pub fn new() -> Self {
201        Self::default()
202    }
203}
204
205impl Default for DMSCGatewayConfig {
206    /// Returns the default configuration for the gateway.
207    /// 
208    /// Default values:
209    /// - listen_address: "0.0.0.0"
210    /// - listen_port: 8080
211    /// - max_connections: 10000
212    /// - request_timeout_seconds: 30
213    /// - enable_rate_limiting: true
214    /// - enable_circuit_breaker: true
215    /// - enable_load_balancing: true
216    /// - cors_enabled: true
217    /// - cors_origins: ["*"]
218    /// - cors_methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
219    /// - cors_headers: ["Content-Type", "Authorization", "X-Requested-With"]
220    /// - enable_logging: true
221    /// - log_level: "info"
222    fn default() -> Self {
223        Self {
224            listen_address: "0.0.0.0".to_string(),
225            listen_port: 8080,
226            max_connections: 10000,
227            request_timeout_seconds: 30,
228            enable_rate_limiting: true,
229            enable_circuit_breaker: true,
230            enable_load_balancing: true,
231            cors_enabled: true,
232            cors_origins: vec!["*".to_string()],
233            cors_methods: vec!["GET".to_string(), "POST".to_string(), "PUT".to_string(), "DELETE".to_string(), "OPTIONS".to_string()],
234            cors_headers: vec!["Content-Type".to_string(), "Authorization".to_string(), "X-Requested-With".to_string()],
235            enable_logging: true,
236            log_level: "info".to_string(),
237        }
238    }
239}
240
241/// Request structure for gateway operations.
242/// 
243/// This struct represents an HTTP request received by the gateway, including method, path, headers,
244/// query parameters, body, and remote address.
245#[derive(Debug, Clone)]
246#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
247pub struct DMSCGatewayRequest {
248    /// Unique request ID
249    pub id: String,
250    /// HTTP method (GET, POST, etc.)
251    pub method: String,
252    /// Request path
253    pub path: String,
254    /// HTTP headers
255    pub headers: HashMap<String, String>,
256    /// Query parameters
257    pub query_params: HashMap<String, String>,
258    /// Request body (if any)
259    pub body: Option<Vec<u8>>,
260    /// Remote address of the client
261    pub remote_addr: String,
262    /// Timestamp when the request was created
263    pub timestamp: std::time::Instant,
264}
265
266impl DMSCGatewayRequest {
267    /// Creates a new gateway request.
268    /// 
269    /// # Parameters
270    /// 
271    /// - `method`: HTTP method
272    /// - `path`: Request path
273    /// - `headers`: HTTP headers
274    /// - `query_params`: Query parameters
275    /// - `body`: Request body (optional)
276    /// - `remote_addr`: Remote address of the client
277    /// 
278    /// # Returns
279    /// 
280    /// A new `DMSCGatewayRequest` instance
281    pub fn new(
282        method: String,
283        path: String,
284        headers: HashMap<String, String>,
285        query_params: HashMap<String, String>,
286        body: Option<Vec<u8>>,
287        remote_addr: String,
288    ) -> Self {
289        Self {
290            id: uuid::Uuid::new_v4().to_string(),
291            method,
292            path,
293            headers,
294            query_params,
295            body,
296            remote_addr,
297            timestamp: std::time::Instant::now(),
298        }
299    }
300}
301
302/// Response structure for gateway operations.
303/// 
304/// This struct represents an HTTP response returned by the gateway, including status code,
305/// headers, body, and request ID.
306#[derive(Debug, Clone)]
307#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
308pub struct DMSCGatewayResponse {
309    /// HTTP status code
310    pub status_code: u16,
311    /// HTTP headers
312    pub headers: HashMap<String, String>,
313    /// Response body
314    pub body: Vec<u8>,
315    /// Request ID associated with this response
316    pub request_id: String,
317}
318
319impl DMSCGatewayResponse {
320    /// Creates a new gateway response.
321    /// 
322    /// # Parameters
323    /// 
324    /// - `status_code`: HTTP status code
325    /// - `body`: Response body
326    /// - `request_id`: Request ID associated with this response
327    /// 
328    /// # Returns
329    /// 
330    /// A new `DMSCGatewayResponse` instance
331    pub fn new(status_code: u16, body: Vec<u8>, request_id: String) -> Self {
332        let mut headers = HashMap::new();
333        headers.insert("Content-Type".to_string(), "application/json".to_string());
334        headers.insert("X-Request-ID".to_string(), request_id.clone());
335        
336        Self {
337            status_code,
338            headers,
339            body,
340            request_id,
341        }
342    }
343
344    /// Adds a header to the response.
345    /// 
346    /// # Parameters
347    /// 
348    /// - `key`: Header name
349    /// - `value`: Header value
350    /// 
351    /// # Returns
352    /// 
353    /// The updated `DMSCGatewayResponse` instance
354    pub fn with_header(mut self, key: String, value: String) -> Self {
355        self.headers.insert(key, value);
356        self
357    }
358
359    /// Creates a JSON response.
360    /// 
361    /// # Parameters
362    /// 
363    /// - `status_code`: HTTP status code
364    /// - `data`: Data to serialize as JSON
365    /// - `request_id`: Request ID associated with this response
366    /// 
367    /// # Returns
368    /// 
369    /// A `DMSCResult<Self>` containing the JSON response
370    pub fn json<T: serde::Serialize>(status_code: u16, data: &T, request_id: String) -> crate::core::DMSCResult<Self> {
371        let body = serde_json::to_vec(data)?;
372        Ok(Self::new(status_code, body, request_id))
373    }
374
375    /// Creates an error response.
376    /// 
377    /// # Parameters
378    /// 
379    /// - `status_code`: HTTP status code
380    /// - `message`: Error message
381    /// - `request_id`: Request ID associated with this response
382    /// 
383    /// # Returns
384    /// 
385    /// A new `DMSCGatewayResponse` instance with error information
386    pub fn error(status_code: u16, message: String, request_id: String) -> Self {
387        let error_body = serde_json::json!({
388            "error": message,
389            "request_id": request_id
390        });
391        
392        let body = serde_json::to_vec(&error_body).unwrap_or_else(|_| b"{}".to_vec());
393        Self::new(status_code, body, request_id)
394    }
395}
396
397/// Main gateway struct implementing the DMSCModule trait.
398/// 
399/// This struct provides the core gateway functionality, including request handling,
400/// routing, middleware execution, rate limiting, and circuit breaking.
401#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
402pub struct DMSCGateway {
403    /// Gateway configuration, protected by a RwLock for thread-safe access
404    config: RwLock<DMSCGatewayConfig>,
405    /// Router for handling request routing
406    router: Arc<DMSCRouter>,
407    /// Middleware chain for request processing
408    middleware_chain: Arc<DMSCMiddlewareChain>,
409    /// Rate limiter for controlling request rates
410    rate_limiter: Option<Arc<DMSCRateLimiter>>,
411    /// Circuit breaker for preventing cascading failures
412    circuit_breaker: Option<Arc<DMSCCircuitBreaker>>,
413}
414
415impl Default for DMSCGateway {
416    fn default() -> Self {
417        Self::new()
418    }
419}
420
421impl DMSCGateway {
422    /// Creates a new gateway instance with default configuration.
423    /// 
424    /// # Returns
425    /// 
426    /// A new `DMSCGateway` instance
427    pub fn new() -> Self {
428        let config = DMSCGatewayConfig::default();
429        let router = Arc::new(DMSCRouter::new());
430        let middleware_chain = Arc::new(DMSCMiddlewareChain::new());
431        
432        let rate_limiter = if config.enable_rate_limiting {
433            Some(Arc::new(DMSCRateLimiter::new(DMSCRateLimitConfig::default())))
434        } else {
435            None
436        };
437        
438        let circuit_breaker = if config.enable_circuit_breaker {
439            Some(Arc::new(DMSCCircuitBreaker::new(DMSCCircuitBreakerConfig::default())))
440        } else {
441            None
442        };
443
444        Self {
445            config: RwLock::new(config),
446            router,
447            middleware_chain,
448            rate_limiter,
449            circuit_breaker,
450        }
451    }
452
453    /// Returns a reference to the router.
454    /// 
455    /// # Returns
456    /// 
457    /// An Arc<DMSCRouter> providing thread-safe access to the router
458    pub fn router(&self) -> Arc<DMSCRouter> {
459        self.router.clone()
460    }
461
462    /// Returns a reference to the middleware chain.
463    /// 
464    /// # Returns
465    /// 
466    /// An Arc<DMSCMiddlewareChain> providing thread-safe access to the middleware chain
467    pub fn middleware_chain(&self) -> Arc<DMSCMiddlewareChain> {
468        self.middleware_chain.clone()
469    }
470
471    /// Handles a gateway request.
472    /// 
473    /// This method processes a request through the gateway pipeline, including:
474    /// 1. Rate limiting
475    /// 2. Circuit breaker check
476    /// 3. Middleware chain execution
477    /// 4. Request routing
478    /// 5. Route handler execution
479    /// 
480    /// # Parameters
481    /// 
482    /// - `request`: The request to handle
483    /// 
484    /// # Returns
485    /// 
486    /// A `DMSCGatewayResponse` containing the response to the request
487    pub async fn handle_request(&self, request: DMSCGatewayRequest) -> DMSCGatewayResponse {
488        let request_id = request.id.clone();
489        
490        // Apply rate limiting
491        if let Some(rate_limiter) = &self.rate_limiter {
492            if !rate_limiter.check_request(&request).await {
493                return DMSCGatewayResponse::new(429, "Rate limit exceeded".to_string().into_bytes(), request_id);
494            }
495        }
496
497        // Apply circuit breaker
498        if let Some(circuit_breaker) = &self.circuit_breaker {
499            if !circuit_breaker.allow_request() {
500                return DMSCGatewayResponse::new(503, "Service temporarily unavailable".to_string().into_bytes(), request_id);
501            }
502        }
503
504        // Apply middleware chain
505        let mut request = request;
506        match self.middleware_chain.execute(&mut request).await {
507            Ok(()) => {
508                // Route the request
509                match self.router.route(&request).await {
510                    Ok(route_handler) => {
511                        // Execute the route handler
512                        match route_handler(request).await {
513                            Ok(response) => response,
514                            Err(e) => {
515                                DMSCGatewayResponse::new(500, format!("Internal server error: {e}").into_bytes(), request_id)
516                            }
517                        }
518                    },
519                    Err(e) => {
520                        DMSCGatewayResponse::new(404, format!("Route not found: {e}").into_bytes(), request_id)
521                    }
522                }
523            },
524            Err(e) => {
525                DMSCGatewayResponse::new(403, format!("Middleware error: {e}").into_bytes(), request_id)
526            }
527        }
528    }
529}
530
531#[async_trait::async_trait]
532impl DMSCModule for DMSCGateway {
533    /// Returns the name of the gateway module.
534    /// 
535    /// # Returns
536    /// 
537    /// The module name as a string
538    fn name(&self) -> &str {
539        "DMSC.Gateway"
540    }
541
542    /// Initializes the gateway module.
543    /// 
544    /// # Parameters
545    /// 
546    /// - `ctx`: Service context containing configuration and other services
547    /// 
548    /// # Returns
549    /// 
550    /// A `DMSCResult<()>` indicating success or failure
551    async fn init(&mut self, ctx: &mut DMSCServiceContext) -> crate::core::DMSCResult<()> {
552        let logger = ctx.logger();
553        logger.info("DMSC.Gateway", "Initializing API gateway module")?;
554
555        let config = self.config.read().await;
556        logger.info(
557            "DMSC.Gateway",
558            format!("Gateway will listen on {}:{}", config.listen_address, config.listen_port)
559        )?;
560
561        logger.info("DMSC.Gateway", "API gateway module initialized successfully")?;
562        Ok(())
563    }
564
565    /// Performs cleanup after the gateway has shut down.
566    /// 
567    /// This method ensures proper resource cleanup during gateway shutdown:
568    /// - Clears all rate limiter buckets
569    /// - Resets the circuit breaker to closed state
570    /// - Clears all registered routes
571    /// 
572    /// # Parameters
573    /// 
574    /// - `_ctx`: Service context (not used in this implementation)
575    /// 
576    /// # Returns
577    /// 
578    /// A `DMSCResult<()>` indicating success or failure
579    /// 
580    /// # Logs
581    /// 
582    /// Logs cleanup progress at INFO level for debugging purposes
583    async fn after_shutdown(&mut self, _ctx: &mut DMSCServiceContext) -> crate::core::DMSCResult<()> {
584        log::info!("Cleaning up DMSC Gateway Module");
585        
586        if let Some(rate_limiter) = &self.rate_limiter {
587            rate_limiter.clear_all_buckets();
588            log::info!("Rate limiter cleanup completed");
589        }
590        
591        if let Some(circuit_breaker) = &self.circuit_breaker {
592            circuit_breaker.reset();
593            log::info!("Circuit breaker reset completed");
594        }
595        
596        self.router.clear_routes();
597        log::info!("Router cleanup completed");
598        
599        log::info!("DMSC Gateway Module cleanup completed");
600        Ok(())
601    }
602}
603
604#[cfg(feature = "pyo3")]
605/// Python bindings for DMSCGateway
606#[pyo3::prelude::pymethods]
607impl DMSCGateway {
608    #[new]
609    fn py_new() -> Self {
610        Self::new()
611    }
612}