1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
#![deny(warnings)] #![deny(clippy::all, clippy::pedantic, clippy::nursery)] #![deny(missing_debug_implementations, rust_2018_idioms)] #![allow(clippy::module_name_repetitions)] mod context; pub mod middleware; use { async_net::{AsyncToSocketAddrs, TcpListener}, async_trait::async_trait, middleware::Middleware, std::{fmt::Debug, io, sync::Arc}, }; pub use { context::Context, http_types::{Method, Request, Response, StatusCode}, }; pub type Result<T = ()> = http_types::Result<T>; type MiddlewareList<Ex> = Vec<Arc<dyn Middleware<Ex>>>; #[allow(missing_debug_implementations)] #[derive(Default)] pub struct Amiya<Ex = ()> { middleware_list: MiddlewareList<Ex>, } impl<Ex> Amiya<Ex> where Ex: Default + Send + Sync + 'static, { pub fn uses<M: Middleware<Ex> + 'static>(mut self, middleware: M) -> Self { self.middleware_list.push(Arc::new(middleware)); self } async fn serve(tail: Arc<MiddlewareList<Ex>>, req: Request) -> Result<Response> { let mut ex = Ex::default(); let mut resp = Response::new(StatusCode::Ok); let mut ctx = Context { req: &req, resp: &mut resp, ex: &mut ex, tail: &tail, remain_path: &req.url().path()[1..], }; ctx.next().await?; Ok(resp) } pub async fn listen<A: AsyncToSocketAddrs + Debug>(self, addr: A) -> io::Result<()> { let listener = TcpListener::bind(addr).await?; let middleware_list = Arc::new(self.middleware_list); loop { match listener.accept().await { Ok((stream, client_addr)) => { let middleware_list = Arc::clone(&middleware_list); let serve = async_h1::accept(stream, move |mut req| { req.set_peer_addr(Some(client_addr)); Self::serve(Arc::clone(&middleware_list), req) }); smol::Task::spawn(async move { if let Err(e) = serve.await { eprintln!("Error when process request: {}", e); } }) .detach(); } Err(e) => { eprintln!("Accept connection error: {}", e); } } } } } #[async_trait] impl<Ex: Send + Sync + 'static> Middleware<Ex> for Amiya<Ex> { async fn handle(&self, mut ctx: Context<'_, Ex>) -> Result<()> { let mut self_ctx = Context { req: ctx.req, resp: ctx.resp, ex: ctx.ex, tail: &self.middleware_list[..], remain_path: &ctx.remain_path, }; self_ctx.next().await?; ctx.next().await } }