bolt_web/
lib.rs

1use std::{convert::Infallible, net::SocketAddr, sync::Arc};
2
3use hyper::{
4    Request,
5    body::Incoming,
6    server::conn::{http1, http2},
7    service::service_fn,
8};
9use hyper_util::rt::{TokioExecutor, TokioIo};
10use tokio::net::TcpListener;
11
12use crate::{
13    client::Client,
14    group::Group,
15    middleware::error::DefaultErrorHandler,
16    request::RequestBody,
17    response::ResponseWriter,
18    router::Router,
19    types::{ErrorHandler, Handler, Method, Middleware, Mode},
20};
21
22pub mod client;
23mod group;
24pub mod middleware;
25pub mod request;
26pub mod response;
27mod router;
28pub mod types;
29
30pub struct Bolt {
31    router: Router,
32    error_handler: Arc<dyn ErrorHandler>,
33    client: Client,
34}
35
36impl Bolt {
37    pub fn new() -> Self {
38        Self {
39            router: Router::new(),
40            error_handler: Arc::new(DefaultErrorHandler),
41            client: Client::new(),
42        }
43    }
44
45    pub async fn run(
46        &self,
47        addr: &str,
48        mode: Mode,
49    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
50        println!("⚡ A high performance & minimalist web framework in rust.");
51        println!(
52            r#"
53    __          ____
54   / /_  ____  / / /_
55  / __ \/ __ \/ / __/
56 / /_/ / /_/ / / /_  
57/_.___/\____/_/\__/  v0.1.0
58"#
59        );
60
61        println!("=> Server running on http://{}", addr);
62
63        let addr: SocketAddr = addr.parse().unwrap();
64
65        let listener = TcpListener::bind(addr).await?;
66        let router = Arc::new(self.router.clone());
67
68        loop {
69            let (stream, _) = listener.accept().await?;
70            let io = TokioIo::new(stream);
71
72            let router = router.clone();
73            let error_handler = self.error_handler.clone();
74
75            let service = service_fn(move |req: Request<Incoming>| {
76                let router = router.clone();
77
78                let error_handler = error_handler.clone();
79
80                async move {
81                    let mut req_body = RequestBody::new(req);
82                    let mut res_body = ResponseWriter::new();
83
84                    let method = match *req_body.method() {
85                        hyper::Method::GET => Method::GET,
86                        hyper::Method::POST => Method::POST,
87                        hyper::Method::PUT => Method::PUT,
88                        hyper::Method::PATCH => Method::PATCH,
89                        hyper::Method::DELETE => Method::DELETE,
90                        hyper::Method::OPTIONS => Method::OPTIONS,
91                        hyper::Method::HEAD => Method::HEAD,
92                        hyper::Method::TRACE => Method::TRACE,
93                        _ => {
94                            res_body.status(405);
95                            res_body.send("Method Not Allowed");
96                            return Ok::<_, Infallible>(res_body.into_response());
97                        }
98                    };
99
100                    let path = req_body.path().to_string();
101
102                    let mws = router.collect_middleware(&path, method);
103
104                    for mw in mws {
105                        mw.run(&mut req_body, &mut res_body).await;
106
107                        if res_body.has_error() {
108                            break;
109                        }
110                    }
111
112                    if !res_body.has_error() {
113                        if let Some((handler, params)) = router.find(&path, method) {
114                            req_body.set_params(params);
115                            handler(&mut req_body, &mut res_body);
116                        } else {
117                            let method_str = match *req_body.method() {
118                                hyper::Method::GET => "GET",
119                                hyper::Method::POST => "POST",
120                                hyper::Method::PUT => "PUT",
121                                hyper::Method::PATCH => "PATCH",
122                                hyper::Method::DELETE => "DELETE",
123                                hyper::Method::OPTIONS => "OPTIONS",
124                                hyper::Method::HEAD => "HEAD",
125                                hyper::Method::TRACE => "TRACE",
126                                _ => "UNKNOWN",
127                            };
128
129                            res_body.error(404, &format!("Not Found {} {}", method_str, path));
130                        }
131                    }
132
133                    if res_body.has_error() {
134                        let msg = res_body.body.clone();
135                        error_handler.run(msg, &mut res_body).await;
136                    }
137
138                    Ok::<_, Infallible>(res_body.into_response())
139                }
140            });
141
142            match mode {
143                Mode::Http1 => {
144                    tokio::task::spawn(async move {
145                        if let Err(err) = http1::Builder::new().serve_connection(io, service).await
146                        {
147                            eprintln!("Error serving connection: {}", err);
148                        }
149                    });
150                }
151
152                Mode::Http2 => {
153                    tokio::task::spawn(async move {
154                        if let Err(err) = http2::Builder::new(TokioExecutor::new())
155                            .serve_connection(io, service)
156                            .await
157                        {
158                            eprintln!("Error serving connection: {}", err);
159                        }
160                    });
161                }
162            }
163        }
164    }
165
166    fn add_route(&mut self, method: Method, path: &str, handler: Handler) {
167        self.router.insert(path, method, handler);
168    }
169
170    pub fn get(&mut self, path: &str, handler: Handler) {
171        self.add_route(Method::GET, path, handler);
172    }
173
174    pub fn post(&mut self, path: &str, handler: Handler) {
175        self.add_route(Method::POST, path, handler);
176    }
177
178    pub fn put(&mut self, path: &str, handler: Handler) {
179        self.add_route(Method::PUT, path, handler);
180    }
181
182    pub fn patch(&mut self, path: &str, handler: Handler) {
183        self.add_route(Method::PATCH, path, handler);
184    }
185
186    pub fn delete(&mut self, path: &str, handler: Handler) {
187        self.add_route(Method::DELETE, path, handler);
188    }
189
190    pub fn group(&mut self, path: &str) -> Group {
191        Group {
192            prefix: path.to_string(),
193            app: self,
194        }
195    }
196
197    pub fn middleware<M>(&mut self, path: &str, method: Option<Method>, middleware_fn: M)
198    where
199        M: Middleware + 'static,
200    {
201        let mw = Arc::new(middleware_fn);
202        let full_path = path.to_string();
203
204        match method {
205            Some(m) => self.router.insert_middleware(&full_path, m, mw),
206            None => {
207                for m in [
208                    Method::GET,
209                    Method::POST,
210                    Method::PUT,
211                    Method::PATCH,
212                    Method::DELETE,
213                    Method::OPTIONS,
214                    Method::HEAD,
215                    Method::TRACE,
216                ] {
217                    self.router.insert_middleware(&full_path, m, mw.clone());
218                }
219            }
220        }
221    }
222
223    pub fn set_error_handler(&mut self, handler: Arc<dyn ErrorHandler>) {
224        self.error_handler = handler;
225    }
226}