1use std::{any::type_name, collections::{HashMap, HashSet}, sync::RwLock};
2
3use dce_util::{arena_tree::{ArenaTree, KeyFactory}, result::{DceError, DceResult}};
4use log::{debug, warn};
5
6use crate::{api::{Api, Handler, Hook, Suffix, MARK_PATH_PART_SEPARATOR, MARK_SUFFIX_BOUNDARY, MARK_VARIABLE_CLOSING, MARK_VARIABLE_OPENER, MARK_VAR_TYPE_EMPTABLE_VECTOR, MARK_VAR_TYPE_OPTIONAL, MARK_VAR_TYPE_VECTOR}, context::Param, protocol::RoutableProtocol};
7
8const CODE_NOT_FOUND: isize = 404;
9const HOOK_PATH_SUFFIXES: [&str; 2] = ["+", "*"];
10
11pub struct Router<Rp: RoutableProtocol + 'static> {
12 path_separator: &'static str,
13 suffix_boundary: &'static str,
14 api_buffer: RwLock<Vec<&'static Api<Rp>>>,
15 raw_omitted_paths: Vec<&'static str>,
16 id_api_mapping: HashMap<&'static str, &'static Api<Rp>>,
17 apis_mapping: HashMap<&'static str, Vec<&'static Api<Rp>>>,
18 apis_tree: ArenaTree<ApiBranch<Rp>, &'static str>,
19 before_mapping: HashMap<&'static str, Hook<Rp>>,
20 after_mapping: HashMap<&'static str, Hook<Rp>>,
21 path_before_mapping: HashMap<&'static str, &'static str>,
22 path_after_mapping: HashMap<&'static str, &'static str>,
23}
24
25impl <Rp: RoutableProtocol> Router<Rp> {
26 pub fn new() -> Self {
27 Router {
28 path_separator: MARK_PATH_PART_SEPARATOR,
29 suffix_boundary: MARK_SUFFIX_BOUNDARY,
30 api_buffer: Default::default(),
31 raw_omitted_paths: Default::default(),
32 id_api_mapping: Default::default(),
33 apis_mapping: Default::default(),
34 apis_tree: ArenaTree::new(ApiBranch::new("")),
35 before_mapping: Default::default(),
36 after_mapping: Default::default(),
37 path_before_mapping: Default::default(),
38 path_after_mapping: Default::default(),
39 }
40 }
41
42 pub fn bind(&mut self, path: &'static str, handler: Handler<Rp>) -> &mut Self {
43 let api = Api::new(path);
44 let api = api.bind_handler(handler);
45 self.add(api)
46 }
47
48 pub fn bind_api(&mut self, api: Api<Rp>, handler: Handler<Rp>) -> &mut Self {
49 let api = api.bind_handler(handler);
50 self.add(api)
51 }
52
53 pub fn register(&mut self, api_supplier: fn() -> Api<Rp>) -> &mut Self {
54 let api = api_supplier();
55 self.add(api)
56 }
57
58 pub fn add(&mut self, api: Api<Rp>) -> &mut Self {
59 let api = Box::leak(Box::new(api.upgrade()));
60 let mut api_buffer = self.api_buffer.write().unwrap();
61 api_buffer.push(api);
62 if api.omission {
63 self.raw_omitted_paths.push(api.path);
64 }
65 if let Some(id) = &api.id {
66 self.id_api_mapping.insert(id, api);
67 }
68 drop(api_buffer);
69 self
70 }
71
72 pub fn ready(&mut self) {
73 self.build_tree();
74 let mut api_buffer = self.api_buffer.write().unwrap();
75 while api_buffer.len() > 0 {
76 let api = api_buffer.remove(0);
77 let path = self.omitted_path(api.path);
78 let mut apis = vec![api];
79 let mut suffixes = api.suffixes.iter().map(|s| s).collect::<HashSet<_>>();
80 let mut i = 0;
81 while i < api_buffer.len() {
82 if path == self.omitted_path(api_buffer.get(i).unwrap().path) {
84 let omitted_api = api_buffer.remove(i);
85 apis.push(omitted_api);
86 suffixes.extend(omitted_api.suffixes.iter().collect::<Vec<_>>());
87 } else {
88 i += 1;
89 }
90 }
91 for suffix in suffixes {
93 self.apis_mapping.insert(Box::leak(Self::suffixed_path(path.as_str(), Some(suffix)).into_boxed_str()),
95 apis.iter().filter(|a| a.suffixes.contains(suffix)).map(|a| *a).collect::<Vec<_>>());
96 }
97 }
98 self.path_before_mapping = self.map_middleware(&self.before_mapping, true);
100 self.path_after_mapping = self.map_middleware(&self.after_mapping, false);
101 }
102
103 fn build_tree(&mut self) {
104 let api_buffer = self.api_buffer.write().unwrap();
106 let mut path_apis = api_buffer.iter().map(|a| a.path).collect::<HashSet<_>>()
107 .into_iter().map(|p| (p, ApiBranch::new(p)))
108 .collect::<HashMap<_, _>>();
109 for api in api_buffer.iter() {
110 path_apis.get_mut(api.path).map(|v| v.push(*api));
111 }
112 self.apis_tree.fill(path_apis.into_values().collect::<Vec<_>>());
114 for i in 1..self.apis_tree.len() {
116 let mut is_omitted_child = false;
117 let node = (*self.apis_tree).get(i).unwrap();
118 let node_var_type = node.element().var_type.clone();
119 let mut parent_index = *node.parent_index();
120 while let Some(Some(parent)) = parent_index.map(|pi| (*self.apis_tree).get_mut(pi)) {
121 parent_index = *parent.parent_index();
122 if parent.element().is_omission {
123 is_omitted_child = true;
124 continue;
125 }
126 match parent.element().var_type {
127 VarType::Required(_) => parent.element_mut().is_mid_var = true,
128 VarType::NotVar => break,
129 _ => panic!(r#"Ambiguous type var "{}" cannot in middle."#, parent.element().id()),
130 };
131 if !matches!(node_var_type, VarType::NotVar) {
132 parent.element_mut().var_children.push(i);
133 } else if is_omitted_child {
134 parent.element_mut().omitted_children.push(i);
135 }
136 }
137 }
138 }
139
140 fn omitted_path(&self, path: &str) -> String {
141 let parts = path.split(MARK_PATH_PART_SEPARATOR).collect::<Vec<_>>();
143 parts.iter().enumerate()
144 .filter(|&(i, _)| !self.raw_omitted_paths.contains(&parts[..=i].join(MARK_PATH_PART_SEPARATOR).as_str()))
145 .map(|(_, p)| *p).collect::<Vec<_>>()
146 .join(MARK_PATH_PART_SEPARATOR)
147 }
148
149 fn suffixed_path(path: &str, suffix: Option<&Suffix>) -> String {
150 suffix.filter(|s| !s.as_ref().is_empty())
151 .map_or_else(|| path.to_owned(), |s| format!("{}{}{}", path, MARK_SUFFIX_BOUNDARY, s.as_ref()))
152 }
153
154 fn map_middleware(&self, handler_mapping: &HashMap<&'static str, Hook<Rp>>, pre: bool) -> HashMap<&'static str, &'static str> {
155 let mut apis_paths = self.apis_mapping.keys().collect::<Vec<_>>();
156 let mut path_mapping: HashMap<&'static str, &'static str> = Default::default();
157
158 for (key, _) in handler_mapping {
159 let mut path = key.to_string();
160 let mut suffix = String::new();
161 let wildcard = HOOK_PATH_SUFFIXES.iter().find(|s| key.ends_with(*s));
162
163 if let Some(w) = wildcard {
164 suffix = key[key.len() - w.len()..].to_string();
165 path = key[..key.len() - w.len()].to_string();
166 }
167 apis_paths = apis_paths
168 .into_iter()
169 .filter(|api_path| {
170 if {
171 if suffix != HOOK_PATH_SUFFIXES[0] && path.eq(*api_path) {
172 true
173 } else if matches!(wildcard, Some(_)) {
174 path.is_empty() || api_path.starts_with(&(path.clone() + MARK_PATH_PART_SEPARATOR))
175 } else {
176 false
177 }
178 } {
179 Self::hook_override_warn(api_path, &path_mapping, pre);
180 path_mapping.insert(api_path, key);
181 false
182 } else {
183 true
184 }
185 })
186 .collect();
187 }
188 path_mapping
189 }
190
191 fn hook_override_warn(path: &str, mapping: &HashMap<&'static str, &'static str>, pre: bool) {
192 if mapping.contains_key(path) {
193 let hook = if pre { "pre-handler" } else { "post-handler" };
194 warn!(r#"Path "{}" already has a {}; reassigning it will overwrite the current one."#, path, hook);
195 }
196 }
197
198 pub fn lookup(&self, rp: &Rp) -> DceResult<RouteMatch<'_, Rp>> {
199 self.lookup_api(rp)
200 .map(|(api, params, suffix)| {
201 let pre_hook = self.path_before_mapping.get(api.path)
202 .map(|p| self.before_mapping.get(p)).flatten();
203 let post_hook = self.path_after_mapping.get(api.path)
204 .map(|p| self.after_mapping.get(p)).flatten();
205 RouteMatch{api, params, suffix, pre_hook, post_hook}
206 })
207 }
208
209 fn lookup_api(&self, rp: &Rp) -> DceResult<(&'static Api<Rp>, HashMap<String, Param>, Option<Suffix>)> {
210 let req_path = rp.path();
211 let mut api = None;
212 let mut suffix = None;
213 let mut params = HashMap::new();
214 let mut path = req_path;
215 while api.is_none() {
216 let mut apis = self.apis_mapping.get(path);
217 if apis.is_none() {
218 if let Some((tmp_path, tmp_params, tmp_suffix)) = self.lookup_var(path) {
219 apis = self.apis_mapping.get(Self::suffixed_path(tmp_path, tmp_suffix.as_ref()).as_str());
220 params = tmp_params;
221 suffix = tmp_suffix;
222 }
223 }
224 if let Some(apis) = apis {
225 if let Some(matched) = rp.match_api(apis) {
226 if let Some(redirect) = matched.redirect {
227 path = redirect;
228 continue;
229 }
230 api = Some(matched);
231 break;
232 }
233 }
234 if self.apis_mapping.is_empty() {
235 if self.api_buffer.read().unwrap().is_empty() {
236 panic!(r#"Lookup failed, "Router.apiBuffer" is empty, you may need to call the "Router.Push()" to bind apis"#);
237 } else {
238 panic!(r#"Router is not ready, please call "Router.ready()" first before lookup"#);
239 }
240 } else {
241 break;
242 }
243 }
244 api.map(|a| {
245 debug!(r#"{}: path "{}" matched api "{}""#, type_name::<Rp>(), req_path, a.path);
246 (a, params, suffix)
247 }).ok_or_else(|| DceError::pub_msg(CODE_NOT_FOUND, format!(r#"path "{}" route failed, could not matched by Router"#, path)))
248 }
249
250 fn lookup_var(&self, path: &str) -> Option<(&'static str, HashMap<String, Param>, Option<Suffix>)> {
251 let mut path_parts = path.split(self.path_separator).collect::<Vec<_>>();
252 let mut branch_and_part_indexes = vec![(0, 0)];
253 let mut params = HashMap::new();
254 let mut target_api_branch = None;
255 let mut suffix = None;
256 'outer: while let Some((branch_index, part_index)) = branch_and_part_indexes.pop() {
257 let api_branch = (*self.apis_tree).get(branch_index).unwrap();
258 let is_last_part = part_index == path_parts.len() - 1;
259 let is_overflowed = part_index >= path_parts.len();
260 if is_overflowed && ! api_branch.element().apis.is_empty() {
261 target_api_branch = Some(api_branch);
263 break;
264 }
265 if ! is_overflowed {
266 if let Some((sub_api_index, matched_suffix)) = self.find_consider_suffix(path_parts[part_index], is_last_part, api_branch.child_indexes(), &api_branch.element().omitted_children) {
268 branch_and_part_indexes.push((sub_api_index, part_index + 1));
269 suffix = matched_suffix;
270 continue;
271 }
272 }
273
274 let insert_pos = branch_and_part_indexes.len();
275 for (var_branch_index, var_api_branch) in api_branch.element().var_children.iter().filter_map(
276 |i| self.apis_tree.by_index(*i).map(|n| (i, n))).collect::<Vec<_>>() {
277 if ! var_api_branch.element().is_mid_var {
278 match &var_api_branch.element().var_type {
280 VarType::Optional(_) if is_overflowed => {},
281 VarType::Optional(var_name) | VarType::Required(var_name) if is_last_part =>
282 suffix = self.suffix_trimmer(&mut path_parts, var_api_branch.element(),
283 &mut |ps|{ params.insert(var_name.clone(), Param::Scalar(ps.get(0).map(|p| p.to_string()).unwrap())); }),
284 VarType::EmptableVector(_) if is_overflowed => {},
285 VarType::EmptableVector(var_name) | VarType::Vector(var_name) if ! is_overflowed =>
286 suffix = self.suffix_trimmer(&mut path_parts, var_api_branch.element(),
287 &mut |ps|{ params.insert(var_name.clone(), Param::Vector(ps.iter().map(|p| p.to_string()).collect::<Vec<_>>())); }),
288 _ => continue,
289 };
290 target_api_branch = Some(var_api_branch);
291 break 'outer
292 } else if let VarType::Required(var_name) = &var_api_branch.element().var_type {
293 params.insert(var_name.clone(), Param::Scalar(path_parts[part_index].to_owned()));
295 branch_and_part_indexes.insert(insert_pos, (*var_branch_index, part_index + 1));
296 }
297 }
298 }
299 target_api_branch.map(|b| (b.element().path, params, suffix))
300 }
301
302 fn suffix_trimmer(&self, parts: &mut Vec<&str>, branch: &ApiBranch<Rp>, consumer: &mut dyn FnMut(&Vec<&str>)) -> Option<Suffix> {
303 let mut suffix = None;
306 if let Some(mut last_part) = parts.pop() {
307 if let Some(ts) = branch.apis.iter().flat_map(|a| &a.suffixes).find(|s| last_part.ends_with(format!("{}{}", self.suffix_boundary, s.as_ref()).as_str())) {
308 last_part = &last_part[..last_part.len() - self.suffix_boundary.len() - ts.as_ref().len()];
309 suffix = Some(ts.clone());
310 }
311 parts.push(last_part);
313 }
314 consumer(parts);
315 suffix
316 }
317
318 fn find_consider_suffix(&self, path_part: &str, is_last_part: bool, child_indexes: &Vec<usize>, omitted_indexes: &Vec<usize>) -> Option<(usize, Option<Suffix>)> {
319 let mut matches = self.find_from_indexes_by_part(child_indexes, path_part);
320 if matches.is_none() {
321 matches = self.find_from_indexes_by_part(omitted_indexes, path_part);
322 }
323 let mut suffix = None;
324 if matches.is_none() && is_last_part {
325 let mut boundary = Some(path_part.len());
326 loop {
327 if let Some((base_part, index)) = boundary.map(|i| (&path_part[..i], i)) {
328 matches = self.find_from_indexes_by_part(child_indexes, base_part);
329 if matches.is_none() {
330 matches = self.find_from_indexes_by_part(omitted_indexes, base_part);
331 }
332 suffix = matches.map(|(_, ab)| ab.apis.iter().flat_map(|a| &a.suffixes)
334 .find(|s| path_part[index + 1..].eq(s.as_ref())))
335 .flatten().map(|s| s.clone());
336 if suffix.is_none() {
337 boundary = path_part[..index].rfind(self.suffix_boundary);
339 continue;
340 }
341 }
342 break;
343 }
344 }
345 matches.map(|(i, _)| (i, suffix))
346 }
347
348 fn find_from_indexes_by_part(&self, indexes: &Vec<usize>, part: &str) -> Option<(usize, &ApiBranch<Rp>)> {
349 indexes.iter()
350 .filter_map(|i| self.apis_tree.by_index(*i).map(|n| (*i, n.element())))
351 .find(|(_, ab)| ab.path_part().eq(part))
352 }
353}
354
355pub struct RouteMatch<'a, Rp: RoutableProtocol + 'static> {
356 pub api: &'static Api<Rp>,
357 pub params: HashMap<String, Param>,
358 pub suffix: Option<Suffix>,
359 pub pre_hook: Option<&'a Hook<Rp>>,
360 pub post_hook: Option<&'a Hook<Rp>>,
361}
362
363#[derive(Clone)]
364pub enum VarType {
365 NotVar,
366 Required(String),
367 Optional(String),
368 Vector(String),
369 EmptableVector(String),
370}
371
372struct ApiBranch<Rp: RoutableProtocol + 'static> {
373 path: &'static str,
374 var_type: VarType,
375 is_mid_var: bool,
376 is_omission: bool,
377 apis: Vec<&'static Api<Rp>>,
378 var_children: Vec<usize>,
379 omitted_children: Vec<usize>,
380}
381
382impl <Rp: RoutableProtocol + 'static> ApiBranch<Rp> {
383 fn push(&mut self, api: &'static Api<Rp>) {
384 self.apis.push(api);
385 if api.omission {
386 self.is_omission = true;
387 }
388 }
389
390 fn path_part(&self) -> &str {
391 self.path.rfind(MARK_PATH_PART_SEPARATOR).map_or(self.path, |i| &self.path[i+1..])
392 }
393
394 fn new(path: &'static str) -> Self {
395 let mut var_type = VarType::NotVar;
396 if path.starts_with(MARK_VARIABLE_OPENER) && path.ends_with(MARK_VARIABLE_CLOSING) {
397 let mut var_name = path[MARK_VARIABLE_OPENER.len() .. path.len() - MARK_VARIABLE_CLOSING.len()].to_string();
398 if var_name.ends_with(MARK_VAR_TYPE_OPTIONAL) {
399 var_name = var_name[..var_name.len() - MARK_VAR_TYPE_OPTIONAL.len()].to_string();
400 var_type = VarType::Optional(var_name);
401 } else if var_name.ends_with(MARK_VAR_TYPE_EMPTABLE_VECTOR) {
402 var_name = var_name[..var_name.len() - MARK_VAR_TYPE_EMPTABLE_VECTOR.len()].to_string();
403 var_type = VarType::EmptableVector(var_name);
404 } else if var_name.ends_with(MARK_VAR_TYPE_VECTOR) {
405 var_name = var_name[..var_name.len() - MARK_VAR_TYPE_VECTOR.len()].to_string();
406 var_type = VarType::Vector(var_name);
407 } else {
408 var_type = VarType::Required(var_name);
409 }
410 }
411 Self {
412 path,
413 var_type,
414 is_mid_var: Default::default(),
415 is_omission: Default::default(),
416 apis: Default::default(),
417 var_children: Default::default(),
418 omitted_children: Default::default(),
419 }
420 }
421}
422
423impl <Rp: RoutableProtocol + 'static> KeyFactory<&'static str> for ApiBranch<Rp> {
424 fn id(&self) -> &'static str {
425 self.path
426 }
427
428 fn child_of(&self, parent: &Self) -> bool {
429 self.path.rfind(MARK_PATH_PART_SEPARATOR).map_or_else(|| parent.path.is_empty(), |i| self.path[..i].eq(parent.path))
430 }
431
432 fn new_parent(&self) -> Self {
433 Self::new(self.path.rfind(MARK_PATH_PART_SEPARATOR).map_or("", |i| &self.path[..i]))
434 }
435}