This commit is contained in:
Nikolay Kim 2022-02-09 18:10:43 +06:00
parent 4824b31b3c
commit 6d454a36eb
7 changed files with 358 additions and 256 deletions

View file

@ -6,11 +6,11 @@ use crate::service::map_config;
use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform};
use crate::util::Extensions;
use super::app_service::{AppFactory, AppFactoryInner, AppRouting, DefaultService};
use super::app_service::{AppFactory, AppFactoryInner, AppRouting};
use super::boxed::{self, BoxServiceFactory};
use super::config::{AppConfig, ServiceConfig};
use super::error::Error;
use super::service::{create_web_service, WebService, WebServiceWrapper};
use super::service::{create_web_service, DefaultService, WebService, WebServiceWrapper};
use super::stack::{Filter, Filters, FiltersFactory, Next, Stack};
use super::types::state::{State, StateFactory};
use super::{DefaultError, ErrorRenderer, Resource, Route, WebRequest, WebResponse};

View file

@ -1,11 +1,10 @@
use std::convert::Infallible;
use std::task::{Context, Poll};
use std::{cell::RefCell, future::Future, marker::PhantomData, pin::Pin, rc::Rc};
use std::{cell::RefCell, convert::Infallible, future::Future, pin::Pin, rc::Rc};
use crate::http::{Request, Response};
use crate::router::{Path, ResourceDef, Router};
use crate::service::{Service, ServiceFactory, Transform};
use crate::util::{ready, Either, Extensions, Ready};
use crate::util::{ready, Either, Extensions};
use super::boxed::{BoxService, BoxServiceFactory};
use super::httprequest::{HttpRequest, HttpRequestPool};
@ -135,43 +134,6 @@ where
pub(super) case_insensitive: bool,
}
#[derive(Copy, Clone)]
pub(super) struct DefaultService<Err>(PhantomData<Err>);
impl<Err> Default for DefaultService<Err> {
fn default() -> Self {
DefaultService(PhantomData)
}
}
impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>>
for DefaultService<Err>
{
type Response = WebResponse;
type Error = Infallible;
type InitError = ();
type Service = Self;
type Future = Ready<Self::Service, Self::InitError>;
fn new_service(&self, _: ()) -> Self::Future {
Ready::Ok(DefaultService(PhantomData))
}
}
impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for DefaultService<Err> {
type Response = WebResponse;
type Error = Infallible;
type Future = Ready<Self::Response, Self::Error>;
fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&self, _: &'a mut WebRequest<'a, Err>) -> Self::Future {
Ready::Ok(Response::NotFound().finish().into())
}
}
impl<'a, T, F, Err> AppFactoryInner<'a, T, F, Err>
where
T: Transform<

View file

