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}