1use crate::IntoHandler;
2use crate::config::RestConf;
3use crate::http::HandlerFunc;
4use crate::middleware::Middleware;
5use crate::router::Route;
6use crate::server::{Server, ServerHandle};
7
8#[derive(Clone)]
10pub struct Engine {
11 conf: RestConf,
12 routes: Vec<Route>,
13 middlewares: Vec<Middleware>,
14 not_found: Option<HandlerFunc>,
15 not_allowed: Option<HandlerFunc>,
16}
17
18impl Engine {
19 pub fn new(conf: RestConf) -> anyhow::Result<Self> {
22 Ok(Self {
23 conf,
24 routes: Vec::new(),
25 middlewares: Vec::new(),
26 not_found: None,
27 not_allowed: None,
28 })
29 }
30
31 pub fn must_new(conf: RestConf) -> Self {
33 Self::new(conf).unwrap()
34 }
35
36 pub fn add_routes<I>(&mut self, routes: I)
39 where
40 I: IntoIterator<Item = Route>,
41 {
42 self.routes.extend(routes);
43 }
44
45 pub fn add_route(&mut self, route: Route) {
48 self.routes.push(route);
49 }
50
51 pub fn use_middleware(&mut self, middleware: Middleware) {
54 self.middlewares.push(middleware);
55 }
56
57 pub fn set_not_found_handler(&mut self, handler: impl IntoHandler) {
60 self.not_found = Some(handler.into_handler());
61 }
62
63 pub fn set_not_allowed_handler(&mut self, handler: impl IntoHandler) {
66 self.not_allowed = Some(handler.into_handler());
67 }
68
69 pub async fn start(self) -> anyhow::Result<ServerHandle> {
72 let mut server = Server::new(self.conf.clone());
73
74 if let Some(h) = self.not_found.clone() {
75 server.set_not_found_handler(h);
76 }
77 if let Some(h) = self.not_allowed.clone() {
78 server.set_not_allowed_handler(h);
79 }
80 for mw in &self.middlewares {
81 server.use_middleware(mw.clone());
82 }
83 server.add_routes(self.routes.clone());
84 server.start().await
85 }
86
87 pub fn print_routes(&self) {
90 let mut routes: Vec<String> = self
91 .routes
92 .iter()
93 .map(|r| format!("{} {}", r.method, r.path))
94 .collect();
95 routes.sort();
96 println!("Routes:");
97 for r in routes {
98 println!(" {r}");
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use http::Method;
107 use hyper::{Body, Response};
108
109 fn ok_route(path: &str) -> Route {
110 Route::new(Method::GET, path, |_req: http::Request<Body>| async {
111 Response::new(Body::from("ok"))
112 })
113 }
114
115 #[test]
116 fn add_routes_should_collect() {
117 let mut eng = Engine::must_new(RestConf::default());
118 eng.add_route(ok_route("/a"));
119 eng.add_routes(vec![ok_route("/b"), ok_route("/c")]);
120 assert_eq!(eng.routes.len(), 3);
121 }
122}