Skip to main content

ri/gateway/
mod.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of Ri.
4//! The Ri 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 Ri, offering routing, middleware support,
23//! load balancing, rate limiting, and circuit breaking capabilities.
24//! 
25//! ## Key Components
26//! 
27//! - **RiGateway**: Main gateway struct implementing the RiModule trait
28//! - **RiGatewayConfig**: Configuration for gateway behavior
29//! - **RiGatewayRequest**: Request structure for gateway operations
30//! - **RiGatewayResponse**: Response structure for gateway operations
31//! - **RiRoute**: Route definition for API endpoints
32//! - **RiRouter**: Router for handling request routing
33//! - **RiMiddleware**: Middleware interface for request processing
34//! - **RiMiddlewareChain**: Chain of middleware for sequential execution
35//! - **RiLoadBalancer**: Load balancing for distributing requests across multiple services
36//! - **RiLoadBalancerStrategy**: Load balancing strategies (RoundRobin, LeastConnections, etc.)
37//! - **RiRateLimiter**: Rate limiting for controlling request rates
38//! - **RiRateLimitConfig**: Configuration for rate limiting
39//! - **RiCircuitBreaker**: Circuit breaker for preventing cascading failures
40//! - **RiCircuitBreakerConfig**: 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 RiGatewayConfig
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 RiModule trait for seamless integration into Ri
53//! 10. **Thread-safe**: Uses Arc and RwLock for safe concurrent access
54//! 
55//! ## Usage
56//! 
57//! ```rust
58//! use ri::prelude::*;
59//! use ri::gateway::{RiGateway, RiGatewayConfig, RiRoute};
60//! use std::collections::HashMap as FxHashMap;
61//! 
62//! async fn example() -> RiResult<()> {
63//!     // Create gateway configuration
64//!     let gateway_config = RiGatewayConfig {
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 = RiGateway::new();
82//!     
83//!     // Get router and add routes
84//!     let router = gateway.router();
85//!     
86//!     // Add a simple GET route
87//!     router.add_route(RiRoute {
88//!         path: "/api/v1/health".to_string(),
89//!         method: "GET".to_string(),
90//!         handler: Arc::new(|req| Box::pin(async move {
91//!             Ok(RiGatewayResponse::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 = RiGatewayRequest::new(
106//!         "GET".to_string(),
107//!         "/api/v1/health".to_string(),
108//!         FxHashMap::default(),
109//!         FxHashMap::default(),
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::{RiModule, RiServiceContext};
122use log;
123use serde::{Deserialize, Serialize};
124use std::collections::HashMap as FxHashMap;
125use std::sync::Arc;
126use tokio::sync::RwLock;
127
128pub mod middleware;
129pub mod routing;
130pub mod radix_tree;
131pub mod circuit_breaker;
132pub mod load_balancer;
133pub mod rate_limiter;
134pub mod server;
135
136pub use routing::{RiRoute, RiRouter, RiRouteHandler};
137pub use radix_tree::{RiRadixTree, RadixNode, PathSegment, SegmentType, RouteMatch};
138pub use middleware::{RiMiddleware, RiMiddlewareChain};
139pub use load_balancer::{RiLoadBalancer, RiLoadBalancerStrategy, RiBackendServer, RiLoadBalancerServerStats};
140pub use rate_limiter::{RiRateLimiter, RiRateLimitConfig, RiRateLimitStats, RiSlidingWindowRateLimiter};
141pub use circuit_breaker::{RiCircuitBreaker, RiCircuitBreakerConfig, RiCircuitBreakerState, RiCircuitBreakerMetrics};
142
143#[cfg(feature = "gateway")]
144pub use server::{RiGatewayServer, load_tls_config};
145
146/// Configuration for the Ri Gateway.
147/// 
148/// This struct defines the configuration options for the API gateway, including network settings,
149/// feature toggles, and CORS configuration.
150#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct RiGatewayConfig {
153    /// Address to listen on
154    pub listen_address: String,
155    /// Port to listen on
156    pub listen_port: u16,
157    /// Maximum number of concurrent connections
158    pub max_connections: usize,
159    /// Request timeout in seconds
160    pub request_timeout_seconds: u64,
161    /// Whether to enable rate limiting
162    pub enable_rate_limiting: bool,
163    /// Whether to enable circuit breaker
164    pub enable_circuit_breaker: bool,
165    /// Whether to enable load balancing
166    pub enable_load_balancing: bool,
167    /// Whether to enable CORS
168    pub cors_enabled: bool,
169    /// Allowed CORS origins
170    pub cors_origins: Vec<String>,
171    /// Allowed CORS methods
172    pub cors_methods: Vec<String>,
173    /// Allowed CORS headers
174    pub cors_headers: Vec<String>,
175    /// Whether to enable logging
176    pub enable_logging: bool,
177    /// Log level for gateway operations
178    pub log_level: String,
179}
180
181#[cfg(feature = "pyo3")]
182/// Python bindings for RiGatewayConfig
183#[pyo3::prelude::pymethods]
184impl RiGatewayConfig {
185    #[new]
186    fn py_new() -> Self {
187        Self::default()
188    }
189    
190    #[staticmethod]
191    fn py_new_with_address(listen_address: String, listen_port: u16) -> Self {
192        Self {
193            listen_address,
194            listen_port,
195            ..Self::default()
196        }
197    }
198}
199
200impl RiGatewayConfig {
201    /// Creates a new RiGatewayConfig with default values.
202    pub fn new() -> Self {
203        Self::default()
204    }
205}
206
207impl Default for RiGatewayConfig {
208    /// Returns the default configuration for the gateway.
209    /// 
210    /// Default values:
211    /// - listen_address: "0.0.0.0"
212    /// - listen_port: 8080
213    /// - max_connections: 10000
214    /// - request_timeout_seconds: 30
215    /// - enable_rate_limiting: true
216    /// - enable_circuit_breaker: true
217    /// - enable_load_balancing: true
218    /// - cors_enabled: true
219    /// - cors_origins: [] (must be explicitly configured for security)
220    /// - cors_methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
221    /// - cors_headers: ["Content-Type", "Authorization", "X-Requested-With"]
222    /// - enable_logging: true
223    /// - log_level: "info"
224    /// 
225    /// # Security
226    /// 
227    /// CORS origins must be explicitly configured. Empty cors_origins means
228    /// no CORS headers will be sent, which is the secure default.
229    fn default() -> Self {
230        Self {
231            listen_address: "0.0.0.0".to_string(),
232            listen_port: 8080,
233            max_connections: 10000,
234            request_timeout_seconds: 30,
235            enable_rate_limiting: true,
236            enable_circuit_breaker: true,
237            enable_load_balancing: true,
238            cors_enabled: true,
239            // Security: Empty by default - must be explicitly configured
240            // Never use ["*"] in production as it allows any origin
241            cors_origins: vec![],
242            cors_methods: vec!["GET".to_string(), "POST".to_string(), "PUT".to_string(), "DELETE".to_string(), "OPTIONS".to_string()],
243            cors_headers: vec!["Content-Type".to_string(), "Authorization".to_string(), "X-Requested-With".to_string()],
244            enable_logging: true,
245            log_level: "info".to_string(),
246        }
247    }
248}
249
250/// Request structure for gateway operations.
251/// 
252/// This struct represents an HTTP request received by the gateway, including method, path, headers,
253/// query parameters, body, and remote address.
254#[derive(Debug, Clone)]
255#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
256pub struct RiGatewayRequest {
257    /// Unique request ID
258    pub id: String,
259    /// HTTP method (GET, POST, etc.)
260    pub method: String,
261    /// Request path
262    pub path: String,
263    /// HTTP headers
264    pub headers: FxHashMap<String, String>,
265    /// Query parameters
266    pub query_params: FxHashMap<String, String>,
267    /// Request body (if any)
268    pub body: Option<Vec<u8>>,
269    /// Remote address of the client
270    pub remote_addr: String,
271    /// Timestamp when the request was created
272    pub timestamp: std::time::Instant,
273}
274
275impl RiGatewayRequest {
276    /// Creates a new gateway request.
277    /// 
278    /// # Parameters
279    /// 
280    /// - `method`: HTTP method
281    /// - `path`: Request path
282    /// - `headers`: HTTP headers
283    /// - `query_params`: Query parameters
284    /// - `body`: Request body (optional)
285    /// - `remote_addr`: Remote address of the client
286    /// 
287    /// # Returns
288    /// 
289    /// A new `RiGatewayRequest` instance
290    pub fn new(
291        method: String,
292        path: String,
293        headers: FxHashMap<String, String>,
294        query_params: FxHashMap<String, String>,
295        body: Option<Vec<u8>>,
296        remote_addr: String,
297    ) -> Self {
298        Self {
299            id: uuid::Uuid::new_v4().to_string(),
300            method,
301            path,
302            headers,
303            query_params,
304            body,
305            remote_addr,
306            timestamp: std::time::Instant::now(),
307        }
308    }
309}
310
311/// Response structure for gateway operations.
312/// 
313/// This struct represents an HTTP response returned by the gateway, including status code,
314/// headers, body, and request ID.
315#[derive(Debug, Clone)]
316#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
317pub struct RiGatewayResponse {
318    /// HTTP status code
319    pub status_code: u16,
320    /// HTTP headers
321    pub headers: FxHashMap<String, String>,
322    /// Response body
323    pub body: Vec<u8>,
324    /// Request ID associated with this response
325    pub request_id: String,
326}
327
328impl RiGatewayResponse {
329    /// Creates a new gateway response.
330    /// 
331    /// # Parameters
332    /// 
333    /// - `status_code`: HTTP status code
334    /// - `body`: Response body
335    /// - `request_id`: Request ID associated with this response
336    /// 
337    /// # Returns
338    /// 
339    /// A new `RiGatewayResponse` instance
340    pub fn new(status_code: u16, body: Vec<u8>, request_id: String) -> Self {
341        let mut headers = FxHashMap::default();
342        headers.insert("Content-Type".to_string(), "application/json".to_string());
343        headers.insert("X-Request-ID".to_string(), request_id.clone());
344        
345        Self {
346            status_code,
347            headers,
348            body,
349            request_id,
350        }
351    }
352
353    /// Adds a header to the response.
354    /// 
355    /// # Parameters
356    /// 
357    /// - `key`: Header name
358    /// - `value`: Header value
359    /// 
360    /// # Returns
361    /// 
362    /// The updated `RiGatewayResponse` instance
363    pub fn with_header(mut self, key: String, value: String) -> Self {
364        self.headers.insert(key, value);
365        self
366    }
367
368    /// Creates a JSON response.
369    /// 
370    /// # Parameters
371    /// 
372    /// - `status_code`: HTTP status code
373    /// - `data`: Data to serialize as JSON
374    /// - `request_id`: Request ID associated with this response
375    /// 
376    /// # Returns
377    /// 
378    /// A `RiResult<Self>` containing the JSON response
379    pub fn json<T: serde::Serialize>(status_code: u16, data: &T, request_id: String) -> crate::core::RiResult<Self> {
380        let body = serde_json::to_vec(data)?;
381        Ok(Self::new(status_code, body, request_id))
382    }
383
384    /// Creates an error response.
385    /// 
386    /// # Parameters
387    /// 
388    /// - `status_code`: HTTP status code
389    /// - `message`: Error message
390    /// - `request_id`: Request ID associated with this response
391    /// 
392    /// # Returns
393    /// 
394    /// A new `RiGatewayResponse` instance with error information
395    pub fn error(status_code: u16, message: String, request_id: String) -> Self {
396        let error_body = serde_json::json!({
397            "error": message,
398            "request_id": request_id
399        });
400        
401        let body = serde_json::to_vec(&error_body).unwrap_or_else(|_| b"{}".to_vec());
402        Self::new(status_code, body, request_id)
403    }
404}
405
406/// Main gateway struct implementing the RiModule trait.
407/// 
408/// This struct provides the core gateway functionality, including request handling,
409/// routing, middleware execution, rate limiting, and circuit breaking.
410#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
411pub struct RiGateway {
412    /// Gateway configuration, protected by a RwLock for thread-safe access
413    config: RwLock<RiGatewayConfig>,
414    /// Router for handling request routing
415    router: Arc<RiRouter>,
416    /// Middleware chain for request processing
417    middleware_chain: Arc<RiMiddlewareChain>,
418    /// Rate limiter for controlling request rates
419    rate_limiter: Option<Arc<RiRateLimiter>>,
420    /// Circuit breaker for preventing cascading failures
421    circuit_breaker: Option<Arc<RiCircuitBreaker>>,
422}
423
424impl Default for RiGateway {
425    fn default() -> Self {
426        Self::new()
427    }
428}
429
430impl RiGateway {
431    /// Creates a new gateway instance with default configuration.
432    /// 
433    /// # Returns
434    /// 
435    /// A new `RiGateway` instance
436    pub fn new() -> Self {
437        let config = RiGatewayConfig::default();
438        let router = Arc::new(RiRouter::new());
439        let middleware_chain = Arc::new(RiMiddlewareChain::new());
440        
441        let rate_limiter = if config.enable_rate_limiting {
442            Some(Arc::new(RiRateLimiter::new(RiRateLimitConfig::default())))
443        } else {
444            None
445        };
446        
447        let circuit_breaker = if config.enable_circuit_breaker {
448            Some(Arc::new(RiCircuitBreaker::new(RiCircuitBreakerConfig::default())))
449        } else {
450            None
451        };
452
453        Self {
454            config: RwLock::new(config),
455            router,
456            middleware_chain,
457            rate_limiter,
458            circuit_breaker,
459        }
460    }
461
462    /// Returns a reference to the router.
463    /// 
464    /// # Returns
465    /// 
466    /// An Arc<RiRouter> providing thread-safe access to the router
467    pub fn router(&self) -> Arc<RiRouter> {
468        self.router.clone()
469    }
470
471    /// Returns a reference to the middleware chain.
472    /// 
473    /// # Returns
474    /// 
475    /// An Arc<RiMiddlewareChain> providing thread-safe access to the middleware chain
476    pub fn middleware_chain(&self) -> Arc<RiMiddlewareChain> {
477        self.middleware_chain.clone()
478    }
479
480    /// Handles a gateway request.
481    /// 
482    /// This method processes a request through the gateway pipeline, including:
483    /// 1. Rate limiting
484    /// 2. Circuit breaker check
485    /// 3. Middleware chain execution
486    /// 4. Request routing
487    /// 5. Route handler execution
488    /// 
489    /// # Parameters
490    /// 
491    /// - `request`: The request to handle
492    /// 
493    /// # Returns
494    /// 
495    /// A `RiGatewayResponse` containing the response to the request
496    pub async fn handle_request(&self, request: RiGatewayRequest) -> RiGatewayResponse {
497        let request_id = request.id.clone();
498        
499        // Apply rate limiting
500        if let Some(rate_limiter) = &self.rate_limiter {
501            if !rate_limiter.check_request(&request).await {
502                return RiGatewayResponse::new(429, "Rate limit exceeded".to_string().into_bytes(), request_id);
503            }
504        }
505
506        // Apply circuit breaker
507        if let Some(circuit_breaker) = &self.circuit_breaker {
508            if !circuit_breaker.allow_request() {
509                return RiGatewayResponse::new(503, "Service temporarily unavailable".to_string().into_bytes(), request_id);
510            }
511        }
512
513        // Apply middleware chain
514        let mut request = request;
515        match self.middleware_chain.execute(&mut request).await {
516            Ok(()) => {
517                // Route the request
518                match self.router.route(&request).await {
519                    Ok(route_handler) => {
520                        // Execute the route handler
521                        match route_handler(request).await {
522                            Ok(response) => response,
523                            Err(e) => {
524                                log::error!("[Ri.Gateway] Internal server error for request {}: {}", request_id, e);
525                                RiGatewayResponse::new(500, "Internal Server Error".to_string().into_bytes(), request_id)
526                            }
527                        }
528                    },
529                    Err(e) => {
530                        log::warn!("[Ri.Gateway] Route not found for request {}: {}", request_id, e);
531                        RiGatewayResponse::new(404, "Not Found".to_string().into_bytes(), request_id)
532                    }
533                }
534            },
535            Err(e) => {
536                log::warn!("[Ri.Gateway] Middleware error for request {}: {}", request_id, e);
537                RiGatewayResponse::new(403, "Forbidden".to_string().into_bytes(), request_id)
538            }
539        }
540    }
541}
542
543#[async_trait::async_trait]
544impl RiModule for RiGateway {
545    /// Returns the name of the gateway module.
546    /// 
547    /// # Returns
548    /// 
549    /// The module name as a string
550    fn name(&self) -> &str {
551        "Ri.Gateway"
552    }
553
554    /// Initializes the gateway module.
555    /// 
556    /// # Parameters
557    /// 
558    /// - `ctx`: Service context containing configuration and other services
559    /// 
560    /// # Returns
561    /// 
562    /// A `RiResult<()>` indicating success or failure
563    async fn init(&mut self, ctx: &mut RiServiceContext) -> crate::core::RiResult<()> {
564        let logger = ctx.logger();
565        logger.info("Ri.Gateway", "Initializing API gateway module")?;
566
567        let config = self.config.read().await;
568        logger.info(
569            "Ri.Gateway",
570            format!("Gateway will listen on {}:{}", config.listen_address, config.listen_port)
571        )?;
572
573        logger.info("Ri.Gateway", "API gateway module initialized successfully")?;
574        Ok(())
575    }
576
577    /// Performs cleanup after the gateway has shut down.
578    /// 
579    /// This method ensures proper resource cleanup during gateway shutdown:
580    /// - Clears all rate limiter buckets
581    /// - Resets the circuit breaker to closed state
582    /// - Clears all registered routes
583    /// 
584    /// # Parameters
585    /// 
586    /// - `_ctx`: Service context (not used in this implementation)
587    /// 
588    /// # Returns
589    /// 
590    /// A `RiResult<()>` indicating success or failure
591    /// 
592    /// # Logs
593    /// 
594    /// Logs cleanup progress at INFO level for debugging purposes
595    async fn after_shutdown(&mut self, _ctx: &mut RiServiceContext) -> crate::core::RiResult<()> {
596        log::info!("Cleaning up Ri Gateway Module");
597        
598        if let Some(rate_limiter) = &self.rate_limiter {
599            rate_limiter.clear_all_buckets();
600            log::info!("Rate limiter cleanup completed");
601        }
602        
603        if let Some(circuit_breaker) = &self.circuit_breaker {
604            circuit_breaker.reset();
605            log::info!("Circuit breaker reset completed");
606        }
607        
608        self.router.clear_routes();
609        log::info!("Router cleanup completed");
610        
611        log::info!("Ri Gateway Module cleanup completed");
612        Ok(())
613    }
614}
615
616#[cfg(feature = "pyo3")]
617/// Python bindings for RiGateway
618#[pyo3::prelude::pymethods]
619impl RiGateway {
620    #[new]
621    fn py_new() -> Self {
622        Self::new()
623    }
624}