1mod predicates;
20
21#[cfg(test)]
22mod tests;
23
24pub use predicates::*;
25
26use std::collections::HashMap;
27use std::sync::Arc;
28use async_trait::async_trait;
29use tokio::sync::RwLock;
30use serde::{Serialize, Deserialize};
31
32use crate::config::Config;
33use crate::core::{ProxyRequest, ProxyError, Route};
34use crate::{debug_fmt, error_fmt, trace_fmt, warn_fmt, FilterFactory};
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct RouteConfig {
39 pub id: String,
41 pub target: String,
43 #[serde(default)]
45 pub filters: Vec<FilterConfig>,
46 #[serde(default = "default_priority")]
48 pub priority: i32,
49 #[serde(default)]
51 pub predicates: Vec<PredicateConfig>,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct FilterConfig {
57 #[serde(rename = "type")]
59 pub type_: String,
60 pub config: serde_json::Value,
62}
63
64fn default_priority() -> i32 {
65 0
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct PredicateConfig {
71 pub type_: String,
73 pub config: serde_json::Value,
75}
76
77#[async_trait]
79pub trait Predicate: Send + Sync + std::fmt::Debug {
80 async fn matches(&self, request: &ProxyRequest) -> bool;
82
83 fn predicate_type(&self) -> &str;
85}
86
87#[derive(Debug)]
89pub struct PredicateRouter {
90 routes: RwLock<HashMap<String, RouteWithPredicates>>,
92 sorted_routes: RwLock<Vec<RouteWithPredicates>>,
94 config: Arc<Config>,
96}
97
98#[derive(Debug, Clone)]
100struct RouteWithPredicates {
101 route: Route,
103 predicates: Vec<Arc<dyn Predicate>>,
105 priority: i32,
107}
108
109impl PredicateRouter {
110 pub async fn new(config: Arc<Config>) -> Result<Self, ProxyError> {
112 let router = Self {
113 routes: RwLock::new(HashMap::new()),
114 sorted_routes: RwLock::new(Vec::new()),
115 config,
116 };
117
118 router.load_routes_from_config().await?;
120
121 Ok(router)
122 }
123
124 async fn load_routes_from_config(&self) -> Result<(), ProxyError> {
126 let route_configs: Option<Vec<RouteConfig>> = self.config.get("routes")?;
128
129 if let Some(route_configs) = route_configs {
130 for route_config in route_configs {
132 let mut predicates = Vec::new();
134 for predicate_config in &route_config.predicates {
135 let predicate = PredicateFactory::create_predicate(
136 &predicate_config.type_,
137 predicate_config.config.clone(),
138 )?;
139 predicates.push(predicate);
140 }
141
142 let mut filters = Vec::new();
144 for filter_config in &route_config.filters {
145 let filter = FilterFactory::create_filter(
146 &filter_config.type_,
147 filter_config.config.clone(),
148 )?;
149 filters.push(filter);
150 }
151
152 let path_pattern = route_config.predicates.iter()
154 .find(|p| p.type_ == "path")
155 .map(|p| p.config.get("pattern")
156 .and_then(|v| v.as_str())
157 .unwrap_or("/*"))
158 .unwrap_or("/*")
159 .to_string();
160
161 let route = Route {
162 id: route_config.id.clone(),
163 target_base_url: route_config.target.clone(),
164 path_pattern,
165 filters: if filters.is_empty() { None } else { Some(filters) },
166 };
167
168 self.add_route_with_predicates(
170 route,
171 predicates,
172 route_config.priority,
173 ).await?;
174 }
175 }
176
177 Ok(())
178 }
179
180 async fn add_route_with_predicates(
182 &self,
183 route: Route,
184 predicates: Vec<Arc<dyn Predicate>>,
185 priority: i32,
186 ) -> Result<(), ProxyError> {
187 let route_with_predicates = RouteWithPredicates {
188 route: route.clone(),
189 predicates,
190 priority,
191 };
192
193 {
195 let mut routes = self.routes.write().await;
196 routes.insert(route.id.clone(), route_with_predicates.clone());
197 }
198
199 {
201 let mut sorted_routes = self.sorted_routes.write().await;
202 sorted_routes.push(route_with_predicates);
203
204 sorted_routes.sort_by(|a, b| b.priority.cmp(&a.priority));
206 }
207
208 Ok(())
209 }
210}
211
212#[async_trait]
213impl crate::core::Router for PredicateRouter {
214 async fn route(&self, request: &ProxyRequest) -> Result<Route, ProxyError> {
215 let sorted_routes = self.sorted_routes.read().await;
217 trace_fmt!("Router", "Routing request {} {} against {} routes",
218 request.method, request.path, sorted_routes.len());
219
220 for route_with_predicates in sorted_routes.iter() {
221 let mut all_match = true;
223 let route_id = &route_with_predicates.route.id;
224
225 trace_fmt!("Router", "Checking route '{}' with {} predicates",
226 route_id, route_with_predicates.predicates.len());
227
228 for predicate in &route_with_predicates.predicates {
229 let predicate_type = predicate.predicate_type();
230 let matches = predicate.matches(request).await;
231
232 trace_fmt!("Router", " Predicate '{}' for route '{}': {}",
233 predicate_type, route_id, if matches { "match" } else { "no match" });
234
235 if !matches {
236 all_match = false;
237 break;
238 }
239 }
240
241 if all_match {
243 debug_fmt!("Router", "Route '{}' matched request {} {}",
244 route_id, request.method, request.path);
245 return Ok(route_with_predicates.route.clone());
246 }
247 }
248
249 let err = ProxyError::RoutingError(format!("No route matched the request: {} {}",
251 request.method, request.path));
252 warn_fmt!("Router", "{}", err);
253 Err(err)
254 }
255
256 async fn get_routes(&self) -> Vec<Route> {
257 let routes = self.routes.read().await;
258 routes.values().map(|r| r.route.clone()).collect()
259 }
260
261 async fn add_route(&self, route: Route) -> Result<(), ProxyError> {
262 self.add_route_with_predicates(route, Vec::new(), 0).await
265 }
266
267 async fn remove_route(&self, route_id: &str) -> Result<(), ProxyError> {
268 {
270 let mut routes = self.routes.write().await;
271 if routes.remove(route_id).is_none() {
272 return Err(ProxyError::RoutingError(format!("Route not found: {}", route_id)));
273 }
274 }
275
276 {
278 let mut sorted_routes = self.sorted_routes.write().await;
279 sorted_routes.retain(|r| r.route.id != route_id);
280 }
281
282 Ok(())
283 }
284}
285
286#[derive(Debug)]
288pub struct PredicateFactory;
289
290impl PredicateFactory {
291 pub fn create_predicate(
293 predicate_type: &str,
294 config: serde_json::Value,
295 ) -> Result<Arc<dyn Predicate>, ProxyError> {
296 debug_fmt!("Router", "Creating predicate of type '{}' with config: {}",
297 predicate_type, config);
298
299 match predicate_type {
300 "path" => {
301 let path_config: PathPredicateConfig = serde_json::from_value(config)
302 .map_err(|e| {
303 let err = ProxyError::RoutingError(
304 format!("Invalid path predicate config: {}", e)
305 );
306 error_fmt!("Router", "{}", err);
307 err
308 })?;
309
310 match PathPredicate::new(path_config) {
311 Ok(predicate) => Ok(Arc::new(predicate)),
312 Err(error) => Err(error),
313 }
314 },
315 "method" => {
316 let method_config: MethodPredicateConfig = serde_json::from_value(config)
317 .map_err(|e| {
318 let err = ProxyError::RoutingError(
319 format!("Invalid method predicate config: {}", e)
320 );
321 error_fmt!("Router", "{}", err);
322 err
323 })?;
324 Ok(Arc::new(MethodPredicate::new(method_config)))
325 },
326 "header" => {
327 let header_config: HeaderPredicateConfig = serde_json::from_value(config)
328 .map_err(|e| {
329 let err = ProxyError::RoutingError(
330 format!("Invalid header predicate config: {}", e)
331 );
332 error_fmt!("Router", "{}", err);
333 err
334 })?;
335 Ok(Arc::new(HeaderPredicate::new(header_config)))
336 },
337 "query" => {
338 let query_config: QueryPredicateConfig = serde_json::from_value(config)
339 .map_err(|e| {
340 let err = ProxyError::RoutingError(
341 format!("Invalid query predicate config: {}", e)
342 );
343 error_fmt!("Router", "{}", err);
344 err
345 })?;
346 Ok(Arc::new(QueryPredicate::new(query_config)))
347 },
348 _ => {
349 let err = ProxyError::RoutingError(
350 format!("Unknown predicate type: {}", predicate_type)
351 );
352 error_fmt!("Router", "{}", err);
353 Err(err)
354 },
355 }
356 }
357}