gato_simple_router/
simple_router.rs1use 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 let p: Vec<&str> = router.split("?").collect();
73
74 let route_piece : Vec<&str> = p[0].split("/").filter(|&x| x != "").collect();
76
77 let uri_piece : Vec<&str> = uri.split("/").filter(|&x| x != "").collect();
79
80 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(|¶ms| {
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();