luciders/src/handlers.rs

73 lines
2.3 KiB
Rust
Raw Normal View History

use crate::http::{
requests::{Request, RequestStatus},
responses::{Response, UnitOrBoxedError},
};
use std::{
collections::HashMap,
net::{Shutdown, TcpListener},
};
// Collection of handlers for requests
pub struct Handlers<FnT> {
matchers: HashMap<String, FnT>,
}
impl<FnT> Handlers<FnT>
where
FnT: Fn(Request) -> Response<'static>,
{
pub fn new() -> Self {
Handlers::<FnT> {
matchers: HashMap::new(),
}
}
/// Add a request handler
///
/// !! Be sure to bind this Handlers struct to a TcpListener to actually handle requests !!
///
/// path: Path to match (no trailing /)
/// handler: Function to handle the request. Must return a Response
pub fn add_handler(&mut self, path: &str, handler: FnT) {
self.matchers.insert(path.to_string(), handler);
}
/// Bind these handlers to a listener in order to handle incoming requests
/// You will need to pass in a TcpListener
///
/// !! Call this *after* adding all your handlers with add_handler !!
///
/// listener: TcpListener to bind to
pub fn bind(&self, listener: TcpListener) {
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let request = match Request::parse_stream(stream) {
RequestStatus::Ok(req) => req,
RequestStatus::MalformedHTTP(stream) => {
stream.shutdown(Shutdown::Both).unwrap_or_else(|_| {
eprintln!("Failed to close malformed HTTP stream")
});
return;
}
};
self.handle_req(request)
.unwrap_or_else(|_| eprintln!("Failed to send handle request"));
}
Err(e) => {
eprintln!("Failed to establish connection: {}", e);
return;
}
}
}
}
fn handle_req(&self, req: Request) -> UnitOrBoxedError {
match self.matchers.get(&req.url.path) {
Some(handler) => (*handler)(req).send(),
None => Response::new(req, 404, "Not Found").send(),
}
}
}