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}