From b9af85d0c148d6d1dda47057965c9fd09e034b13 Mon Sep 17 00:00:00 2001 From: Erik Hollensbe Date: Thu, 20 Jan 2022 10:11:11 -0800 Subject: [PATCH] preliminary spike of app functionality Signed-off-by: Erik Hollensbe --- src/app.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 21 +++++++----- src/router.rs | 2 -- 3 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 src/app.rs diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..b2e6079 --- /dev/null +++ b/src/app.rs @@ -0,0 +1,92 @@ +use std::{convert::Infallible, net::SocketAddr}; + +use http::{Method, Request, Response, StatusCode}; +use hyper::{server::conn::Http, service::service_fn, Body}; +use tokio::net::TcpListener; + +use crate::{handler::Handler, router::Router, Error, ServerError}; + +pub struct App { + router: Router, +} + +impl App { + pub fn new() -> Self { + Self { + router: Router::new(), + } + } + + pub fn get(&mut self, path: &str, ch: Handler) { + self.router.add(Method::GET, path.to_string(), ch); + } + + pub fn post(&mut self, path: &str, ch: Handler) { + self.router.add(Method::POST, path.to_string(), ch); + } + + pub fn delete(&mut self, path: &str, ch: Handler) { + self.router.add(Method::DELETE, path.to_string(), ch); + } + + pub fn put(&mut self, path: &str, ch: Handler) { + self.router.add(Method::PUT, path.to_string(), ch); + } + + pub fn options(&mut self, path: &str, ch: Handler) { + self.router.add(Method::OPTIONS, path.to_string(), ch); + } + + pub fn patch(&mut self, path: &str, ch: Handler) { + self.router.add(Method::PATCH, path.to_string(), ch); + } + + pub fn head(&mut self, path: &str, ch: Handler) { + self.router.add(Method::HEAD, path.to_string(), ch); + } + + pub fn connect(&mut self, path: &str, ch: Handler) { + self.router.add(Method::CONNECT, path.to_string(), ch); + } + + pub fn trace(&mut self, path: &str, ch: Handler) { + self.router.add(Method::TRACE, path.to_string(), ch); + } + + pub async fn dispatch(&self, req: Request) -> Result, Infallible> { + match self.router.dispatch(req).await { + Ok(resp) => Ok(resp), + Err(e) => match e { + Error::StatusCode(sc) => Ok(Response::builder() + .status(sc) + .body(Body::default()) + .unwrap()), + Error::InternalServerError(_) => Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(Body::default()) + .unwrap()), + }, + } + } + + pub async fn serve(&'static self, addr: String) -> Result<(), ServerError> { + let socketaddr: SocketAddr = addr.parse()?; + + let s = self.clone(); + let sfn = service_fn(move |req: Request| s.dispatch(req)); + + let tcp_listener = TcpListener::bind(socketaddr).await?; + loop { + let (tcp_stream, _) = tcp_listener.accept().await?; + tokio::task::spawn(async move { + if let Err(http_err) = Http::new() + .http1_keep_alive(true) + .serve_connection(tcp_stream, sfn) + .await + { + eprintln!("Error while serving HTTP connection: {}", http_err); + } + }); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 899c5d8..0099800 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,25 @@ +pub mod app; pub mod handler; pub mod macros; pub mod path; pub mod router; -use handler::Handler; use http::{Request, Response}; - -use std::{collections::BTreeMap, pin::Pin}; +use std::pin::Pin; pub(crate) type PinBox = Pin>; +pub struct ServerError(String); + +impl From for ServerError +where + T: ToString, +{ + fn from(t: T) -> Self { + ServerError(t.to_string()) + } +} + #[derive(Clone, Debug)] pub enum Error { StatusCode(http::StatusCode), @@ -42,8 +52,3 @@ impl From for Error { } pub type HTTPResult = Result<(Request, Option>), Error>; - -pub struct App { - #[allow(dead_code)] // FIXME remove - routes: BTreeMap, -} diff --git a/src/router.rs b/src/router.rs index d56aa02..4fe4f6c 100644 --- a/src/router.rs +++ b/src/router.rs @@ -34,7 +34,6 @@ impl Ord for Route { } impl Route { - #[allow(dead_code)] fn new(method: http::Method, path: String, handler: Handler) -> Self { Self { method, @@ -63,7 +62,6 @@ impl Router { Self(Vec::new()) } - #[allow(dead_code)] pub(crate) fn add(&mut self, method: http::Method, path: String, ch: Handler) -> Self { self.0.push(Route::new(method, path, ch)); self.clone()