use tokio::{
fs::File,
io::{ AsyncBufReadExt, AsyncReadExt, BufReader, ErrorKind },
net::TcpListener,
runtime::Runtime,
sync::RwLock,
};
use std::{ future::Future, path::PathBuf, pin::Pin };
use std::sync::{ Arc };
use std::time::Instant;
use mime_guess;
pub mod macros;
use crate::request::{ parse_path_params, Request };
use crate::response::Response;
pub type Next = Box<dyn (FnOnce() -> Pin<Box<dyn Future<Output = ()> + Send>>) + Send + Sync>;
pub type Middleware = dyn (Fn(
Arc<RwLock<Request>>,
Arc<RwLock<Response>>,
Next
) -> Pin<Box<dyn Future<Output = ()> + Send>>) +
Send +
Sync;
pub type Handler = dyn (Fn(
Arc<RwLock<Request>>,
Arc<RwLock<Response>>
) -> Pin<Box<dyn Future<Output = ()> + Send>>) +
Send +
Sync;
#[derive(Clone)]
struct Route {
method: String,
path: String,
middleware: Vec<Arc<Middleware>>,
handler: Arc<Handler>,
}
pub struct Glote {
routes: Arc<RwLock<Vec<Route>>>,
middleware: Arc<RwLock<Vec<Arc<Middleware>>>>,
static_path: Arc<RwLock<Option<String>>>,
runtime: Runtime,
}
impl Glote {
pub fn new() -> Arc<Self> {
Arc::new(Self {
routes: Arc::new(RwLock::new(Vec::new())),
middleware: Arc::new(RwLock::new(Vec::new())),
static_path: Arc::new(RwLock::new(None)),
runtime: tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime"),
})
}
pub fn block_on<F: Future>(&self, fut: F) -> F::Output {
self.runtime.block_on(fut)
}
pub async fn static_path(&self, path: &str) {
let static_path = Arc::clone(&self.static_path);
*static_path.write().await = Some(path.into());
}
async fn run_handlers(
&self,
req: Arc<RwLock<Request>>,
res: Arc<RwLock<Response>>,
middlewares: &[Arc<Middleware>],
final_handler: Arc<Handler>
) {
fn call_middleware(
req: Arc<RwLock<Request>>,
res: Arc<RwLock<Response>>,
middlewares: &[Arc<Middleware>],
idx: usize,
final_handler: Arc<Handler>
) -> Pin<Box<dyn Future<Output = ()> + Send>> {
if idx == middlewares.len() {
Box::pin(final_handler(req, res))
} else {
let mw = middlewares[idx].clone();
let new_req = req.clone();
let new_res = res.clone();
let new_middleware = middlewares.to_vec();
let new_final_handler = final_handler.clone();
let next: Next = Box::new(move || {
Box::pin(
call_middleware(
new_req.clone(),
new_res.clone(),
&new_middleware,
idx + 1,
new_final_handler.clone()
)
)
});
Box::pin(async move {
mw(req, res, next).await;
})
}
}
call_middleware(req, res, middlewares, 0, final_handler).await;
}
pub async fn use_middleware<F, Fut>(&self, middleware: F)
where
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>, Next) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static
{
let wrapped = move |req, res, next| {
Box::pin(middleware(req, res, next)) as Pin<Box<dyn Future<Output = ()> + Send>>
};
let mut middlewares = self.middleware.write().await;
middlewares.push(Arc::new(wrapped));
}
pub async fn listen(self: Arc<Self>, addr: (&str, u16)) -> tokio::io::Result<()> {
let listener = TcpListener::bind((addr.0, addr.1)).await?;
println!("\n---------------------\nServer running on port {}", addr.1);
let global_middleware = self.middleware.read().await.clone();
for route in self.routes.write().await.iter_mut() {
let mut new_middleware = global_middleware.clone();
let route_specific = std::mem::take(&mut route.middleware);
new_middleware.extend(route_specific);
route.middleware = new_middleware;
}
drop(global_middleware);
loop {
match listener.accept().await {
Ok((s, _add)) => {
let stream = s;
let routers_clone = {
let guard = self.routes.read().await;
guard.clone()
};
let static_file = self.static_path.clone();
let this = self.clone();
tokio::spawn(async move {
let now = Instant::now();
let mut stream = stream;
let mut reader = BufReader::new(&mut stream);
let mut lines = Vec::new();
let mut buffer = String::new();
loop {
buffer.clear();
match reader.read_line(&mut buffer).await {
Ok(0) => {
break;
}
Ok(_) => {
let line = buffer.trim_end().to_string();
if line.is_empty() {
break;
}
lines.push(line);
}
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
tokio::time::sleep(tokio::time::Duration::from_millis(5)).await;
continue;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => {
continue;
}
Err(e) => {
eprintln!("Failed to read line: {e}");
return;
}
}
}
let content_length = lines
.iter()
.find(|line| line.to_ascii_lowercase().starts_with("content-length:"))
.and_then(|line| line.split(": ").nth(1))
.and_then(|len| len.parse::<usize>().ok());
let mut body_lines = Vec::new();
if let Some(len) = content_length {
let mut buf = vec![0u8; len];
match reader.read_exact(&mut buf).await {
Ok(_) => {
let body = String::from_utf8_lossy(&buf).to_string();
body_lines.extend(body.lines().map(|s| s.to_string()));
}
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
tokio::time::sleep(tokio::time::Duration::from_millis(5)).await;
return;
}
Err(e) => {
eprintln!("Failed to read body: {e}");
return;
}
}
let body = String::from_utf8_lossy(&buf).to_string();
body_lines.extend(body.lines().map(|s| s.to_string()));
}
lines.push(String::new()); lines.extend(body_lines);
let req = Request::new(&lines);
let mut res_opt = Some(Arc::new(RwLock::new(Response::new(stream))));
let mut matched = false;
for route in routers_clone.into_iter() {
if route.method == req.method {
if let Some(params) = parse_path_params(&route.path, &req.path) {
let mut req_with_params = req.clone();
req_with_params.path_params = params;
let req_with_params = Arc::new(RwLock::new(req_with_params));
let combined_middleware: Vec<_> = route.middleware.clone();
if let Some(res_actual) = res_opt.take() {
let req_for_handler = Arc::clone(&req_with_params);
let res_for_handler = Arc::clone(&res_actual);
this.run_handlers(
Arc::clone(&req_for_handler),
Arc::clone(&res_for_handler),
&combined_middleware,
route.handler.clone()
).await;
matched = true;
break;
}
}
}
}
let duration = now.elapsed();
if !matched {
if let Some(res) = res_opt {
if let Some(static_dir) = &static_file.read().await.as_ref() {
let mut file_path = PathBuf::from(static_dir);
let mut req_path = req.path.trim_start_matches('/').to_string();
if req_path.is_empty() {
req_path = "index.html".into();
}
file_path.push(req_path);
if let Ok(mut file) = File::open(&file_path).await {
let mut contents = Vec::new();
if file.read_to_end(&mut contents).await.is_ok() {
let mut res = res.write().await;
res.status(200).await;
res.send_bytes(
&contents,
mime_guess
::from_path(&file_path)
.first_or_text_plain()
.as_ref()
).await;
println!(
"\x1b[34mSTATIC {}: {:?}\x1b[0m",
file_path.display(),
duration
);
return;
}
}
}
let mut res = res.write().await;
res.status(404).await;
res.send("404 Not Found").await;
}
println!("\x1b[31m{} {}: {:?}\x1b[0m ", req.method, req.path, duration);
} else {
println!("\x1b[32m{} {}: {:?}\x1b[0m ", req.method, req.path, duration);
}
});
}
Err(e) => eprintln!("Listener accept failed: \n{e}"),
}
}
}
pub async fn get<F, Fut>(&self, path: &str, handler: F)
where
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static
{
let empty_middleware: Vec<Arc<Middleware>> = vec![];
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
let fut = handler(req, res);
Box::pin(fut) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.get_with_middleware_run(path, empty_middleware, wrapped_handler).await;
}
pub async fn get_with_middleware<Mfut, F, Ffut>(
&self,
path: &str,
middleware: Vec<fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>, Next) -> Mfut>,
handler: F
)
where
Mfut: Future<Output = ()> + Send + 'static,
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Ffut + Send + Sync + 'static,
Ffut: Future<Output = ()> + Send + 'static
{
let wrapped_middleware: Vec<Arc<Middleware>> = middleware
.into_iter()
.map(|mw_fn| {
let wrapped = move |
req: Arc<RwLock<Request>>,
res: Arc<RwLock<Response>>,
next: Next
| {
Box::pin(mw_fn(req, res, next)) as Pin<Box<dyn Future<Output = ()> + Send>>
};
Arc::new(wrapped) as Arc<Middleware>
})
.collect();
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
Box::pin(handler(req, res)) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.get_with_middleware_run(path, wrapped_middleware, wrapped_handler).await;
}
async fn get_with_middleware_run(
&self,
path: &str,
middleware: Vec<Arc<Middleware>>,
handler: Arc<Handler>
) {
let route = Route {
method: "GET".to_string(),
path: path.to_string(),
middleware,
handler,
};
self.routes.write().await.push(route);
}
pub async fn post<F, Fut>(&self, path: &str, handler: F)
where
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static
{
let empty_middleware: Vec<Arc<Middleware>> = vec![];
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
let fut = handler(req, res);
Box::pin(fut) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.post_with_middleware_run(path, empty_middleware, wrapped_handler).await;
}
pub async fn post_with_middleware<Mfut, F, Ffut>(
&self,
path: &str,
middleware: Vec<fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>, Next) -> Mfut>,
handler: F
)
where
Mfut: Future<Output = ()> + Send + 'static,
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Ffut + Send + Sync + 'static,
Ffut: Future<Output = ()> + Send + 'static
{
let wrapped_middleware: Vec<Arc<Middleware>> = middleware
.into_iter()
.map(|mw_fn| {
let wrapped = move |
req: Arc<RwLock<Request>>,
res: Arc<RwLock<Response>>,
next: Next
| {
Box::pin(mw_fn(req, res, next)) as Pin<Box<dyn Future<Output = ()> + Send>>
};
Arc::new(wrapped) as Arc<Middleware>
})
.collect();
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
Box::pin(handler(req, res)) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.post_with_middleware_run(path, wrapped_middleware, wrapped_handler).await;
}
async fn post_with_middleware_run(
&self,
path: &str,
middleware: Vec<Arc<Middleware>>,
handler: Arc<Handler>
) {
let route = Route {
method: "POST".to_string(),
path: path.to_string(),
middleware,
handler,
};
self.routes.write().await.push(route);
}
pub async fn put<F, Fut>(&self, path: &str, handler: F)
where
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static
{
let empty_middleware: Vec<Arc<Middleware>> = vec![];
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
let fut = handler(req, res);
Box::pin(fut) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.put_with_middleware_run(path, empty_middleware, wrapped_handler).await;
}
pub async fn put_with_middleware<Mfut, F, Ffut>(
&self,
path: &str,
middleware: Vec<fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>, Next) -> Mfut>,
handler: F
)
where
Mfut: Future<Output = ()> + Send + 'static,
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Ffut + Send + Sync + 'static,
Ffut: Future<Output = ()> + Send + 'static
{
let wrapped_middleware: Vec<Arc<Middleware>> = middleware
.into_iter()
.map(|mw_fn| {
let wrapped = move |
req: Arc<RwLock<Request>>,
res: Arc<RwLock<Response>>,
next: Next
| {
Box::pin(mw_fn(req, res, next)) as Pin<Box<dyn Future<Output = ()> + Send>>
};
Arc::new(wrapped) as Arc<Middleware>
})
.collect();
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
Box::pin(handler(req, res)) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.put_with_middleware_run(path, wrapped_middleware, wrapped_handler).await;
}
async fn put_with_middleware_run(
&self,
path: &str,
middleware: Vec<Arc<Middleware>>,
handler: Arc<Handler>
) {
let route = Route {
method: "PUT".to_string(),
path: path.to_string(),
middleware,
handler,
};
self.routes.write().await.push(route);
}
pub async fn delete<F, Fut>(&self, path: &str, handler: F)
where
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static
{
let empty_middleware: Vec<Arc<Middleware>> = vec![];
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
let fut = handler(req, res);
Box::pin(fut) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.delete_with_middleware_run(path, empty_middleware, wrapped_handler).await;
}
pub async fn delete_with_middleware<Mfut, F, Ffut>(
&self,
path: &str,
middleware: Vec<fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>, Next) -> Mfut>,
handler: F
)
where
Mfut: Future<Output = ()> + Send + 'static,
F: Fn(Arc<RwLock<Request>>, Arc<RwLock<Response>>) -> Ffut + Send + Sync + 'static,
Ffut: Future<Output = ()> + Send + 'static
{
let wrapped_middleware: Vec<Arc<Middleware>> = middleware
.into_iter()
.map(|mw_fn| {
let wrapped = move |
req: Arc<RwLock<Request>>,
res: Arc<RwLock<Response>>,
next: Next
| {
Box::pin(mw_fn(req, res, next)) as Pin<Box<dyn Future<Output = ()> + Send>>
};
Arc::new(wrapped) as Arc<Middleware>
})
.collect();
let wrapped_handler: Arc<Handler> = Arc::new(move |req, res| {
Box::pin(handler(req, res)) as Pin<Box<dyn Future<Output = ()> + Send>>
});
self.delete_with_middleware_run(path, wrapped_middleware, wrapped_handler).await;
}
async fn delete_with_middleware_run(
&self,
path: &str,
middleware: Vec<Arc<Middleware>>,
handler: Arc<Handler>
) {
let route = Route {
method: "DELETE".to_string(),
path: path.to_string(),
middleware,
handler,
};
self.routes.write().await.push(route);
}
}