use std::collections::HashMap;
use std::net::{TcpListener, TcpStream};
use std::num::NonZeroUsize;
use std::sync::Arc;
use std::thread::available_parallelism;
use log::{debug, info};
use crate::http::conn::Conn;
use crate::middleware::Middleware;
use crate::pool::ThreadPool;
use crate::router::Router;
use crate::{DynHandler, Handler, Request, Response};
pub struct Application {
addr: &'static str,
num_threads: usize,
router: Router,
middlewares: Vec<Middleware>,
}
impl Application {
pub fn new(addr: &'static str) -> Self {
env_logger::init();
let router = Router::default();
let middlewares = Vec::new();
let default_num_threads = NonZeroUsize::new(8).unwrap();
let num_threads = available_parallelism().unwrap_or(default_num_threads).get();
Self {
addr,
num_threads,
router,
middlewares,
}
}
pub fn num_threads(mut self, n: usize) -> Self {
self.num_threads = n;
self
}
pub fn middleware<M>(&mut self, middleware: M)
where
M: Fn(DynHandler) -> DynHandler + Send + Sync + 'static,
{
self.middlewares.push(Arc::new(middleware));
}
pub fn route<F>(&mut self, pattern: &'static str, f: F)
where
F: Fn(Request) -> Response + Send + Sync + 'static,
{
self.router.add(pattern, f);
}
pub fn route_handler<H>(&mut self, pattern: &'static str, h: H)
where
H: Handler + Send + Sync + 'static,
{
self.router.add_handler(pattern, h);
}
pub fn request(
&self,
method: &str,
uri: &str,
headers: HashMap<String, String>,
body: &[u8],
) -> Response {
let mut req = Request::new(method, uri, headers, body);
let (params, mut handler) = self.router.dispatch(req.path());
req.params = params;
for middleware in self.middlewares.iter().rev() {
handler = middleware(handler);
}
handler(req)
}
pub fn run(&self) {
info!("Started web server on addr {}", self.addr);
debug!("routes: \n {:}", self.router);
let pool = ThreadPool::new(self.num_threads);
let listener = TcpListener::bind(self.addr).unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
let router = self.router.clone();
let middlewares = self.middlewares.clone();
pool.execute(|| {
handle_connection(router, middlewares, stream);
});
}
}
}
fn handle_connection(router: Router, middlewares: Vec<Middleware>, stream: TcpStream) {
let mut conn = Conn::from(stream);
let mut req = Request::from(&mut conn);
let (params, mut handler) = router.dispatch(req.path());
req.params = params;
for middleware in middlewares.iter().rev() {
handler = middleware(handler);
}
let res = handler(req);
conn.write_all(res.to_string().as_bytes());
conn.flush();
}
#[cfg(test)]
mod tests {
use super::Application;
#[test]
fn it_works() {
Application::new("0:65530").num_threads(2);
}
}