1use std::{collections::HashMap, path::Path};
2
3use crate::{serve_static_file, webserver::RouteHandler, Request, Response, ReturnData};
4
5#[derive(Clone)]
6pub struct Router {
7 basepath: String,
8 routes: HashMap<String, RouteHandler>,
9}
10
11impl Router {
12 pub fn new(base_path: &str) -> Self {
13 Self {
14 basepath: base_path.to_string(),
15 routes: HashMap::new(),
16 }
17 }
18
19 pub fn add_simple_route(
20 &mut self,
21 route: &str,
22 function: fn(_: Request, _: &mut Response) -> ReturnData,
23 ) {
24 self.routes
25 .insert(route.to_owned(), RouteHandler::Simple(function));
26 }
27
28 pub fn add_route_with_params(
29 &mut self,
30 route: &str,
31 function: fn(Request, &mut Response, HashMap<String, String>) -> ReturnData,
32 ) {
33 self.routes
34 .insert(route.to_owned(), RouteHandler::WithRouteParams(function));
35 }
36
37 pub fn add_static_file_route(&mut self, route: &str, path: &str) {
38 let mut params: HashMap<String, String> = HashMap::new();
39 params.insert("basepath".to_string(), path.to_string());
40 self.routes.insert(
41 route.to_owned(),
42 RouteHandler::WithRouteAndOptionalParams(
43 |_req: Request, res: &mut Response, params: HashMap<String, String>| {
44 if !params.contains_key("basepath") {
45 res.set_status_code(500);
46 return ReturnData::Text("Something went wrong!".to_string());
47 }
48 if !params.contains_key("path") {
49 res.set_status_code(403);
50 return ReturnData::Text("Cannot index folders".to_string());
51 } else if params["path"].ends_with("/") {
52 res.set_status_code(403);
53 return ReturnData::Text("Cannot index folders".to_string());
54 }
55 let path = Path::new(¶ms["basepath"]).join(¶ms["path"]);
56 serve_static_file(path.to_str().unwrap(), res)
57 },
58 params,
59 ),
60 );
61 }
62
63
64
65 pub fn does_path_exists(
66 &self,
67 path: &str,
68 ) -> Option<String> {
69 let mut current_path = None;
70 let path_parts: Vec<&str> = path.split("/").filter(|i| !i.is_empty()).collect();
71 for i in self.routes.clone() {
72 let mut route_parts: Vec<&str> = i.0.split("/").filter(|i| !i.is_empty()).collect();
73 let basepath_parts: Vec<&str> = self.basepath.split("/").filter(|i| !i.is_empty()).collect();
75 route_parts.extend(basepath_parts);
76 if route_parts.len() != path_parts.len() {
78 let diff = path_parts.len() as i32 - route_parts.len() as i32;
79 if diff > 0 {
80 for _ in 0..diff {
81 route_parts.push("");
82 }
83 }
84 }
85 if route_parts == path_parts {
86 current_path = Some(i.0.to_owned());
87 continue;
88 }
89
90 for (route_part, path_part) in route_parts.iter().zip(path_parts.iter()) {
91 if route_part.starts_with(":") || route_part == path_part || route_part == &"*" {
93 current_path = Some(i.0.to_owned());
94 } else if route_part == &"**" {
95 current_path = Some(i.0.to_owned());
96 break;
97 } else if route_part != path_part {
98 current_path = None;
99 break;
100 }
101 }
102 if current_path.is_some() {
103 break;
104 }
105 }
106 current_path
108 }
109 pub fn route_handler_from_path(&self, path: String) -> Option<RouteHandler> {
110 if self.routes.keys().any(|i| i == &path) {
111 return Some(self.routes[&path].clone());
112 }
113 None
114 }
115}