1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-12-02 19:32:24 +01:00

refactor Scope (#1895)

This commit is contained in:
fakeshadow 2021-01-10 02:06:49 +08:00 committed by GitHub
parent fe392abeb4
commit 9e401b6ef7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 147 deletions

View File

@ -62,7 +62,8 @@ where
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>; type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
fn new_service(&self, config: AppConfig) -> Self::Future { fn new_service(&self, config: AppConfig) -> Self::Future {
// update resource default service // set AppService's default service to 404 NotFound
// if no user defined default service exists.
let default = self.default.clone().unwrap_or_else(|| { let default = self.default.clone().unwrap_or_else(|| {
Rc::new(boxed::factory(fn_service(|req: ServiceRequest| async { Rc::new(boxed::factory(fn_service(|req: ServiceRequest| async {
Ok(req.into_response(Response::NotFound().finish())) Ok(req.into_response(Response::NotFound().finish()))

View File

@ -1,18 +1,18 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt; use std::fmt;
use std::future::Future; use std::future::Future;
use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::task::{Context, Poll}; use std::task::Poll;
use actix_http::{Extensions, Response}; use actix_http::Extensions;
use actix_router::{ResourceDef, ResourceInfo, Router}; use actix_router::{ResourceDef, Router};
use actix_service::boxed::{self, BoxService, BoxServiceFactory}; use actix_service::boxed::{self, BoxService, BoxServiceFactory};
use actix_service::{ use actix_service::{
apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory, apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory,
ServiceFactoryExt, Transform, ServiceFactoryExt, Transform,
}; };
use futures_core::future::LocalBoxFuture; use futures_core::future::LocalBoxFuture;
use futures_util::future::join_all;
use crate::config::ServiceConfig; use crate::config::ServiceConfig;
use crate::data::Data; use crate::data::Data;
@ -61,10 +61,10 @@ type HttpNewService = BoxServiceFactory<(), ServiceRequest, ServiceResponse, Err
pub struct Scope<T = ScopeEndpoint> { pub struct Scope<T = ScopeEndpoint> {
endpoint: T, endpoint: T,
rdef: String, rdef: String,
data: Option<Extensions>, app_data: Option<Extensions>,
services: Vec<Box<dyn AppServiceFactory>>, services: Vec<Box<dyn AppServiceFactory>>,
guards: Vec<Box<dyn Guard>>, guards: Vec<Box<dyn Guard>>,
default: Rc<RefCell<Option<Rc<HttpNewService>>>>, default: Option<Rc<HttpNewService>>,
external: Vec<ResourceDef>, external: Vec<ResourceDef>,
factory_ref: Rc<RefCell<Option<ScopeFactory>>>, factory_ref: Rc<RefCell<Option<ScopeFactory>>>,
} }
@ -76,10 +76,10 @@ impl Scope {
Scope { Scope {
endpoint: ScopeEndpoint::new(fref.clone()), endpoint: ScopeEndpoint::new(fref.clone()),
rdef: path.to_string(), rdef: path.to_string(),
data: None, app_data: None,
guards: Vec::new(), guards: Vec::new(),
services: Vec::new(), services: Vec::new(),
default: Rc::new(RefCell::new(None)), default: None,
external: Vec::new(), external: Vec::new(),
factory_ref: fref, factory_ref: fref,
} }
@ -155,10 +155,10 @@ where
/// ///
/// Data of different types from parent contexts will still be accessible. /// Data of different types from parent contexts will still be accessible.
pub fn app_data<U: 'static>(mut self, data: U) -> Self { pub fn app_data<U: 'static>(mut self, data: U) -> Self {
if self.data.is_none() { if self.app_data.is_none() {
self.data = Some(Extensions::new()); self.app_data = Some(Extensions::new());
} }
self.data.as_mut().unwrap().insert(data); self.app_data.as_mut().unwrap().insert(data);
self self
} }
@ -201,15 +201,15 @@ where
self.external.extend(cfg.external); self.external.extend(cfg.external);
if !cfg.data.is_empty() { if !cfg.data.is_empty() {
let mut data = self.data.unwrap_or_else(Extensions::new); let mut data = self.app_data.unwrap_or_else(Extensions::new);
for value in cfg.data.iter() { for value in cfg.data.iter() {
value.create(&mut data); value.create(&mut data);
} }
self.data = Some(data); self.app_data = Some(data);
} }
self.data self.app_data
.get_or_insert_with(Extensions::new) .get_or_insert_with(Extensions::new)
.extend(cfg.extensions); .extend(cfg.extensions);
self self
@ -295,11 +295,9 @@ where
U::InitError: fmt::Debug, U::InitError: fmt::Debug,
{ {
// create and configure default resource // create and configure default resource
self.default = Rc::new(RefCell::new(Some(Rc::new(boxed::factory( self.default = Some(Rc::new(boxed::factory(f.into_factory().map_init_err(
f.into_factory().map_init_err(|e| { |e| log::error!("Can not construct default service: {:?}", e),
log::error!("Can not construct default service: {:?}", e) ))));
}),
)))));
self self
} }
@ -337,7 +335,7 @@ where
Scope { Scope {
endpoint: apply(mw, self.endpoint), endpoint: apply(mw, self.endpoint),
rdef: self.rdef, rdef: self.rdef,
data: self.data, app_data: self.app_data,
guards: self.guards, guards: self.guards,
services: self.services, services: self.services,
default: self.default, default: self.default,
@ -397,7 +395,7 @@ where
Scope { Scope {
endpoint: apply_fn_factory(self.endpoint, mw), endpoint: apply_fn_factory(self.endpoint, mw),
rdef: self.rdef, rdef: self.rdef,
data: self.data, app_data: self.app_data,
guards: self.guards, guards: self.guards,
services: self.services, services: self.services,
default: self.default, default: self.default,
@ -419,9 +417,7 @@ where
{ {
fn register(mut self, config: &mut AppService) { fn register(mut self, config: &mut AppService) {
// update default resource if needed // update default resource if needed
if self.default.borrow().is_none() { let default = self.default.unwrap_or_else(|| config.default_service());
*self.default.borrow_mut() = Some(config.default_service());
}
// register nested services // register nested services
let mut cfg = config.clone_config(); let mut cfg = config.clone_config();
@ -437,14 +433,14 @@ where
} }
// custom app data storage // custom app data storage
if let Some(ref mut ext) = self.data { if let Some(ref mut ext) = self.app_data {
config.set_service_data(ext); config.set_service_data(ext);
} }
// complete scope pipeline creation // complete scope pipeline creation
*self.factory_ref.borrow_mut() = Some(ScopeFactory { *self.factory_ref.borrow_mut() = Some(ScopeFactory {
data: self.data.take().map(Rc::new), app_data: self.app_data.take().map(Rc::new),
default: self.default.clone(), default,
services: cfg services: cfg
.into_services() .into_services()
.1 .1
@ -476,129 +472,65 @@ where
} }
pub struct ScopeFactory { pub struct ScopeFactory {
data: Option<Rc<Extensions>>, app_data: Option<Rc<Extensions>>,
services: Rc<[(ResourceDef, HttpNewService, RefCell<Option<Guards>>)]>, services: Rc<[(ResourceDef, HttpNewService, RefCell<Option<Guards>>)]>,
default: Rc<RefCell<Option<Rc<HttpNewService>>>>, default: Rc<HttpNewService>,
} }
impl ServiceFactory<ServiceRequest> for ScopeFactory { impl ServiceFactory<ServiceRequest> for ScopeFactory {
type Config = ();
type Response = ServiceResponse; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type InitError = (); type Config = ();
type Service = ScopeService; type Service = ScopeService;
type Future = ScopeFactoryResponse; type InitError = ();
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future { fn new_service(&self, _: ()) -> Self::Future {
let default_fut = if let Some(ref default) = *self.default.borrow() { // construct default service factory future
Some(default.new_service(())) let default_fut = self.default.new_service(());
} else {
None
};
ScopeFactoryResponse { // construct all services factory future with it's resource def and guards.
fut: self let factory_fut =
.services join_all(self.services.iter().map(|(path, factory, guards)| {
.iter() let path = path.clone();
.map(|(path, service, guards)| { let guards = guards.borrow_mut().take();
CreateScopeServiceItem::Future( let factory_fut = factory.new_service(());
Some(path.clone()), async move {
guards.borrow_mut().take(), let service = factory_fut.await?;
service.new_service(()), Ok((path, guards, service))
)
})
.collect(),
default: None,
data: self.data.clone(),
default_fut,
} }
} }));
}
/// Create scope service let app_data = self.app_data.clone();
#[doc(hidden)]
#[pin_project::pin_project]
pub struct ScopeFactoryResponse {
fut: Vec<CreateScopeServiceItem>,
data: Option<Rc<Extensions>>,
default: Option<HttpService>,
default_fut: Option<LocalBoxFuture<'static, Result<HttpService, ()>>>,
}
type HttpServiceFut = LocalBoxFuture<'static, Result<HttpService, ()>>; Box::pin(async move {
let default = default_fut.await?;
enum CreateScopeServiceItem { // build router from the factory future result.
Future(Option<ResourceDef>, Option<Guards>, HttpServiceFut), let router = factory_fut
Service(ResourceDef, Option<Guards>, HttpService), .await
} .into_iter()
.collect::<Result<Vec<_>, _>>()?
impl Future for ScopeFactoryResponse {
type Output = Result<ScopeService, ()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut done = true;
if let Some(ref mut fut) = self.default_fut {
match Pin::new(fut).poll(cx)? {
Poll::Ready(default) => self.default = Some(default),
Poll::Pending => done = false,
}
}
// poll http services
for item in &mut self.fut {
let res = match item {
CreateScopeServiceItem::Future(
ref mut path,
ref mut guards,
ref mut fut,
) => match Pin::new(fut).poll(cx)? {
Poll::Ready(service) => {
Some((path.take().unwrap(), guards.take(), service))
}
Poll::Pending => {
done = false;
None
}
},
CreateScopeServiceItem::Service(_, _, _) => continue,
};
if let Some((path, guards, service)) = res {
*item = CreateScopeServiceItem::Service(path, guards, service);
}
}
if done {
let router = self
.fut
.drain(..) .drain(..)
.fold(Router::build(), |mut router, item| { .fold(Router::build(), |mut router, (path, guards, service)| {
match item {
CreateScopeServiceItem::Service(path, guards, service) => {
router.rdef(path, service).2 = guards; router.rdef(path, service).2 = guards;
}
CreateScopeServiceItem::Future(_, _, _) => unreachable!(),
}
router router
}); })
Poll::Ready(Ok(ScopeService { .finish();
data: self.data.clone(),
router: router.finish(), Ok(ScopeService {
default: self.default.take(), app_data,
_ready: None, router,
})) default,
} else { })
Poll::Pending })
}
} }
} }
pub struct ScopeService { pub struct ScopeService {
data: Option<Rc<Extensions>>, app_data: Option<Rc<Extensions>>,
router: Router<HttpService, Vec<Box<dyn Guard>>>, router: Router<HttpService, Vec<Box<dyn Guard>>>,
default: Option<HttpService>, default: HttpService,
_ready: Option<(ServiceRequest, ResourceInfo)>,
} }
impl Service<ServiceRequest> for ScopeService { impl Service<ServiceRequest> for ScopeService {
@ -606,9 +538,7 @@ impl Service<ServiceRequest> for ScopeService {
type Error = Error; type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { actix_service::always_ready!();
Poll::Ready(Ok(()))
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future { fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let res = self.router.recognize_mut_checked(&mut req, |req, guards| { let res = self.router.recognize_mut_checked(&mut req, |req, guards| {
@ -622,21 +552,14 @@ impl Service<ServiceRequest> for ScopeService {
true true
}); });
if let Some(ref app_data) = self.app_data {
req.add_data_container(app_data.clone());
}
if let Some((srv, _info)) = res { if let Some((srv, _info)) = res {
if let Some(ref data) = self.data {
req.add_data_container(data.clone());
}
srv.call(req) srv.call(req)
} else if let Some(ref mut default) = self.default {
if let Some(ref data) = self.data {
req.add_data_container(data.clone());
}
default.call(req)
} else { } else {
let req = req.into_parts().0; self.default.call(req)
Box::pin(async {
Ok(ServiceResponse::new(req, Response::NotFound().finish()))
})
} }
} }
} }
@ -658,7 +581,7 @@ impl ServiceFactory<ServiceRequest> for ScopeEndpoint {
type Config = (); type Config = ();
type Service = ScopeService; type Service = ScopeService;
type InitError = (); type InitError = ();
type Future = ScopeFactoryResponse; type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future { fn new_service(&self, _: ()) -> Self::Future {
self.factory.borrow_mut().as_mut().unwrap().new_service(()) self.factory.borrow_mut().as_mut().unwrap().new_service(())