preliminary spike of app functionality

Signed-off-by: Erik Hollensbe <linux@hollensbe.org>
This commit is contained in:
Erik Hollensbe
2022-01-20 10:11:11 -08:00
parent cdd0646c33
commit b9af85d0c1
3 changed files with 105 additions and 10 deletions
+92
View File
@@ -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<Body>) -> Result<Response<Body>, 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<Body>| 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);
}
});
}
}
}
+13 -8
View File
@@ -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<F> = Pin<Box<F>>;
pub struct ServerError(String);
impl<T> From<T> 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<http::Error> for Error {
}
pub type HTTPResult = Result<(Request<hyper::Body>, Option<Response<hyper::Body>>), Error>;
pub struct App {
#[allow(dead_code)] // FIXME remove
routes: BTreeMap<String, Handler>,
}
-2
View File
@@ -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()