1use std::{collections::HashMap, sync::Arc};
2
3use crate::route::Route;
4
5#[allow(unused_imports)]
6use pillow_http::{handler::Handler, middlewares::Middleware, Request, Response};
7
8#[allow(dead_code)]
17pub struct MainRouter {
18 routes: HashMap<pillow_http::http_methods::HttpMethods, Vec<Route>>,
19}
20
21impl MainRouter {
22 pub fn new() -> Self {
24 Self {
25 routes: HashMap::new(),
26 }
27 }
28
29 pub fn routes(&self) -> &HashMap<pillow_http::http_methods::HttpMethods, Vec<Route>> {
31 &self.routes
32 }
33
34 fn get_routes_from_method(
35 &self,
36 method: &pillow_http::http_methods::HttpMethods,
37 ) -> Option<&Vec<Route>> {
38 self.routes.get(&method)
39 }
40
41 fn get_option_index(&self, uri: &pillow_http::Uri, routes_vec: &Vec<Route>) -> Option<usize> {
42 routes_vec.iter().position(|route| route.uri() == uri)
43 }
44
45 fn response_404(&self, response: &mut Response, request: &Request) -> Response {
46 response.set_status_code(pillow_http::status_code::StatusCode::ClientError(
47 pillow_http::status_code::ClientError::NotFound,
48 ));
49
50 response.add_header(
51 pillow_http::header::Header::ContentType,
52 "text/html".to_string(),
53 );
54
55 let content = format!(
56 "<html>
57 <head>
58 <style>
59 * {{
60 margin: 0;
61 padding: 0;
62 }}
63 body {{
64 height: 100vh;
65 display: flex;
66 justify-content: center;
67 align-items: center;
68 background-color: #080808;
69 }}
70 h1 {{
71 font-family: system-ui;
72 color: #fefefe;
73 }}
74 </style>
75 </head>
76 <body>
77 <h1>Not Found {} {}</h1>
78 </body>
79 </html>",
80 &request.method().as_str(),
81 &request.uri().0.as_str()
82 );
83
84 response.insert_string_content(content);
85
86 response.clone()
87 }
88
89 fn use_controller(&self, route: &Route, request: &Request) -> Response {
90 let response = route.use_controller(&request);
91
92 response.clone()
93 }
94
95 fn search_route_with_params(
96 &self,
97 request: &mut Request,
98 response: &mut Response,
99 routes_with_params: Vec<&Route>,
100 ) -> Response {
101 let mut response = response.clone();
102
103 for route in routes_with_params {
104 let path: Vec<_> = route
105 .regex_complete
106 .split(&route.uri().0.as_str())
107 .collect();
108
109 let path_param: Vec<_> = route
110 .regex_words
111 .find_iter(&request.uri().0.as_str())
112 .collect();
113
114 if request.uri().0.starts_with(path[0]) {
115 let key = &route.params()[0].clone();
116 let value = path_param[1].as_str().to_string();
117
118 request.add_params((key.clone(), value));
119
120 response = self.use_controller(route, &request);
121 } else {
122 return self.response_404(&mut response, &request);
123 }
124 }
125
126 response.clone()
127 }
128
129 pub(crate) fn routing(&self, request_ref: &Request) -> Vec<Response> {
130 let mut request = request_ref.clone();
132
133 let mut response = Response::new_empty();
135
136 let option_routes_vec = self.get_routes_from_method(request.method());
137 let routes_vec: &Vec<Route>;
138
139 match option_routes_vec {
140 Some(routes) => routes_vec = routes,
141 None => return vec![self.response_404(&mut response, &request)],
143 }
144
145 let option_index = self.get_option_index(request.uri(), &routes_vec);
146
147 match option_index {
148 Some(index) => {
150 response = self.use_controller(&routes_vec[index], &request);
151 }
152
153 None => {
155 let routes_params: Vec<_> = routes_vec
157 .iter()
158 .filter(|route| route.has_parameters())
159 .collect();
160
161 if routes_params.len() == 0 {
163 return vec![self.response_404(&mut response, &request)];
164 }
165
166 response =
168 self.search_route_with_params(&mut request, &mut response, routes_params);
169 }
170 }
171
172 vec![response]
173 }
174}
175
176impl MainRouter {
178 pub fn add_route_closure<T>(
179 &mut self,
180 method: pillow_http::http_methods::HttpMethods,
181 path: &str,
182 controller: T,
183 ) where
184 T: Fn(&Request) -> Response + Send + Sync + 'static,
185 {
186 let uri = path.to_string();
187
188 self.routes
189 .entry(method)
190 .or_insert(Vec::new())
191 .push(Route::new(uri, method, controller));
192 }
193
194 pub fn add_route(&mut self, route: Route) {
219 self.routes
220 .entry(route.method().clone())
221 .or_insert(Vec::new())
222 .push(route)
223 }
224
225 pub fn public(&mut self) {
238 self.static_files("public");
239 }
240
241 pub fn assets(&mut self) {
254 self.static_files("resources/js");
255 self.static_files("resources/css");
256 }
257
258 fn static_files(&mut self, path: &str) {
266 let static_files = pillow_http::static_files::StaticFiles::new(path);
267
268 for file in static_files.files {
269 let path = file.path.clone();
270 let content_type = Arc::new(file.content_type().unwrap().to_owned());
271
272 let decoded_bytes = file.clone().content;
273
274 let closure = move |_: &Request| -> Response {
275 let content_type =
276 pillow_http::header::from_str_ext_to_content_type(&content_type.clone());
277
278 let content = decoded_bytes.clone();
279
280 Response::file(content_type, content.clone())
281 };
282
283 self.add_route_closure(pillow_http::http_methods::HttpMethods::GET, &path, closure);
284 }
285 }
286}