1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2025-02-19 20:36:16 +00:00

Simplify handler (#1843)

This commit is contained in:
fakeshadow 2020-12-23 23:47:07 +08:00 committed by GitHub
parent 2a7f2c1d59
commit 3a192400a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 130 deletions

View file

@ -1,4 +1,3 @@
use std::convert::Infallible;
use std::future::Future; use std::future::Future;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
@ -6,7 +5,7 @@ use std::task::{Context, Poll};
use actix_http::{Error, Response}; use actix_http::{Error, Response};
use actix_service::{Service, ServiceFactory}; use actix_service::{Service, ServiceFactory};
use futures_util::future::{ok, Ready}; use futures_util::future::{ready, Ready};
use futures_util::ready; use futures_util::ready;
use pin_project::pin_project; use pin_project::pin_project;
@ -36,9 +35,11 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
/// Extract arguments from request, run factory function and make response.
pub struct Handler<F, T, R, O> pub struct Handler<F, T, R, O>
where where
F: Factory<T, R, O>, F: Factory<T, R, O>,
T: FromRequest,
R: Future<Output = O>, R: Future<Output = O>,
O: Responder, O: Responder,
{ {
@ -49,6 +50,7 @@ where
impl<F, T, R, O> Handler<F, T, R, O> impl<F, T, R, O> Handler<F, T, R, O>
where where
F: Factory<T, R, O>, F: Factory<T, R, O>,
T: FromRequest,
R: Future<Output = O>, R: Future<Output = O>,
O: Responder, O: Responder,
{ {
@ -63,6 +65,7 @@ where
impl<F, T, R, O> Clone for Handler<F, T, R, O> impl<F, T, R, O> Clone for Handler<F, T, R, O>
where where
F: Factory<T, R, O>, F: Factory<T, R, O>,
T: FromRequest,
R: Future<Output = O>, R: Future<Output = O>,
O: Responder, O: Responder,
{ {
@ -74,172 +77,103 @@ where
} }
} }
impl<F, T, R, O> Service for Handler<F, T, R, O> impl<F, T, R, O> ServiceFactory for Handler<F, T, R, O>
where where
F: Factory<T, R, O>, F: Factory<T, R, O>,
T: FromRequest,
R: Future<Output = O>, R: Future<Output = O>,
O: Responder, O: Responder,
{
type Request = (T, HttpRequest);
type Response = ServiceResponse;
type Error = Infallible;
type Future = HandlerServiceResponse<R, O>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, (param, req): (T, HttpRequest)) -> Self::Future {
let fut = self.hnd.call(param);
HandlerServiceResponse::Future(fut, Some(req))
}
}
#[doc(hidden)]
#[pin_project(project = HandlerProj)]
pub enum HandlerServiceResponse<T, R>
where
T: Future<Output = R>,
R: Responder,
{
Future(#[pin] T, Option<HttpRequest>),
Responder(#[pin] R::Future, Option<HttpRequest>),
}
impl<T, R> Future for HandlerServiceResponse<T, R>
where
T: Future<Output = R>,
R: Responder,
{
type Output = Result<ServiceResponse, Infallible>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match self.as_mut().project() {
HandlerProj::Future(fut, req) => {
let res = ready!(fut.poll(cx));
let fut = res.respond_to(req.as_ref().unwrap());
let state = HandlerServiceResponse::Responder(fut, req.take());
self.as_mut().set(state);
}
HandlerProj::Responder(fut, req) => {
let res = ready!(fut.poll(cx));
let req = req.take().unwrap();
return match res {
Ok(res) => Poll::Ready(Ok(ServiceResponse::new(req, res))),
Err(e) => {
let res: Response = e.into().into();
Poll::Ready(Ok(ServiceResponse::new(req, res)))
}
};
}
}
}
}
}
/// Extract arguments from request
pub struct Extract<T: FromRequest, S> {
service: S,
_t: PhantomData<T>,
}
impl<T: FromRequest, S> Extract<T, S> {
pub fn new(service: S) -> Self {
Extract {
service,
_t: PhantomData,
}
}
}
impl<T: FromRequest, S> ServiceFactory for Extract<T, S>
where
S: Service<
Request = (T, HttpRequest),
Response = ServiceResponse,
Error = Infallible,
> + Clone,
{ {
type Request = ServiceRequest; type Request = ServiceRequest;
type Response = ServiceResponse; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type Config = (); type Config = ();
type Service = ExtractService<T, S>; type Service = Self;
type InitError = (); type InitError = ();
type Future = Ready<Result<Self::Service, ()>>; type Future = Ready<Result<Self::Service, ()>>;
fn new_service(&self, _: ()) -> Self::Future { fn new_service(&self, _: ()) -> Self::Future {
ok(ExtractService { ready(Ok(self.clone()))
_t: PhantomData,
service: self.service.clone(),
})
} }
} }
pub struct ExtractService<T: FromRequest, S> { // Handler is both it's ServiceFactory and Service Type.
service: S, impl<F, T, R, O> Service for Handler<F, T, R, O>
_t: PhantomData<T>,
}
impl<T: FromRequest, S> Service for ExtractService<T, S>
where where
S: Service< F: Factory<T, R, O>,
Request = (T, HttpRequest), T: FromRequest,
Response = ServiceResponse, R: Future<Output = O>,
Error = Infallible, O: Responder,
> + Clone,
{ {
type Request = ServiceRequest; type Request = ServiceRequest;
type Response = ServiceResponse; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type Future = ExtractResponse<T, S>; type Future = HandlerServiceFuture<F, T, R, O>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
fn call(&mut self, req: ServiceRequest) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
let (req, mut payload) = req.into_parts(); let (req, mut payload) = req.into_parts();
let fut = T::from_request(&req, &mut payload); let fut = T::from_request(&req, &mut payload);
ExtractResponse::Future(fut, Some(req), self.service.clone()) HandlerServiceFuture::Extract(fut, Some(req), self.hnd.clone())
} }
} }
#[pin_project(project = ExtractProj)] #[doc(hidden)]
pub enum ExtractResponse<T: FromRequest, S: Service> { #[pin_project(project = HandlerProj)]
Future(#[pin] T::Future, Option<HttpRequest>, S), pub enum HandlerServiceFuture<F, T, R, O>
Response(#[pin] S::Future), where
F: Factory<T, R, O>,
T: FromRequest,
R: Future<Output = O>,
O: Responder,
{
Extract(#[pin] T::Future, Option<HttpRequest>, F),
Handle(#[pin] R, Option<HttpRequest>),
Respond(#[pin] O::Future, Option<HttpRequest>),
} }
impl<T: FromRequest, S> Future for ExtractResponse<T, S> impl<F, T, R, O> Future for HandlerServiceFuture<F, T, R, O>
where where
S: Service< F: Factory<T, R, O>,
Request = (T, HttpRequest), T: FromRequest,
Response = ServiceResponse, R: Future<Output = O>,
Error = Infallible, O: Responder,
>,
{ {
// Error type in this future is a placeholder type.
// all instances of error must be converted to ServiceResponse and return in Ok.
type Output = Result<ServiceResponse, Error>; type Output = Result<ServiceResponse, Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop { loop {
match self.as_mut().project() { match self.as_mut().project() {
ExtractProj::Future(fut, req, srv) => { HandlerProj::Extract(fut, req, handle) => {
let res = ready!(fut.poll(cx)); match ready!(fut.poll(cx)) {
let req = req.take().unwrap();
match res {
Err(e) => {
let req = ServiceRequest::new(req);
return Poll::Ready(Ok(req.error_response(e.into())));
}
Ok(item) => { Ok(item) => {
let fut = srv.call((item, req)); let fut = handle.call(item);
self.as_mut().set(ExtractResponse::Response(fut)); let state = HandlerServiceFuture::Handle(fut, req.take());
self.as_mut().set(state);
} }
} Err(e) => {
let res: Response = e.into().into();
let req = req.take().unwrap();
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
}
};
}
HandlerProj::Handle(fut, req) => {
let res = ready!(fut.poll(cx));
let fut = res.respond_to(req.as_ref().unwrap());
let state = HandlerServiceFuture::Respond(fut, req.take());
self.as_mut().set(state);
}
HandlerProj::Respond(fut, req) => {
let res = ready!(fut.poll(cx)).unwrap_or_else(|e| e.into().into());
let req = req.take().unwrap();
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
} }
ExtractProj::Response(fut) => return fut.poll(cx).map_err(|_| panic!()),
} }
} }
} }

View file

@ -11,7 +11,7 @@ use futures_util::future::{ready, FutureExt, LocalBoxFuture};
use crate::extract::FromRequest; use crate::extract::FromRequest;
use crate::guard::{self, Guard}; use crate::guard::{self, Guard};
use crate::handler::{Extract, Factory, Handler}; use crate::handler::{Factory, Handler};
use crate::responder::Responder; use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceRequest, ServiceResponse};
use crate::HttpResponse; use crate::HttpResponse;
@ -51,9 +51,9 @@ impl Route {
#[allow(clippy::new_without_default)] #[allow(clippy::new_without_default)]
pub fn new() -> Route { pub fn new() -> Route {
Route { Route {
service: Box::new(RouteNewService::new(Extract::new(Handler::new(|| { service: Box::new(RouteNewService::new(Handler::new(|| {
ready(HttpResponse::NotFound()) ready(HttpResponse::NotFound())
})))), }))),
guards: Rc::new(Vec::new()), guards: Rc::new(Vec::new()),
} }
} }
@ -226,8 +226,7 @@ impl Route {
R: Future<Output = U> + 'static, R: Future<Output = U> + 'static,
U: Responder + 'static, U: Responder + 'static,
{ {
self.service = self.service = Box::new(RouteNewService::new(Handler::new(handler)));
Box::new(RouteNewService::new(Extract::new(Handler::new(handler))));
self self
} }
} }