use std::collections::BTreeMap;
use std::io::prelude::*;
use std::net::{SocketAddr, TcpStream};
use std::sync::Arc;
use super::http::{Method, Request, Response, ResponseWriter, StatusCode};
pub type HandlerFunc = Arc<dyn for<'a> Fn(&'a mut ResponseWriter, Request)>;
pub type Middleware = fn(HandlerFunc) -> HandlerFunc;
pub struct Router {
routes: BTreeMap<(Method, String), HandlerFunc>,
middlewares: BTreeMap<(Method, String), Vec<Middleware>>,
}
impl Router {
pub fn new() -> Self {
Self {
routes: BTreeMap::new(),
middlewares: BTreeMap::new(),
}
}
pub fn handle(&mut self, key: (String, String), handler: HandlerFunc) {
let method = Method::from_str(&key.0);
let path = key.1;
self.routes.insert((method, path), handler);
}
pub fn r#use(&mut self, key: (String, String), middleware: Middleware) {
let method = Method::from_str(&key.0);
let path = key.1;
let key: (Method, String) = (method, path);
self.middlewares.entry(key).or_insert_with(Vec::new).push(middleware);
}
pub fn route<'a>(&'a self, mut stream: TcpStream, addr: SocketAddr) {
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
let mut response_writer = Response::builder();
let request = Request::from(&buffer, addr);
let key = (request.method(), request.path());
if let Some(handler) = self.routes.get(&key) {
if let Some(mids) = self.middlewares.get(&key) {
let handler_func = Arc::clone(handler);
let resulting = mids
.into_iter()
.rev()
.fold(handler_func, |acc: HandlerFunc, middleware: &Middleware| {
middleware(acc)
});
resulting(&mut response_writer, request);
let response = response_writer.build();
response.write(stream);
return;
}
handler(&mut response_writer, request);
let response = response_writer.build();
response.write(stream);
return;
}
response_writer.set_status(StatusCode::NotFound);
let response = response_writer.build();
response.write(stream);
}
}