1use crate::{
2 routes::{RequestProcessor, RouteContext, RouteMethod},
3 server::Server,
4};
5use serde::{Serialize, de::DeserializeOwned};
6use serde_json::Value;
7use std::{collections::HashMap, error::Error, net::SocketAddr};
8
9pub struct Request(pub http::Request<Value>);
10pub struct Response(pub http::Response<Value>);
11
12pub trait Route: FnMut(Request) -> Response + 'static {}
14impl<T> Route for T where T: FnMut(Request) -> Response + 'static {}
15
16pub trait TextRoute: FnMut() -> String + 'static {}
22impl<T> TextRoute for T where T: FnMut() -> String + 'static {}
23
24#[derive(Default)]
43pub struct Mise {
44 routes: HashMap<RouteMethod, HashMap<String, RouteContext>>,
45 text_routes: HashMap<String, Box<dyn TextRoute>>,
46}
47
48impl Mise {
49 pub fn new() -> Self {
51 Self::default()
52 }
53
54 pub fn text<F: TextRoute>(mut self, path: &str, f: F) -> Self {
59 self.text_routes.insert(path.to_string(), Box::new(f));
60 self
61 }
62
63 pub fn get<F: Route>(mut self, path: &str, f: F) -> Self {
65 let routes = self.routes.entry(RouteMethod::Get).or_default();
66 let d: Box<dyn Route> = Box::new(f);
67 routes.insert(path.to_string(), (path, d).into());
68 self
69 }
70
71 pub fn post<F: Route>(mut self, path: &str, f: F) -> Self {
74 let routes = self.routes.entry(RouteMethod::Post).or_default();
75 let d: Box<dyn Route> = Box::new(f);
76 routes.insert(path.to_string(), (path, d).into());
77 self
78 }
79
80 pub fn serve(self, addr: SocketAddr) {
83 Server::serve(
84 RequestProcessor {
85 routes: self.routes,
86 text_routes: self.text_routes,
87 },
88 addr,
89 )
90 .run();
91 }
92}
93
94impl From<Request> for Value {
95 fn from(value: Request) -> Self {
96 value.0.body().to_owned()
97 }
98}
99
100impl From<Value> for Response {
101 fn from(value: Value) -> Self {
102 Response(http::Response::new(value))
103 }
104}
105
106impl From<http::StatusCode> for Response {
107 fn from(value: http::StatusCode) -> Self {
108 Response(
109 http::Response::builder()
110 .status(value)
111 .body(Value::Null)
112 .expect("Statically built body should not fail"),
113 )
114 }
115}
116
117pub trait Serializable: Serialize {
118 fn to_response(&self) -> Result<Response, Box<dyn Error>> {
119 Ok(Response(http::Response::new(serde_json::to_value(self)?)))
120 }
121}
122impl<T> Serializable for T where T: Serialize {}
123
124pub trait Deserializable: DeserializeOwned {
125 fn from_request(r: Request) -> Result<Self, Box<dyn Error>> {
126 Ok(serde_json::from_value(r.body().to_owned())?)
127 }
128}
129impl<T> Deserializable for T where T: DeserializeOwned {}
130
131impl Request {
132 pub fn path(&self) -> &str {
134 self.0.uri().path()
135 }
136
137 pub fn query(&self) -> Option<&str> {
138 self.0.uri().query()
139 }
140
141 pub fn query_param(&self, name: &str) -> Option<&str> {
143 let q = self.0.uri().query()?;
144 let f = format!("{name}=");
145 let idx = q.find(&f)?;
146 let end = q[idx..].find('&').unwrap_or(q.len());
147 Some(&q[idx + f.len()..end])
148 }
149
150 pub fn base(&self) -> &str {
156 let p = self.0.uri().path();
157 let n = self.name();
158 p[..p.len() - n.len()].trim_end_matches("/")
159 }
160
161 pub fn name(&self) -> &str {
167 if !self.0.uri().path().contains("/") {
168 return "";
169 }
170 self.0.uri().path().split("/").last().unwrap_or("")
171 }
172
173 pub fn body(&self) -> &Value {
177 self.0.body()
178 }
179
180 pub(crate) fn base_star(&self) -> Option<String> {
181 if self.name().is_empty() {
182 return None;
184 }
185 Some(format!("{}/*", self.base()))
186 }
187}
188
189#[cfg(test)]
190mod test {
191 use super::*;
192 use serde::Deserialize;
193 use serde_json::json;
194
195 #[derive(Serialize, Deserialize)]
196 struct My {
197 val: usize,
198 }
199
200 #[test]
201 fn test_serde() {
202 let m = My { val: 1 };
203 let r = m.to_response().unwrap();
204 assert_eq!(r.0.body()["val"].clone(), 1);
205
206 let r = Request(http::Request::new(json!({"val":2})));
207 let m = My::from_request(r).unwrap();
208 assert_eq!(m.val, 2);
209 }
210
211 #[test]
212 fn test_paths() {
213 assert_eq!(requri("/").name(), "");
214 assert_eq!(requri("/a").name(), "a");
215 assert_eq!(requri("/a/b").name(), "b");
216
217 assert_eq!(requri("/").base(), "");
218 assert_eq!(requri("/a").base(), "");
219 assert_eq!(requri("/a/b").base(), "/a");
220
221 assert_eq!(requri("/").base_star(), None);
222 assert_eq!(requri("/a").base_star(), Some("/*".to_string()));
223 assert_eq!(requri("/a/b").base_star(), Some("/a/*".to_string()));
224
225 assert_eq!(requri("/?b=a").query_param("b"), Some("a"));
226 }
227
228 fn requri(uri: &str) -> Request {
229 Request(http::Request::builder().uri(uri).body(Value::Null).unwrap())
230 }
231}