Skip to content

Commit

Permalink
handler, extractor
Browse files Browse the repository at this point in the history
  • Loading branch information
lz1998 committed Aug 31, 2023
1 parent bf96df5 commit 83edb64
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion examples/src/http/http.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::{convert::Infallible, net::SocketAddr};

use bytes::Bytes;
use http::{Response, StatusCode};
use http::{Method, Response, StatusCode, Uri};
use hyper::body::Incoming;
use motore::service::service_fn;
use serde::{Deserialize, Serialize};
use volo_http::{
handler::HandlerService,
request::Json,
route::{Route, Router},
HttpContext,
Expand Down Expand Up @@ -51,12 +52,22 @@ async fn json(
Ok(Response::new(()))
}

async fn test(u: Uri, m: Method) -> &'static str {
println!("{u:?}");
println!("{m:?}");
"test"
}

#[tokio::main(flavor = "multi_thread")]
async fn main() {
Router::build()
.route("/", Route::builder().get(service_fn(hello)).build())
.route("/:echo", Route::builder().get(service_fn(echo)).build())
.route("/user", Route::builder().post(service_fn(json)).build())
.route(
"/test",
Route::builder().get(HandlerService::new(test)).build(),
)
.serve(SocketAddr::from(([127, 0, 0, 1], 3000)))
.await
.unwrap();
Expand Down
1 change: 1 addition & 0 deletions volo-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ serde_json = "1"
thiserror.workspace = true
mime = "0.3"
serde = "1"
async-trait.workspace = true

[dev-dependencies]
serde = { version = "1", features = ["derive"] }
37 changes: 37 additions & 0 deletions volo-http/src/extract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use http::{Method, Uri};

use crate::{response::RespBody, HttpContext};
#[async_trait::async_trait]
pub trait FromContext: Sized {
type Rejection: Into<RespBody>;
async fn from_context(context: &mut HttpContext) -> Result<Self, Self::Rejection>;
}
#[async_trait::async_trait]
impl<T> FromContext for Option<T>
where
T: FromContext,
{
type Rejection = &'static str;

async fn from_context(context: &mut HttpContext) -> Result<Self, Self::Rejection> {
Ok(T::from_context(context).await.ok())
}
}

#[async_trait::async_trait]
impl FromContext for Uri {
type Rejection = String;

async fn from_context(context: &mut HttpContext) -> Result<Uri, Self::Rejection> {
Ok(context.uri.clone())
}
}

#[async_trait::async_trait]
impl FromContext for Method {
type Rejection = String;

async fn from_context(context: &mut HttpContext) -> Result<Method, Self::Rejection> {
Ok(context.method.clone())
}
}
102 changes: 102 additions & 0 deletions volo-http/src/handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use std::{future::Future, marker::PhantomData};

use http::{Response, StatusCode};
use hyper::body::Incoming;

use crate::{extract::FromContext, response::RespBody, HttpContext};

impl<H, T> Clone for HandlerService<H, T>
where
H: Clone,
{
fn clone(&self) -> Self {
Self {
h: self.h.clone(),
_mark: PhantomData,
}
}
}
pub trait Handler<'r, T> {
type Future: Future<Output = RespBody> + Send + 'r;
fn call(self, context: &'r mut HttpContext) -> Self::Future;
}

impl<'r, F, Fut, T1, Res> Handler<'r, T1> for F
where
F: FnOnce(T1) -> Fut + Clone + Send + 'r,
Fut: Future<Output = Res> + Send + 'r,
T1: FromContext + Send + 'r,
Res: Into<RespBody>,
{
type Future = impl Future<Output = RespBody> + Send + 'r;

fn call(self, context: &'r mut HttpContext) -> Self::Future {
async move {
let t1 = match T1::from_context(context).await {
Ok(value) => value,
Err(rejection) => return rejection.into(),
};
self(t1).await.into()
}
}
}

impl<'r, F, Fut, T1, T2, Res> Handler<'r, (T1, T2)> for F
where
F: FnOnce(T1, T2) -> Fut + Clone + Send + 'r,
Fut: Future<Output = Res> + Send,
T1: FromContext + Send + 'r,
T2: FromContext + Send + 'r,
Res: Into<RespBody>,
{
type Future = impl Future<Output = RespBody> + Send + 'r;

fn call(self, context: &'r mut HttpContext) -> Self::Future {
async move {
let t1 = match T1::from_context(context).await {
Ok(value) => value,
Err(rejection) => return rejection.into(),
};
let t2 = match T2::from_context(context).await {
Ok(value) => value,
Err(rejection) => return rejection.into(),
};
self(t1, t2).await.into()
}
}
}
pub struct HandlerService<H, T> {
h: H,
_mark: PhantomData<fn(T)>,
}

impl<H, T> HandlerService<H, T> {
pub fn new(h: H) -> Self {
Self {
h,
_mark: PhantomData,
}
}
}

impl<H, T> motore::Service<HttpContext, Incoming> for HandlerService<H, T>
where
H: for<'r> Handler<'r, T> + Clone + Send + Sync,
{
type Response = Response<RespBody>;
type Error = http::Error;
type Future<'cx> = impl Future<Output = Result<Self::Response, Self::Error>> + Send + 'cx
where
HttpContext: 'cx,
Self: 'cx;

fn call<'cx, 's>(&'s self, cx: &'cx mut HttpContext, _req: Incoming) -> Self::Future<'cx>
where
's: 'cx,
{
async move {
let resp = self.h.clone().call(cx).await;
Response::builder().status(StatusCode::OK).body(resp)
}
}
}
2 changes: 2 additions & 0 deletions volo-http/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![feature(impl_trait_in_assoc_type)]

pub(crate) mod dispatch;
pub mod extract;
pub mod handler;
pub mod layer;
pub mod param;
pub mod request;
Expand Down

0 comments on commit 83edb64

Please sign in to comment.