mise_server/
mise.rs

1use crate::server::Server;
2use http::StatusCode;
3use serde_json::Value;
4use std::{collections::HashMap, net::SocketAddr};
5use tracing::trace;
6
7pub struct Request(pub http::Request<Value>);
8pub struct Response(pub http::Response<Value>);
9
10/// Final routes are always in JSON.
11pub trait Route: Fn(Request) -> Response + 'static {}
12impl<T> Route for T where T: Fn(Request) -> Response + 'static {}
13
14/// Server resource and entry point.
15#[derive(Default)]
16pub struct Mise {
17    routes: HashMap<String, Box<dyn Route>>,
18}
19
20impl Mise {
21    /// Create a new default server.
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Register a get route.
27    pub fn get<F: Route>(mut self, path: &str, f: F) -> Self {
28        self.routes.insert(path.to_string(), Box::new(f));
29        self
30    }
31
32    /// Starts the server. Blocks until the server quits.
33    /// Can panic if cannot bind the server.
34    pub fn serve(self, addr: SocketAddr) {
35        Server::serve(
36            RequestProcessor {
37                routes: self.routes,
38            },
39            addr,
40        )
41        .run();
42    }
43}
44
45impl From<Request> for Value {
46    fn from(value: Request) -> Self {
47        value.0.body().to_owned()
48    }
49}
50
51impl From<Value> for Response {
52    fn from(value: Value) -> Self {
53        Response(http::Response::new(value))
54    }
55}
56
57impl From<http::StatusCode> for Response {
58    fn from(value: http::StatusCode) -> Self {
59        Response(
60            http::Response::builder()
61                .status(value)
62                .body(Value::Null)
63                .expect("Statically built body should not fail"),
64        )
65    }
66}
67
68pub(crate) struct RequestProcessor {
69    routes: HashMap<String, Box<dyn Route>>,
70}
71
72impl RequestProcessor {
73    pub(crate) fn process(&self, req: Request) -> Response {
74        let Some(route) = self.routes.get(&req.0.uri().to_string()) else {
75            return StatusCode::NOT_FOUND.into();
76        };
77        trace!("Received {:?}", req.0);
78        let resp = route(req);
79        trace!("Sending {:?}", resp.0);
80        resp
81    }
82}