mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 16:02:59 +01:00
allow to use custom state for scope
This commit is contained in:
parent
eefbe19651
commit
25b245ac72
101
src/scope.rs
101
src/scope.rs
@ -42,6 +42,7 @@ type ScopeResources<S> = Rc<Vec<(Resource, Rc<UnsafeCell<ResourceHandler<S>>>)>>
|
|||||||
/// * /app/path3 - `HEAD` requests
|
/// * /app/path3 - `HEAD` requests
|
||||||
///
|
///
|
||||||
pub struct Scope<S: 'static> {
|
pub struct Scope<S: 'static> {
|
||||||
|
handler: Option<UnsafeCell<Box<RouteHandler<S>>>>,
|
||||||
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
default: Rc<UnsafeCell<ResourceHandler<S>>>,
|
default: Rc<UnsafeCell<ResourceHandler<S>>>,
|
||||||
resources: ScopeResources<S>,
|
resources: ScopeResources<S>,
|
||||||
@ -56,12 +57,54 @@ impl<S: 'static> Default for Scope<S> {
|
|||||||
impl<S: 'static> Scope<S> {
|
impl<S: 'static> Scope<S> {
|
||||||
pub fn new() -> Scope<S> {
|
pub fn new() -> Scope<S> {
|
||||||
Scope {
|
Scope {
|
||||||
|
handler: None,
|
||||||
resources: Rc::new(Vec::new()),
|
resources: Rc::new(Vec::new()),
|
||||||
middlewares: Rc::new(Vec::new()),
|
middlewares: Rc::new(Vec::new()),
|
||||||
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create scope with new state.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// use actix_web::{http, App, HttpRequest, HttpResponse, Path};
|
||||||
|
///
|
||||||
|
/// struct AppState;
|
||||||
|
///
|
||||||
|
/// fn index(req: HttpRequest<AppState>) -> &'static str {
|
||||||
|
/// "Welcome!"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = App::new()
|
||||||
|
/// .scope("/app", |scope| {
|
||||||
|
/// scope.with_state(AppState, |scope| {
|
||||||
|
/// scope.resource("/test1", |r| r.f(index))
|
||||||
|
/// })
|
||||||
|
/// });
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn with_state<F, T: 'static>(mut self, state: T, f: F) -> Scope<S>
|
||||||
|
where
|
||||||
|
F: FnOnce(Scope<T>) -> Scope<T>,
|
||||||
|
{
|
||||||
|
let scope = Scope {
|
||||||
|
handler: None,
|
||||||
|
resources: Rc::new(Vec::new()),
|
||||||
|
middlewares: Rc::new(Vec::new()),
|
||||||
|
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
||||||
|
};
|
||||||
|
let scope = f(scope);
|
||||||
|
|
||||||
|
self.handler = Some(UnsafeCell::new(Box::new(Wrapper {
|
||||||
|
scope,
|
||||||
|
state: Rc::new(state),
|
||||||
|
})));
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Configure route for a specific path.
|
/// Configure route for a specific path.
|
||||||
///
|
///
|
||||||
/// This is a simplified version of the `Scope::resource()` method.
|
/// This is a simplified version of the `Scope::resource()` method.
|
||||||
@ -184,6 +227,7 @@ impl<S: 'static> RouteHandler<S> for Scope<S> {
|
|||||||
let path = unsafe { &*(&req.match_info()["tail"] as *const _) };
|
let path = unsafe { &*(&req.match_info()["tail"] as *const _) };
|
||||||
let path = if path == "" { "/" } else { path };
|
let path = if path == "" { "/" } else { path };
|
||||||
|
|
||||||
|
// recognize paths
|
||||||
for &(ref pattern, ref resource) in self.resources.iter() {
|
for &(ref pattern, ref resource) in self.resources.iter() {
|
||||||
if pattern.match_with_params(path, req.match_info_mut()) {
|
if pattern.match_with_params(path, req.match_info_mut()) {
|
||||||
let default = unsafe { &mut *self.default.as_ref().get() };
|
let default = unsafe { &mut *self.default.as_ref().get() };
|
||||||
@ -202,20 +246,39 @@ impl<S: 'static> RouteHandler<S> for Scope<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let default = unsafe { &mut *self.default.as_ref().get() };
|
// nested scope
|
||||||
if self.middlewares.is_empty() {
|
if let Some(ref handler) = self.handler {
|
||||||
default.handle(req, None)
|
let hnd: &mut RouteHandler<_> = unsafe { (&mut *(handler.get())).as_mut() };
|
||||||
|
hnd.handle(req)
|
||||||
} else {
|
} else {
|
||||||
Reply::async(Compose::new(
|
// default handler
|
||||||
req,
|
let default = unsafe { &mut *self.default.as_ref().get() };
|
||||||
Rc::clone(&self.middlewares),
|
if self.middlewares.is_empty() {
|
||||||
Rc::clone(&self.default),
|
default.handle(req, None)
|
||||||
None,
|
} else {
|
||||||
))
|
Reply::async(Compose::new(
|
||||||
|
req,
|
||||||
|
Rc::clone(&self.middlewares),
|
||||||
|
Rc::clone(&self.default),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Wrapper<S: 'static> {
|
||||||
|
state: Rc<S>,
|
||||||
|
scope: Scope<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static, S2: 'static> RouteHandler<S2> for Wrapper<S> {
|
||||||
|
fn handle(&mut self, req: HttpRequest<S2>) -> Reply {
|
||||||
|
self.scope
|
||||||
|
.handle(req.change_state(Rc::clone(&self.state)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Compose resource level middlewares with route handler.
|
/// Compose resource level middlewares with route handler.
|
||||||
struct Compose<S: 'static> {
|
struct Compose<S: 'static> {
|
||||||
info: ComposeInfo<S>,
|
info: ComposeInfo<S>,
|
||||||
@ -574,6 +637,26 @@ mod tests {
|
|||||||
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scope_with_state() {
|
||||||
|
struct State;
|
||||||
|
|
||||||
|
let mut app = App::new()
|
||||||
|
.scope("/app", |scope| {
|
||||||
|
scope.with_state(State, |scope| {
|
||||||
|
scope.resource("/path1", |r| r.f(|_| HttpResponse::Created()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/path1").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(
|
||||||
|
resp.as_response().unwrap().status(),
|
||||||
|
StatusCode::CREATED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_resource() {
|
fn test_default_resource() {
|
||||||
let mut app = App::new()
|
let mut app = App::new()
|
||||||
|
Loading…
Reference in New Issue
Block a user