First stab at a handler framework; a basic chain-of-responsibility pattern

This is intended to make middleware a forefront technology.

Signed-off-by: Erik Hollensbe <linux@hollensbe.org>
This commit is contained in:
Erik Hollensbe
2022-01-14 23:44:16 -08:00
parent ae9340276f
commit 369ee0006c
3 changed files with 63 additions and 7 deletions
+1
View File
@@ -8,3 +8,4 @@ edition = "2021"
[dependencies]
hyper = { version = "*", features = [ "http1", "http2", "server", "runtime", "tcp", "stream" ] }
http = "*"
async-trait = "*"
+50
View File
@@ -0,0 +1,50 @@
use crate::Params;
use async_trait::async_trait;
use hyper::{Error, Request, Response};
pub type HandlerFunc<T, R> =
dyn Fn(&Request<T>, &Params, Option<&Response<R>>) -> Result<Response<R>, Error>;
#[async_trait]
pub trait Handler<R>
where
Self: Send + Sync + 'static,
{
async fn perform(&self, response: Option<&Response<R>>) -> Result<Response<R>, Error>;
}
pub struct BasicHandler<T, R>
where
T: Send + Sync + 'static,
R: Send + Sync + 'static,
{
req: Request<T>,
params: Params,
next: Option<&'static BasicHandler<T, R>>,
func: &'static HandlerFunc<T, R>,
}
impl<T, R> BasicHandler<T, R>
where
T: Send + Sync + 'static,
R: Send + Sync + 'static,
{
}
#[async_trait]
impl<T, R> Handler<R> for BasicHandler<T, R>
where
Self: Send + Sync,
R: Copy + Send + Sync + Sized + 'static,
T: Copy + Send + Sync + Sized + 'static,
{
async fn perform(&self, response: Option<&Response<R>>) -> Result<Response<R>, Error> {
let response = (*self.func)(&self.req, &self.params, response)?;
if self.next.is_some() {
return Ok(self.next.unwrap().perform(Some(&response)).await?);
}
Ok(response)
}
}
+12 -7
View File
@@ -1,8 +1,13 @@
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
pub mod handler;
use crate::handler::BasicHandler;
use std::collections::BTreeMap;
#[derive(Debug, Clone)]
pub struct Params(BTreeMap<String, String>);
pub struct App {
#[allow(dead_code)] // FIXME remove
routes: BTreeMap<String, BasicHandler<hyper::Body, hyper::Body>>,
}