rocal_core/
router.rs

1use std::{collections::HashMap, future::Future, pin::Pin};
2
3use regex::Regex;
4use url::Url;
5
6use crate::enums::request_method::RequestMethod;
7
8type Action = Box<dyn Fn(HashMap<String, String>) -> Pin<Box<dyn Future<Output = ()>>>>;
9
10struct Node {
11    children: HashMap<String, Node>,
12    action: Option<Action>,
13}
14
15pub struct Router {
16    root: Node,
17}
18
19impl Router {
20    const HOST: &str = "https://www.example.com";
21
22    pub fn new() -> Self {
23        Router {
24            root: Node {
25                children: HashMap::new(),
26                action: None,
27            },
28        }
29    }
30
31    pub fn register(&mut self, method: RequestMethod, route: &str, action: Action) {
32        let mut ptr = &mut self.root;
33
34        if !ptr.children.contains_key(&method.to_string()) {
35            ptr.children.insert(
36                method.to_string(),
37                Node {
38                    children: HashMap::new(),
39                    action: None,
40                },
41            );
42        }
43
44        ptr = ptr.children.get_mut(&method.to_string()).unwrap();
45
46        for s in route.split("/") {
47            if !ptr.children.contains_key(s) {
48                ptr.children.insert(
49                    s.to_string(),
50                    Node {
51                        children: HashMap::new(),
52                        action: None,
53                    },
54                );
55            }
56
57            ptr = ptr.children.get_mut(s).unwrap();
58        }
59
60        ptr.action = Some(action);
61    }
62
63    pub async fn resolve(
64        &self,
65        method: RequestMethod,
66        route: &str,
67        action_args: Option<HashMap<String, String>>,
68    ) -> bool {
69        let mut route = route.to_string();
70        let path_param_regex: Regex = Regex::new(r"^<(?<key>.+)>$").unwrap();
71
72        let mut action_args: HashMap<String, String> = action_args.unwrap_or(HashMap::new());
73
74        if let Ok(url) = Url::parse(&format!("{}{}", Self::HOST, route)) {
75            for (k, v) in url.query_pairs() {
76                action_args.insert(k.to_string(), v.to_string());
77            }
78            route = url.path().to_string();
79        }
80
81        let mut ptr = &self.root;
82
83        if !ptr.children.contains_key(&method.to_string()) {
84            return false;
85        }
86
87        ptr = ptr.children.get(&method.to_string()).unwrap();
88
89        for s in route.split("/") {
90            if !ptr.children.contains_key(s) {
91                if let Some(param) = ptr
92                    .children
93                    .keys()
94                    .find(|key| path_param_regex.is_match(key))
95                {
96                    let caps = path_param_regex.captures(&param).unwrap();
97                    action_args.insert(caps["key"].to_string(), s.to_string());
98                    ptr = ptr.children.get(param).unwrap();
99                    continue;
100                } else {
101                    return false;
102                }
103            }
104
105            ptr = ptr.children.get(s).unwrap();
106        }
107
108        if let Some(action) = &ptr.action {
109            action(action_args).await;
110            true
111        } else {
112            false
113        }
114    }
115}