1mod predicates;
20
21#[cfg(test)]
22mod tests;
23
24pub use predicates::*;
25
26use std::collections::HashMap;
27use std::sync::Arc;
28use once_cell::sync::Lazy;
29use std::sync::RwLock as StdRwLock;
30use async_trait::async_trait;
31use tokio::sync::RwLock;
32use serde::{Serialize, Deserialize};
33
34use crate::config::Config;
35use crate::core::{ProxyRequest, ProxyError, Route};
36use crate::{debug_fmt, error_fmt, trace_fmt, warn_fmt, FilterFactory};
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct RouteConfig {
41 pub id: String,
43 pub target: String,
45 #[serde(default)]
47 pub filters: Vec<FilterConfig>,
48 #[serde(default = "default_priority")]
50 pub priority: i32,
51 #[serde(default)]
53 pub predicates: Vec<PredicateConfig>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct FilterConfig {
59 #[serde(rename = "type")]
61 pub type_: String,
62 pub config: serde_json::Value,
64}
65
66fn default_priority() -> i32 {
67 0
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct PredicateConfig {
73 pub type_: String,
75 pub config: serde_json::Value,
77}
78
79#[async_trait]
81pub trait Predicate: Send + Sync + std::fmt::Debug {
82 async fn matches(&self, request: &ProxyRequest) -> bool;
84
85 fn predicate_type(&self) -> &str;
87}
88
89pub type PredicateConstructor =
91fn(serde_json::Value) -> Result<Arc<dyn Predicate>, ProxyError>;
92
93
94static PREDICATE_REGISTRY: Lazy<StdRwLock<HashMap<String, PredicateConstructor>>> =
97 Lazy::new(|| StdRwLock::new(HashMap::new()));
98
99pub fn register_predicate(name: &str, ctor: PredicateConstructor) {
101 PREDICATE_REGISTRY
102 .write()
103 .expect("PREDICATE_REGISTRY poisoned")
104 .insert(name.to_string(), ctor);
105}
106
107fn get_registered_predicate(name: &str) -> Option<PredicateConstructor> {
109 PREDICATE_REGISTRY
110 .read()
111 .expect("PREDICATE_REGISTRY poisoned")
112 .get(name)
113 .copied()
114}
115
116#[derive(Debug)]
118pub struct PredicateRouter {
119 routes: RwLock<HashMap<String, RouteWithPredicates>>,
121 sorted_routes: RwLock<Vec<RouteWithPredicates>>,
123 config: Arc<Config>,
125}
126
127#[derive(Debug, Clone)]
129struct RouteWithPredicates {
130 route: Route,
132 predicates: Vec<Arc<dyn Predicate>>,
134 priority: i32,
136}
137
138impl PredicateRouter {
139 pub async fn new(config: Arc<Config>) -> Result<Self, ProxyError> {
141 let router = Self {
142 routes: RwLock::new(HashMap::new()),
143 sorted_routes: RwLock::new(Vec::new()),
144 config,
145 };
146
147 router.load_routes_from_config().await?;
149
150 Ok(router)
151 }
152
153 async fn load_routes_from_config(&self) -> Result<(), ProxyError> {
155 let route_configs: Option<Vec<RouteConfig>> = self.config.get("routes")?;
157
158 if let Some(route_configs) = route_configs {
159 for route_config in route_configs {
161 let mut predicates = Vec::new();
163 for predicate_config in &route_config.predicates {
164 let predicate = PredicateFactory::create_predicate(
165 &predicate_config.type_,
166 predicate_config.config.clone(),
167 )?;
168 predicates.push(predicate);
169 }
170
171 let mut filters = Vec::new();
173 for filter_config in &route_config.filters {
174 let filter = FilterFactory::create_filter(
175 &filter_config.type_,
176 filter_config.config.clone(),
177 )?;
178 filters.push(filter);
179 }
180
181 let path_pattern = route_config.predicates.iter()
183 .find(|p| p.type_ == "path")
184 .map(|p| p.config.get("pattern")
185 .and_then(|v| v.as_str())
186 .unwrap_or("/*"))
187 .unwrap_or("/*")
188 .to_string();
189
190 let route = Route {
191 id: route_config.id.clone(),
192 target_base_url: route_config.target.clone(),
193 path_pattern,
194 filters: if filters.is_empty() { None } else { Some(filters) },
195 };
196
197 self.add_route_with_predicates(
199 route,
200 predicates,
201 route_config.priority,
202 ).await?;
203 }
204 }
205
206 Ok(())
207 }
208
209 async fn add_route_with_predicates(
211 &self,
212 route: Route,
213 predicates: Vec<Arc<dyn Predicate>>,
214 priority: i32,
215 ) -> Result<(), ProxyError> {
216 let route_with_predicates = RouteWithPredicates {
217 route: route.clone(),
218 predicates,
219 priority,
220 };
221
222 {
224 let mut routes = self.routes.write().await;
225 routes.insert(route.id.clone(), route_with_predicates.clone());
226 }
227
228 {
230 let mut sorted_routes = self.sorted_routes.write().await;
231 sorted_routes.push(route_with_predicates);
232
233 sorted_routes.sort_by(|a, b| b.priority.cmp(&a.priority));
235 }
236
237 Ok(())
238 }
239}
240
241#[async_trait]
242impl crate::core::Router for PredicateRouter {
243 async fn route(&self, request: &ProxyRequest) -> Result<Route, ProxyError> {
244 let sorted_routes = self.sorted_routes.read().await;
246 trace_fmt!("Router", "Routing request {} {} against {} routes",
247 request.method, request.path, sorted_routes.len());
248
249 for route_with_predicates in sorted_routes.iter() {
250 let mut all_match = true;
252 let route_id = &route_with_predicates.route.id;
253
254 trace_fmt!("Router", "Checking route '{}' with {} predicates",
255 route_id, route_with_predicates.predicates.len());
256
257 for predicate in &route_with_predicates.predicates {
258 let predicate_type = predicate.predicate_type();
259 let matches = predicate.matches(request).await;
260
261 trace_fmt!("Router", " Predicate '{}' for route '{}': {}",
262 predicate_type, route_id, if matches { "match" } else { "no match" });
263
264 if !matches {
265 all_match = false;
266 break;
267 }
268 }
269
270 if all_match {
272 debug_fmt!("Router", "Route '{}' matched request {} {}",
273 route_id, request.method, request.path);
274 return Ok(route_with_predicates.route.clone());
275 }
276 }
277
278 let err = ProxyError::RoutingError(format!("No route matched the request: {} {}",
280 request.method, request.path));
281 warn_fmt!("Router", "{}", err);
282 Err(err)
283 }
284
285 async fn get_routes(&self) -> Vec<Route> {
286 let routes = self.routes.read().await;
287 routes.values().map(|r| r.route.clone()).collect()
288 }
289
290 async fn add_route(&self, route: Route) -> Result<(), ProxyError> {
291 self.add_route_with_predicates(route, Vec::new(), 0).await
294 }
295
296 async fn remove_route(&self, route_id: &str) -> Result<(), ProxyError> {
297 {
299 let mut routes = self.routes.write().await;
300 if routes.remove(route_id).is_none() {
301 return Err(ProxyError::RoutingError(format!("Route not found: {}", route_id)));
302 }
303 }
304
305 {
307 let mut sorted_routes = self.sorted_routes.write().await;
308 sorted_routes.retain(|r| r.route.id != route_id);
309 }
310
311 Ok(())
312 }
313}
314
315#[derive(Debug)]
317pub struct PredicateFactory;
318
319impl PredicateFactory {
320 pub fn create_predicate(
322 predicate_type: &str,
323 config: serde_json::Value,
324 ) -> Result<Arc<dyn Predicate>, ProxyError> {
325 debug_fmt!("Router", "Creating predicate of type '{}' with config: {}",
326 predicate_type, config);
327
328 if let Some(ctor) = get_registered_predicate(predicate_type) {
330 return ctor(config);
331 }
332
333 match predicate_type {
334 "path" => {
335 let path_config: PathPredicateConfig = serde_json::from_value(config)
336 .map_err(|e| {
337 let err = ProxyError::RoutingError(
338 format!("Invalid path predicate config: {}", e)
339 );
340 error_fmt!("Router", "{}", err);
341 err
342 })?;
343
344 match PathPredicate::new(path_config) {
345 Ok(predicate) => Ok(Arc::new(predicate)),
346 Err(error) => Err(error),
347 }
348 },
349 "method" => {
350 let method_config: MethodPredicateConfig = serde_json::from_value(config)
351 .map_err(|e| {
352 let err = ProxyError::RoutingError(
353 format!("Invalid method predicate config: {}", e)
354 );
355 error_fmt!("Router", "{}", err);
356 err
357 })?;
358 Ok(Arc::new(MethodPredicate::new(method_config)))
359 },
360 "header" => {
361 let header_config: HeaderPredicateConfig = serde_json::from_value(config)
362 .map_err(|e| {
363 let err = ProxyError::RoutingError(
364 format!("Invalid header predicate config: {}", e)
365 );
366 error_fmt!("Router", "{}", err);
367 err
368 })?;
369 Ok(Arc::new(HeaderPredicate::new(header_config)))
370 },
371 "query" => {
372 let query_config: QueryPredicateConfig = serde_json::from_value(config)
373 .map_err(|e| {
374 let err = ProxyError::RoutingError(
375 format!("Invalid query predicate config: {}", e)
376 );
377 error_fmt!("Router", "{}", err);
378 err
379 })?;
380 Ok(Arc::new(QueryPredicate::new(query_config)))
381 },
382 _ => {
383 let err = ProxyError::RoutingError(
384 format!("Unknown predicate type: {}", predicate_type)
385 );
386 error_fmt!("Router", "{}", err);
387 Err(err)
388 },
389 }
390 }
391}