fixed handlers!!!!one

Signed-off-by: Erik Hollensbe <linux@hollensbe.org>
This commit is contained in:
Erik Hollensbe
2022-01-19 12:26:15 -08:00
parent 1779cf13ca
commit b841c8589d
5 changed files with 49 additions and 62 deletions
+1 -1
View File
@@ -8,5 +8,5 @@ edition = "2021"
[dependencies]
hyper = { version = "*", features = [ "http1", "http2", "server", "runtime", "tcp", "stream" ] }
http = "*"
async-trait = "*"
async-recursion = "*"
tokio = { version = "*", features = [ "full" ] }
+34 -47
View File
@@ -1,62 +1,46 @@
use std::{collections::BTreeMap, sync::Arc};
use std::{collections::BTreeMap, future::Future};
use crate::HTTPResult;
use crate::{HTTPResult, PinBox};
use async_recursion::async_recursion;
use async_trait::async_trait;
use http::{Request, Response};
use hyper::Body;
pub(crate) type Params = BTreeMap<&'static str, &'static str>;
pub type HandlerFunc =
dyn Fn(Request<hyper::Body>, Option<Response<hyper::Body>>, Params) -> HTTPResult + Sync;
#[async_trait]
pub trait Handler
where
Self: Sync + Sized,
{
async fn perform(
&self,
req: Request<hyper::Body>,
response: Option<Response<hyper::Body>>,
params: Params,
) -> HTTPResult;
}
pub type HandlerFunc = fn(
req: Request<Body>,
response: Option<Response<Body>>,
params: Params,
) -> PinBox<dyn Future<Output = HTTPResult> + Send + 'static>;
#[derive(Clone)]
pub struct BasicHandler
where
Self: Sync + Sized,
{
next: Option<Arc<BasicHandler>>,
func: &'static HandlerFunc,
pub struct Handler {
handler: HandlerFunc,
next: Box<Option<Handler>>,
}
impl BasicHandler
impl Handler
where
Self: Sync + Sized,
Self: Send + 'static,
{
pub fn new(next: Option<Arc<BasicHandler>>, func: &'static HandlerFunc) -> Self {
Self { next, func }
pub fn new(handler: HandlerFunc, next: Option<Handler>) -> Self {
Self {
handler,
next: Box::new(next),
}
}
}
#[async_trait]
impl Handler for BasicHandler
where
Self: Sync + Sized,
{
async fn perform(
#[async_recursion(?Send)]
pub async fn perform(
&self,
req: Request<hyper::Body>,
response: Option<Response<hyper::Body>>,
params: Params,
) -> HTTPResult {
let (req, response) = (*self.func)(req, response, params.clone())?;
let (req, response) = (self.handler)(req, response, params.clone()).await?;
if self.next.is_some() {
return Ok(self
.next
.clone()
return Ok((*self.clone().next)
.unwrap()
.perform(req, response, params)
.await?);
@@ -77,7 +61,7 @@ mod tests {
// wakka: wakka wakka
// to the request. that's it!
#[allow(dead_code)]
fn one(
async fn one(
mut req: Request<Body>,
_response: Option<Response<Body>>,
_params: Params,
@@ -89,7 +73,7 @@ mod tests {
// this method returns an OK status when the wakka header exists.
#[allow(dead_code)]
fn two(
async fn two(
req: Request<Body>,
mut response: Option<Response<Body>>,
_params: Params,
@@ -117,11 +101,8 @@ mod tests {
// orchestration!!!!
#[tokio::test]
async fn test_handler_basic() {
use super::Handler;
use std::sync::Arc;
// single stage handler that never yields a response
let bh = super::BasicHandler::new(None, &one);
let bh = super::Handler::new(|req, resp, params| Box::pin(one(req, resp, params)), None);
let req = Request::default();
let (req, response) = bh.perform(req, None, Params::new()).await.unwrap();
if !req.headers().get("wakka").is_some() {
@@ -133,8 +114,12 @@ mod tests {
}
// two-stage handler; yields a response if the first one was good.
let bh_two = super::BasicHandler::new(None, &two);
let bh = super::BasicHandler::new(Some(Arc::new(bh_two.clone())), &one);
let bh_two =
super::Handler::new(|req, resp, params| Box::pin(two(req, resp, params)), None);
let bh = super::Handler::new(
|req, resp, params| Box::pin(one(req, resp, params)),
Some(bh_two.clone()),
);
let (_, response) = bh.perform(req, None, Params::new()).await.unwrap();
if !(response.is_some() && response.unwrap().status() == StatusCode::OK) {
@@ -148,5 +133,7 @@ mod tests {
{
panic!("no error")
}
drop(bh)
}
}
+4 -3
View File
@@ -2,11 +2,12 @@ pub mod handler;
pub mod path;
pub mod router;
use handler::Handler;
use http::{Request, Response};
use crate::handler::BasicHandler;
use std::{collections::BTreeMap, pin::Pin};
use std::collections::BTreeMap;
pub(crate) type PinBox<F> = Pin<Box<F>>;
#[derive(Clone, Debug)]
pub struct Error(String);
@@ -36,5 +37,5 @@ pub type HTTPResult = Result<(Request<hyper::Body>, Option<Response<hyper::Body>
pub struct App {
#[allow(dead_code)] // FIXME remove
routes: BTreeMap<String, &'static BasicHandler>,
routes: BTreeMap<String, Handler>,
}
+2
View File
@@ -47,6 +47,7 @@ impl Path {
self.clone()
}
#[allow(dead_code)]
pub(crate) fn params(&self) -> Vec<&str> {
let mut params = Vec::new();
for arg in self.0.clone() {
@@ -59,6 +60,7 @@ impl Path {
params
}
#[allow(dead_code)]
pub(crate) fn extract(&self, provided: &'static str) -> Result<Params, Error> {
let parts: Vec<&str> = provided.split("/").collect();
let mut params = Params::default();
+8 -11
View File
@@ -1,18 +1,14 @@
use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::collections::BTreeSet;
use http::Request;
use crate::{
handler::{BasicHandler, Handler},
path::Path,
Error, HTTPResult,
};
use crate::{handler::Handler, path::Path, Error, HTTPResult};
#[derive(Clone)]
pub struct Route {
method: http::Method,
path: Path,
handler: BasicHandler,
handler: Handler,
}
impl PartialEq for Route {
@@ -41,7 +37,7 @@ impl Ord for Route {
}
impl Route {
fn new(method: http::Method, path: &'static str, handler: BasicHandler) -> Self {
fn new(method: http::Method, path: &'static str, handler: Handler) -> Self {
Self {
method,
handler,
@@ -49,6 +45,7 @@ impl Route {
}
}
#[allow(dead_code)]
async fn dispatch(&self, provided: &'static str, req: Request<hyper::Body>) -> HTTPResult {
let params = self.path.extract(provided)?;
self.handler.perform(req, None, params).await
@@ -63,12 +60,12 @@ impl Router {
Self(BTreeSet::new())
}
pub fn add(&mut self, method: http::Method, path: &'static str, bh: BasicHandler) -> Self {
self.0.insert(Route::new(method, path, bh));
pub fn add(&mut self, method: http::Method, path: &'static str, ch: Handler) -> Self {
self.0.insert(Route::new(method, path, ch));
self.clone()
}
pub fn find(&self, req: &'static Request<hyper::Body>) -> Result<BasicHandler, Error> {
pub fn find(&self, req: &'static Request<hyper::Body>) -> Result<Handler, Error> {
let path = req.uri().path();
for route_path in self.0.clone() {