gato_simple_router/
simple_router.rs

1use gato_core::kernel::{Router, Request, Response, Logger, RequestBuilder};
2use std::collections::HashMap;
3
4struct Endpoint {
5    uri: String,
6    method: String,
7    handler: &'static dyn Fn(&Request) -> Response
8}
9
10impl Endpoint {
11    pub fn new(uri: &str, method: &str, handler: &'static dyn Fn(&Request) -> Response) -> Self {
12        return Endpoint { uri: uri.to_string(), handler, method: method.to_string() };
13    }
14}
15
16pub struct SimpleRouter { }
17
18impl SimpleRouter {
19    pub fn new() -> Self {
20        return SimpleRouter { }
21    }
22    pub fn any(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
23        unsafe {
24            ENDPOINTS.push(Endpoint::new(endpoint, "ANY", f));
25        }
26    }
27    pub fn options(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
28        unsafe {
29            ENDPOINTS.push(Endpoint::new(endpoint, "OPTIONS", f));
30        }
31    }
32    pub fn head(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
33        unsafe {
34            ENDPOINTS.push(Endpoint::new(endpoint, "HEAD", f));
35        }
36    }
37    pub fn get(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
38        unsafe {
39            ENDPOINTS.push(Endpoint::new(endpoint, "GET", f));
40        }
41    }
42    pub fn post(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
43        unsafe {
44            ENDPOINTS.push(Endpoint::new(endpoint, "POST", f));
45        }
46    }
47    pub fn put(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
48        unsafe {
49            ENDPOINTS.push(Endpoint::new(endpoint, "PUT", f));
50        }
51    }
52    pub fn patch(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
53        unsafe {
54            ENDPOINTS.push(Endpoint::new(endpoint, "PATCH", f));
55        }
56    }
57    pub fn delete(endpoint: &str, f: &'static dyn Fn(&Request) -> Response) {
58        unsafe {
59            ENDPOINTS.push(Endpoint::new(endpoint, "DELETE", f));
60        }
61    }
62}
63
64impl SimpleRouter {
65    fn match_route_name(&self, uri: &str, router: &str, request_builder: &mut RequestBuilder) -> bool {
66        if uri == "*" || uri == router {
67            return true;
68        }
69        let mut params : HashMap<String, String> = HashMap::new();
70        
71        // Remove QueryString
72        let p: Vec<&str> = router.split("?").collect();
73        
74        // Get ROUTER Folders
75        let route_piece : Vec<&str> = p[0].split("/").filter(|&x| x != "").collect();
76        
77        // Get URL Folders
78        let uri_piece : Vec<&str> = uri.split("/").filter(|&x| x != "").collect();
79        
80        // Get URL QueryString Variables
81        let url_query: Vec<&str> = if p.len() > 1 { p[1].split("&").collect() } else { vec!() };
82        
83        let limit = uri_piece.len();
84        for i in 0..limit {
85            if route_piece.len() <= i {
86                return false;
87            }
88            let is_param =
89                uri_piece[i].find("{").is_some() &&
90                uri_piece[i].find("}").is_some();
91
92            if route_piece[i] != uri_piece[i] && !is_param {
93                return false;
94            } else if is_param && uri_piece[i] == "" {
95                return false;
96            } else if is_param {
97                let param = uri_piece[i].to_string();
98                params.insert(param.replace("{", "").replace("}", ""), route_piece[i].to_string());
99            }
100        }
101
102        if uri_piece.len() == route_piece.len() {
103            request_builder.add_params(params);
104            let querystring: HashMap<_, _> = url_query.iter().map(|&params| {
105                let p: Vec<_> = params.split("=").collect();
106                return if p.len() == 2 {
107                    (p[0].to_string(), p[1].to_string())
108                } else {
109                    (p[0].to_string(), String::new())
110                }
111            }).collect();
112            request_builder.add_querystring(querystring);
113            return true;
114        }
115
116        return false;
117    }
118}
119
120impl Router for SimpleRouter {
121    fn boot(&self) -> () {
122        Logger::info("SimpleRouter[boot]");
123    }
124    fn handle(&self, request_builder: &mut RequestBuilder) -> Response {
125        Logger::info("SimpleRouter[handle]");
126
127        let endpoints = unsafe { ENDPOINTS.iter() };
128        let request = request_builder.get_request();
129
130        for endpoint in endpoints {
131            let did_match_route : bool = self.match_route_name(
132                endpoint.uri.as_str(), request.get_uri().as_str(), request_builder
133            );
134            if did_match_route {
135                let req_method = request.get_method();
136                if endpoint.method == "ANY" || endpoint.method == req_method {
137                    let request = request_builder.get_request();
138                    return (endpoint.handler)(&request);
139                } else if req_method == "OPTIONS" || req_method == "HEAD" {
140                    return Response::new().status(200).raw("");
141                }
142            }
143        }
144
145        return Response::new().status(404).json(serde_json::json!({
146            "error": "Page Not Found"
147        }));
148    }
149}
150
151const fn new_vec() -> Vec<Endpoint> {
152    return Vec::new();
153}
154
155static mut ENDPOINTS : Vec<Endpoint> = new_vec();