1use crate::server::Server;
2use http::StatusCode;
3use serde_json::Value;
4use std::{
5 collections::HashMap,
6 net::SocketAddr,
7 panic::{AssertUnwindSafe, catch_unwind},
8};
9use tracing::trace;
10
11pub struct Request(pub http::Request<Value>);
12pub struct Response(pub http::Response<Value>);
13
14pub trait Route: Fn(Request) -> Response + 'static {}
16impl<T> Route for T where T: Fn(Request) -> Response + 'static {}
17
18#[derive(Default)]
20pub struct Mise {
21 routes: HashMap<String, Box<dyn Route>>,
22}
23
24impl Mise {
25 pub fn new() -> Self {
27 Self::default()
28 }
29
30 pub fn get<F: Route>(mut self, path: &str, f: F) -> Self {
32 self.routes.insert(path.to_string(), Box::new(f));
33 self
34 }
35
36 pub fn serve(self, addr: SocketAddr) {
39 Server::serve(
40 RequestProcessor {
41 routes: self.routes,
42 },
43 addr,
44 )
45 .run();
46 }
47}
48
49impl From<Request> for Value {
50 fn from(value: Request) -> Self {
51 value.0.body().to_owned()
52 }
53}
54
55impl From<Value> for Response {
56 fn from(value: Value) -> Self {
57 Response(http::Response::new(value))
58 }
59}
60
61impl From<http::StatusCode> for Response {
62 fn from(value: http::StatusCode) -> Self {
63 Response(
64 http::Response::builder()
65 .status(value)
66 .body(Value::Null)
67 .expect("Statically built body should not fail"),
68 )
69 }
70}
71
72pub(crate) struct RequestProcessor {
73 routes: HashMap<String, Box<dyn Route>>,
74}
75
76impl RequestProcessor {
77 pub(crate) fn process(&self, req: Request) -> Response {
78 let Some(route) = self.routes.get(req.0.uri().path()) else {
79 return StatusCode::NOT_FOUND.into();
80 };
81 trace!("Received {:?}", req.0);
82 let res = catch_unwind(AssertUnwindSafe(|| route(req)));
83 let resp = res.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR.into());
84 trace!("Sending {:?}", resp.0);
85 resp
86 }
87}
88
89impl Request {
90 pub fn query_param(&self, name: &str) -> Option<String> {
92 let q = self.0.uri().query()?;
93 let f = format!("{name}=");
94 let idx = q.find(&f)?;
95 let end = q[idx..].find('&').unwrap_or(q.len());
96 Some(q[idx + f.len()..end].to_string())
97 }
98}