@ -17,10 +17,33 @@ use crate::util::{BytesMut, Either};
pub use super::error_default::DefaultError;
pub use crate::http::error::BlockingError;
pub trait ErrorRenderer: Sized + 'static {}
pub trait ErrorRenderer: Sized + 'static {
#[inline]
/// Generate response for error
///
/// Internal server error is generated by default.
fn error_response<E: fmt::Display>(
err: E,
_: &HttpRequest,
st: StatusCode,
) -> HttpResponse {
let mut resp = HttpResponse::new(st);
let mut buf = BytesMut::new();
let _ = write!(Writer(&mut buf), "{}", err);
resp.headers_mut().insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("text/plain; charset=utf-8"),
);
resp.set_body(Body::from(buf))
}
}
/// Error that can be rendered to a `Response`
pub trait Error<Err = DefaultError>: fmt::Display + fmt::Debug + Sized {
pub trait Error<Err = DefaultError>: fmt::Display + fmt::Debug + Sized
where
Err: ErrorRenderer,
{
#[inline]
/// Response's status code
///
/// Internal server error is generated by default.
@ -28,18 +51,13 @@ pub trait Error<Err = DefaultError>: fmt::Display + fmt::Debug + Sized {
StatusCode::INTERNAL_SERVER_ERROR
}
#[inline]
/// Generate response for error
///
/// Internal server error is generated by default.
fn error_response(self, _: &HttpRequest) -> HttpResponse {
let mut resp = HttpResponse::new(self.status_code());
let mut buf = BytesMut::new();
let _ = write!(Writer(&mut buf), "{}", self);
resp.headers_mut().insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("text/plain; charset=utf-8"),
);
resp.set_body(Body::from(buf))
fn error_response(self, req: &HttpRequest) -> HttpResponse {
let st = self.status_code();
<Err as ErrorRenderer>::error_response(self, req, st)
}
}

View file

@ -64,6 +64,7 @@
mod app;
mod app_service;
mod boxed;
mod config;
pub mod error;
mod error_default;
@ -80,7 +81,6 @@ mod response;
mod rmap;
mod route;
// mod scope;
mod boxed;
mod server;
mod service;
mod stack;

View file

@ -1,29 +1,26 @@
use std::task::{Context, Poll};
use std::{cell::RefCell, fmt, future::Future, convert::Infallible, pin::Pin, rc::Rc};
use std::{
cell::RefCell, fmt, future::Future, pin::Pin, rc::Rc, task::Context, task::Poll,
};
use std::{convert::Infallible, marker::PhantomData};
use crate::http::Response;
use crate::router::{IntoPattern, ResourceDef, Router};
use crate::service::boxed::{self, BoxService, BoxServiceFactory};
use crate::service::{pipeline_factory, PipelineFactory};
use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform};
use crate::util::{Either, Extensions, Ready};
use crate::util::{ready, Extensions};
use super::config::ServiceConfig;
use super::dev::{WebServiceConfig, WebServiceFactory};
use super::boxed::{self, BoxService, BoxServiceFactory};
use super::config::{AppConfig, ServiceConfig};
use super::error::Error;
use super::guard::Guard;
use super::rmap::ResourceMap;
use super::service::{AppServiceFactory, ServiceFactoryWrapper};
use super::stack::{Filter, Next, Stack, MiddlewareStack, Middleware};
use super::service::{WebService, WebServiceConfig, DefaultService};
use super::stack::{
Filter, Filters, FiltersFactory, Middleware, MiddlewareStack, Next, Services,
ServicesFactory, Stack,
};
use super::types::State;
use super::{ErrorRenderer, Resource, Route, WebRequest, WebResponse};
type Guards = Vec<Box<dyn Guard>>;
type HttpService<Err: ErrorRenderer> =
BoxService<&'a mut WebRequest<'a, Err>, WebResponse, Err::Container>;
type HttpNewService<Err: ErrorRenderer> =
BoxServiceFactory<(), &'a mut WebRequest<'a, Err>, WebResponse, Err::Container, ()>;
type BoxResponse<Err: ErrorRenderer> =
Pin<Box<dyn Future<Output = Result<WebResponse, Err::Container>>>>;
/// Resources scope.
///
@ -54,43 +51,39 @@ type BoxResponse<Err: ErrorRenderer> =
/// * /{project_id}/path2 - `GET` requests
/// * /{project_id}/path3 - `HEAD` requests
///
pub struct Scope<Err: ErrorRenderer, M = Identity, T = Filter<Err>> {
pub struct Scope<Err: ErrorRenderer, S = Identity, M = Identity, F = Filter> {
service: S,
filter: F,
middleware: M,
filter: PipelineFactory<T, &'a mut WebRequest<'a, Err>>,
rdef: Vec<String>,
state: Option<Extensions>,
services: Vec<Box<dyn AppServiceFactory<Err>>>,
// default: BoxServiceFactory<'a, Err>,
guards: Vec<Box<dyn Guard>>,
default: Rc<RefCell<Option<Rc<HttpNewService<Err>>>>>,
external: Vec<ResourceDef>,
case_insensitive: bool,
_marker: PhantomData<Err>,
}
impl<Err: ErrorRenderer> Scope<Err> {
/// Create a new scope
pub fn new<T: IntoPattern>(path: T) -> Scope<Err> {
Scope {
service: Identity,
filter: Filter,
middleware: Identity,
filter: pipeline_factory(Filter::new()),
rdef: path.patterns(),
state: None,
guards: Vec::new(),
services: Vec::new(),
default: Rc::new(RefCell::new(None)),
// default: boxed::factory(DefaultService::default()),
external: Vec::new(),
case_insensitive: false,
_marker: PhantomData,
}
}
}
impl<Err, M, T> Scope<Err, M, T>
impl<Err, S, M, F> Scope<Err, S, M, F>
where
T: ServiceFactory<
&'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container,
InitError = (),
>,
Err: ErrorRenderer,
{
/// Add match guard to a scope.
@ -195,24 +188,24 @@ where
/// .route("/index.html", web::get().to(|| async { HttpResponse::Ok() }));
/// }
/// ```
pub fn configure<F>(mut self, f: F) -> Self
pub fn configure<'a, U>(mut self, f: U) -> Self
where
F: FnOnce(&mut ServiceConfig<Err>),
U: FnOnce(&mut ServiceConfig<'a, Err>),
{
let mut cfg = ServiceConfig::new();
f(&mut cfg);
self.services.extend(cfg.services);
self.external.extend(cfg.external);
//let mut cfg = ServiceConfig::new();
//f(&mut cfg);
//self.services.extend(cfg.services);
//self.external.extend(cfg.external);
if !cfg.state.is_empty() {
let mut state = self.state.unwrap_or_else(Extensions::new);
// if !cfg.state.is_empty() {
// let mut state = self.state.unwrap_or_else(Extensions::new);
for value in cfg.state.iter() {
value.create(&mut state);
}
// for value in cfg.state.iter() {
// value.create(&mut state);
// }
self.state = Some(state);
}
// self.state = Some(state);
// }
self
}
@ -243,13 +236,19 @@ where
/// );
/// }
/// ```
pub fn service<F>(mut self, factory: F) -> Self
where
F: WebServiceFactory<Err> + 'static,
{
self.services
.push(Box::new(ServiceFactoryWrapper::new(factory)));
self
pub fn service<U>(self, factory: U) -> Scope<Err, Services<S, Next<U>>, M, F> {
Scope {
service: Services::new(self.service, Next::new(factory)),
filter: self.filter,
middleware: self.middleware,
rdef: self.rdef,
state: self.state,
guards: self.guards,
// default: self.default,
external: self.external,
case_insensitive: self.case_insensitive,
_marker: PhantomData,
}
}
/// Configure route for a specific path.
@ -273,7 +272,11 @@ where
/// );
/// }
/// ```
pub fn route(self, path: &str, mut route: Route<Err>) -> Self {
pub fn route(
self,
path: &str,
mut route: Route<Err>,
) -> Scope<Err, Services<S, Next<Resource<Err>>>, M, F> {
self.service(
Resource::new(path)
.add_guards(route.take_guards())
@ -284,18 +287,20 @@ where
/// Default service to be used if no matching route could be found.
///
/// If default resource is not registered, app's default resource is being used.
pub fn default_service<F, S>(mut self, f: F) -> Self
pub fn default<'a, T, U>(mut self, f: T) -> Self
where
F: IntoServiceFactory<S, &'a mut WebRequest<'a, Err>>,
S: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container>
+ 'static,
S::InitError: fmt::Debug,
T: IntoServiceFactory<U, &'a mut WebRequest<'a, Err>>,
U: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static,
U::Service: 'static,
U::Future: 'static,
U::Error: Error<Err>,
U::InitError: fmt::Debug + 'static,
{
// create and configure default resource
self.default = Rc::new(RefCell::new(Some(Rc::new(boxed::factory(
f.into_factory()
.map_init_err(|e| log::error!("Cannot construct default service: {:?}", e)),
)))));
//self.default =
// boxed::factory(f.into_factory().map_init_err(|e| {
// log::error!("Cannot construct default service: {:?}", e)
// }));
self
}
@ -307,38 +312,18 @@ where
/// necessary, across all requests managed by the *Scope*.
///
/// This is similar to `App's` filters, but filter get invoked on scope level.
pub fn filter<U, F>(
self,
filter: F,
) -> Scope<
Err,
M,
impl ServiceFactory<
&'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container,
InitError = (),
>,
>
where
U: ServiceFactory<
&'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container,
InitError = (),
>,
F: IntoServiceFactory<U, &'a mut WebRequest<'a, Err>>,
{
pub fn filter<U>(self, filter: U) -> Scope<Err, S, M, Filters<F, Next<U>>> {
Scope {
filter: self.filter.and_then(filter.into_factory()),
filter: Filters::new(self.filter, Next::new(filter)),
service: self.service,
middleware: self.middleware,
rdef: self.rdef,
state: self.state,
guards: self.guards,
services: self.services,
default: self.default,
// default: self.default,
external: self.external,
case_insensitive: self.case_insensitive,
_marker: PhantomData,
}
}
@ -352,46 +337,53 @@ where
/// WebResponse.
///
/// Use middleware when you need to read or modify *every* request in some way.
pub fn wrap<U>(self, mw: U) -> Scope<Err, Stack<M, U, Err>, T> {
pub fn wrap<U>(self, mw: U) -> Scope<Err, S, Stack<M, U>, F> {
Scope {
middleware: Stack::new(self.middleware, mw),
filter: self.filter,
service: self.service,
rdef: self.rdef,
state: self.state,
guards: self.guards,
services: self.services,
default: self.default,
// default: self.default,
external: self.external,
case_insensitive: self.case_insensitive,
_marker: PhantomData,
}
}
}
impl<Err, M, T> WebServiceFactory<Err> for Scope<Err, M, T>
impl<'a, Err, S, M, F> WebService<'a, Err> for Scope<Err, S, M, F>
where
T: ServiceFactory<
&'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container,
InitError = (),
> + 'static,
M: Transform<Next<ScopeService<T::Service, Err>, Err>> + 'static,
S: ServicesFactory<'a, Err> + 'static,
M: Transform<
ScopeService<
'a,
<F::Service as ServiceFactory<&'a mut WebRequest<'a, Err>>>::Service,
Err,
>,
> + 'static,
M::Service: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>,
<M::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a,
F: FiltersFactory<'a, Err> + 'static,
Err: ErrorRenderer,
{
fn register(mut self, config: &mut WebServiceConfig<Err>) {
fn register(mut self, config: &mut WebServiceConfig<'a, Err>) {
// update default resource if needed
if self.default.borrow().is_none() {
*self.default.borrow_mut() = Some(config.default_service());
}
//if self.default.borrow().is_none() {
// *self.default.borrow_mut() = Some(config.default_service());
//}
// register nested services
let mut cfg = config.clone_config();
self.services
.into_iter()
.for_each(|mut srv| srv.register(&mut cfg));
// // register nested services
// let mut cfg: WebServiceConfig<'a, Err> = WebServiceConfig::<'a, _>::new(
// config.config.clone(),
// Rc::new(boxed::factory(DefaultService::default())),
// config.service_state.clone()
// );
// self.service.register(&mut cfg);
let slesh = self.rdef.iter().any(|s| s.ends_with('/'));
let slash = self.rdef.iter().any(|s| s.ends_with('/'));
let mut rmap = ResourceMap::new(ResourceDef::root_prefix(self.rdef.clone()));
// external resources
@ -400,33 +392,33 @@ where
}
// custom app data storage
if let Some(ref mut ext) = self.state {
config.set_service_state(ext);
}
//if let Some(ref mut ext) = self.state {
// config.set_service_state(ext);
//}
// complete scope pipeline creation
let router_factory = ScopeRouterFactory {
state: self.state.take().map(Rc::new),
default: self.default.clone(),
case_insensitive: self.case_insensitive,
services: Rc::new(
cfg.into_services()
.1
.into_iter()
.map(|(rdef, srv, guards, nested)| {
// case for scope prefix ends with '/' and
// resource is empty pattern
let mut rdef = if slesh && rdef.pattern() == "" {
ResourceDef::new("/")
} else {
rdef
};
rmap.add(&mut rdef, nested);
(rdef, srv, RefCell::new(guards))
})
.collect(),
),
};
// let router_factory: ScopeRouterFactory<'a, Err> = ScopeRouterFactory {
// state: self.state.take().map(Rc::new),
// // default: self.default.clone(),
// case_insensitive: self.case_insensitive,
// services: Rc::new(
// cfg.into_services()
// .1
// .into_iter()
// .map(|(rdef, srv, guards, nested)| {
// // case for scope prefix ends with '/' and
// // resource is empty pattern
// let mut rdef = if slesh && rdef.pattern() == "" {
// ResourceDef::new("/")
// } else {
// rdef
// };
// rmap.add(&mut rdef, nested);
// (rdef, srv, RefCell::new(guards))
// })
// .collect(),
// ),
// };
// get guards
let guards = if self.guards.is_empty() {
@ -440,9 +432,14 @@ where
ResourceDef::root_prefix(self.rdef),
guards,
ScopeServiceFactory {
slash,
config: config.config.clone(),
middleware: Rc::new(MiddlewareStack::new(self.middleware)),
filter: self.filter,
routing: router_factory,
filter: self.filter.create(),
state: self.state.take().map(Rc::new),
// default: self.default.clone(),
case_insensitive: self.case_insensitive,
service: self.service,
},
Some(Rc::new(rmap)),
)
@ -450,33 +447,79 @@ where
}
/// Scope service
struct ScopeServiceFactory<M, F, Err: ErrorRenderer> {
struct ScopeServiceFactory<Err: ErrorRenderer, S, M, F> {
config: AppConfig,
middleware: Rc<MiddlewareStack<M, Err>>,
filter: F,
routing: ScopeRouterFactory<Err>,
service: S,
state: Option<Rc<Extensions>>,
slash: bool,
case_insensitive: bool,
// default: Rc<RefCell<Option<Rc<BoxServiceFactory<'a, Err>>>>>,
// routing: ScopeRouterFactory<'a, Err>,
}
impl<M, F, Err> ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeServiceFactory<M, F, Err>
impl<'a, Err, S, M, F> ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeServiceFactory<Err, S, M, F>
where
M: Transform<Next<ScopeService<F::Service, Err>, Err>> + 'static,
S: ServicesFactory<'a, Err> + 'static,
M: Transform<ScopeService<'a, F::Service, Err>> + 'static,
M::Service: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>,
F: ServiceFactory<
&'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container,
Error = Infallible,
InitError = (),
> + 'static,
F::Service: 'static,
F::Future: 'static,
Err: ErrorRenderer,
{
type Response = WebResponse;
type Error = Err::Container;
type Error = Infallible;
type Service = Middleware<M::Service, Err>;
type InitError = ();
type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::InitError>>>>;
fn new_service(&self, _: ()) -> Self::Future {
// register nested services
let mut cfg: WebServiceConfig<'a, Err> = WebServiceConfig::<'a, _>::new(
self.config.clone(),
Rc::new(boxed::factory(DefaultService::default())),
Rc::new(Vec::new()),
);
// custom app data storage
if let Some(ref mut ext) = self.state {
cfg.set_service_state(ext);
}
// complete scope pipeline creation
self.service.register(&mut cfg);
let router_factory: ScopeRouterFactory<'a, Err> = ScopeRouterFactory {
state: self.state.take(),
// default: self.default.clone(),
case_insensitive: self.case_insensitive,
services: Rc::new(
cfg.into_services()
.1
.into_iter()
.map(|(rdef, srv, guards, nested)| {
// case for scope prefix ends with '/' and
// resource is empty pattern
let mut rdef = if self.slash && rdef.pattern() == "" {
ResourceDef::new("/")
} else {
rdef
};
(rdef, srv, RefCell::new(guards))
})
.collect(),
),
};
let filter_fut = self.filter.new_service(());
let routing_fut = self.routing.new_service(());
let routing_fut = router_factory.new_service(());
let middleware = self.middleware.clone();
Box::pin(async move {
Ok(middleware.new_transform(ScopeService {
@ -487,24 +530,28 @@ where
}
}
pub struct ScopeService<F, Err: ErrorRenderer> {
pub struct ScopeService<'a, F, Err: ErrorRenderer> {
filter: F,
routing: Rc<ScopeRouter<Err>>,
routing: Rc<ScopeRouter<'a, Err>>,
}
impl<F, Err> Service<&'a mut WebRequest<'a, Err>> for ScopeService<F, Err>
impl<'a, F, Err> Service<&'a mut WebRequest<'a, Err>> for ScopeService<'a, F, Err>
where
F: Service<&'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, Error = Err::Container>,
F: Service<
&'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>,
Error = Infallible,
>,
Err: ErrorRenderer,
{
type Response = WebResponse;
type Error = Err::Container;
type Future = ScopeServiceResponse<F, Err>;
type Error = Infallible;
type Future = ScopeServiceResponse<'a, F, Err>;
#[inline]
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let ready1 = self.filter.poll_ready(cx)?.is_ready();
let ready2 = self.routing.poll_ready(cx)?.is_ready();
let ready1 = self.filter.poll_ready(cx).is_ready();
let ready2 = self.routing.poll_ready(cx).is_ready();
if ready1 && ready2 {
Poll::Ready(Ok(()))
} else {
@ -522,20 +569,24 @@ where
}
pin_project_lite::pin_project! {
pub struct ScopeServiceResponse<F: Service<&'a mut WebRequest<'a, Err>>, Err: ErrorRenderer> {
pub struct ScopeServiceResponse<'a, F: Service<&'a mut WebRequest<'a, Err>>, Err: ErrorRenderer> {
#[pin]
filter: F::Future,
routing: Rc<ScopeRouter<Err>>,
endpoint: Option<<ScopeRouter<Err> as Service<&'a mut WebRequest<'a, Err>>>::Future>,
routing: Rc<ScopeRouter<'a, Err>>,
endpoint: Option<<ScopeRouter<'a, Err> as Service<&'a mut WebRequest<'a, Err>>>::Future>,
}
}
impl<F, Err> Future for ScopeServiceResponse<F, Err>
impl<'a, F, Err> Future for ScopeServiceResponse<'a, F, Err>
where
F: Service<&'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, Error = Err::Container>,
F: Service<
&'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>,
Error = Infallible,
>,
Err: ErrorRenderer,
{
type Output = Result<WebResponse, Err::Container>;
type Output = Result<WebResponse, Infallible>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.as_mut().project();
@ -543,40 +594,44 @@ where
if let Some(fut) = this.endpoint.as_mut() {
Pin::new(fut).poll(cx)
} else {
let res = if let Poll::Ready(res) = this.filter.poll(cx) {
res?
} else {
return Poll::Pending;
};
*this.endpoint = Some(this.routing.call(res));
let req = ready!(this.filter.poll(cx)).unwrap();
*this.endpoint = Some(this.routing.call(req));
self.poll(cx)
}
}
}
struct ScopeRouterFactory<Err: ErrorRenderer> {
struct ScopeRouterFactory<'a, Err: ErrorRenderer> {
state: Option<Rc<Extensions>>,
services: Rc<Vec<(ResourceDef, HttpNewService<Err>, RefCell<Option<Guards>>)>>,
default: Rc<RefCell<Option<Rc<HttpNewService<Err>>>>>,
services: Rc<
Vec<(
ResourceDef,
BoxServiceFactory<'a, Err>,
RefCell<Option<Guards>>,
)>,
>,
// default: Rc<RefCell<Option<Rc<BoxServiceFactory<'a, Err>>>>>,
case_insensitive: bool,
}
impl<Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeRouterFactory<Err> {
impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>>
for ScopeRouterFactory<'a, Err>
{
type Response = WebResponse;
type Error = Err::Container;
type Error = Infallible;
type InitError = ();
type Service = ScopeRouter<Err>;
type Service = ScopeRouter<'a, Err>;
type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::InitError>>>>;
fn new_service(&self, _: ()) -> Self::Future {
let services = self.services.clone();
let case_insensitive = self.case_insensitive;
let state = self.state.clone();
let default_fut = self
.default
.borrow()
.as_ref()
.map(|srv| srv.new_service(()));
// let default_fut = self
// .default
// .borrow()
// .as_ref()
// .map(|srv| srv.new_service(()));
Box::pin(async move {
// create http services
@ -589,31 +644,31 @@ impl<Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeRo
router.rdef(path.clone(), service).2 = guards.borrow_mut().take();
}
let default = if let Some(fut) = default_fut {
Some(fut.await?)
} else {
None
};
// let default = if let Some(fut) = default_fut {
// Some(fut.await?)
// } else {
// None
// };
Ok(ScopeRouter {
state,
default,
// default,
router: router.finish(),
})
})
}
}
struct ScopeRouter<Err: ErrorRenderer> {
struct ScopeRouter<'a, Err: ErrorRenderer> {
state: Option<Rc<Extensions>>,
router: Router<HttpService<Err>, Vec<Box<dyn Guard>>>,
default: Option<HttpService<Err>>,
router: Router<BoxService<'a, Err>, Vec<Box<dyn Guard>>>,
// default: Option<BoxService<'a, Err>>,
}
impl<Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ScopeRouter<Err> {
impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ScopeRouter<'a, Err> {
type Response = WebResponse;
type Error = Err::Container;
type Future = Either<BoxResponse<Err>, Ready<Self::Response, Self::Error>>;
type Error = Infallible;
type Future = Pin<Box<dyn Future<Output = Result<WebResponse, Infallible>> + 'a>>;
#[inline]
fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
@ -621,7 +676,7 @@ impl<Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ScopeRouter<Er
}
fn call(&self, mut req: &'a mut WebRequest<'a, Err>) -> Self::Future {
let res = self.router.recognize_checked(&mut req, |req, guards| {
let res = self.router.recognize_checked(req, |req, guards| {
if let Some(guards) = guards {
for f in guards {
if !f.check(req.head()) {
@ -636,15 +691,10 @@ impl<Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ScopeRouter<Er
if let Some(ref state) = self.state {
req.set_state_container(state.clone());
}
Either::Left(srv.call(req))
} else if let Some(ref default) = self.default {
Either::Left(default.call(req))
srv.call(req)
} else {
let req = req.into_parts().0;
Either::Right(Ready::Ok(WebResponse::new(
Response::NotFound().finish(),
// req,
)))
//self.default.call(req)
todo!()
}
}
}

View file

@ -1,13 +1,15 @@
use std::rc::Rc;
use std::{convert::Infallible, marker::PhantomData, rc::Rc, task::Context, task::Poll};
use crate::router::{IntoPattern, ResourceDef};
use crate::service::{IntoServiceFactory, ServiceFactory};
use crate::util::Extensions;
use crate::service::{IntoServiceFactory, Service, ServiceFactory};
use crate::util::{Extensions, Ready};
use super::boxed::{self, BoxServiceFactory};
use super::types::state::StateFactory;
use super::{config::AppConfig, dev::insert_slash, rmap::ResourceMap};
use super::{error::Error, guard::Guard, ErrorRenderer, WebRequest, WebResponse};
use super::{
error::Error, guard::Guard, ErrorRenderer, HttpResponse, WebRequest, WebResponse,
};
pub trait WebService<'a, Err: ErrorRenderer>: 'static {
fn register(self, config: &mut WebServiceConfig<'a, Err>);
@ -43,16 +45,16 @@ type Guards = Vec<Box<dyn Guard>>;
/// Application service configuration
pub struct WebServiceConfig<'a, Err: ErrorRenderer> {
config: AppConfig,
pub(super) config: AppConfig,
root: bool,
default: Rc<BoxServiceFactory<'a, Err>>,
pub(super) default: Rc<BoxServiceFactory<'a, Err>>,
services: Vec<(
ResourceDef,
BoxServiceFactory<'a, Err>,
Option<Guards>,
Option<Rc<ResourceMap>>,
)>,
service_state: Rc<Vec<Box<dyn StateFactory>>>,
pub(super) service_state: Rc<Vec<Box<dyn StateFactory>>>,
}
impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> {
@ -90,7 +92,7 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> {
(self.config, self.services)
}
pub(crate) fn clone_config(&self) -> Self {
pub(super) fn clone_config(&'a self) -> WebServiceConfig<'a, Err> {
WebServiceConfig {
config: self.config.clone(),
default: self.default.clone(),
@ -267,6 +269,43 @@ where
// }
// }
#[derive(Copy, Clone)]
pub(super) struct DefaultService<Err>(PhantomData<Err>);
impl<Err> Default for DefaultService<Err> {
fn default() -> Self {
DefaultService(PhantomData)
}
}
impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>>
for DefaultService<Err>
{
type Response = WebResponse;
type Error = Infallible;
type InitError = ();
type Service = Self;
type Future = Ready<Self::Service, Self::InitError>;
fn new_service(&self, _: ()) -> Self::Future {
Ready::Ok(DefaultService(PhantomData))
}
}
impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for DefaultService<Err> {
type Response = WebResponse;
type Error = Infallible;
type Future = Ready<Self::Response, Self::Error>;
fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&self, _: &'a mut WebRequest<'a, Err>) -> Self::Future {
Ready::Ok(HttpResponse::NotFound().finish().into())
}
}
macro_rules! tuple_web_service({$(($n:tt, $T:ident)),+} => {
/// WebServiceFactory implementation for a tuple
#[allow(unused_parens)]

View file

@ -3,10 +3,10 @@ use std::{
task::Poll,
};
use crate::service::{dev::AndThenFactory, Service, ServiceFactory, Transform};
use crate::service::{dev::AndThenFactory, Identity, Service, ServiceFactory, Transform};
use crate::util::{ready, Ready};
use super::{Error, ErrorRenderer, WebRequest, WebResponse};
use super::{Error, ErrorRenderer, WebRequest, WebResponse, WebService, WebServiceConfig};
pub struct Stack<Inner, Outer> {
inner: Inner,
@ -233,6 +233,7 @@ where
> + 'static,
First::Service: 'static,
First::Future: 'static,
<First::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a,
Second: FiltersFactory<'a, Err>,
Second::Service: ServiceFactory<
&'a mut WebRequest<'a, Err>,
@ -242,6 +243,7 @@ where
>,
<Second::Service as ServiceFactory<&'a mut WebRequest<'a, Err>>>::Service: 'static,
<Second::Service as ServiceFactory<&'a mut WebRequest<'a, Err>>>::Future: 'static,
<<Second::Service as ServiceFactory<&'a mut WebRequest<'a, Err>>>::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a,
{
type Service = AndThenFactory<First, Second::Service>;
@ -260,3 +262,34 @@ pub trait FiltersFactory<'a, Err: ErrorRenderer> {
fn create(self) -> Self::Service;
}
impl<'a, Err: ErrorRenderer> ServicesFactory<'a, Err> for Identity {
fn register(self, _: &mut WebServiceConfig<'a, Err>) {}
}
pub struct Services<First, Second> {
first: First,
second: Second,
}
impl<First, Second> Services<First, Second> {
pub(super) fn new(first: First, second: Second) -> Self {
Services { first, second }
}
}
impl<'a, First, Second, Err> ServicesFactory<'a, Err> for Services<First, Second>
where
Err: ErrorRenderer,
First: WebService<'a, Err>,
Second: ServicesFactory<'a, Err>,
{
fn register(self, cfg: &mut WebServiceConfig<'a, Err>) {
self.second.register(cfg);
self.first.register(cfg);
}
}
pub trait ServicesFactory<'a, Err: ErrorRenderer> {
fn register(self, cfg: &mut WebServiceConfig<'a, Err>);
}