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