1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-08-31 00:50:20 +02:00

refactor router

This commit is contained in:
Nikolay Kim
2018-07-15 15:12:21 +06:00
parent cf976d296f
commit da915972c0
11 changed files with 635 additions and 655 deletions

View File

@@ -6,7 +6,7 @@ use futures::{Async, Future, Poll};
use error::Error;
use handler::{AsyncResult, AsyncResultItem, FromRequest, Responder, RouteHandler};
use http::{Method, StatusCode};
use http::Method;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::{
@@ -14,15 +14,10 @@ use middleware::{
Started as MiddlewareStarted,
};
use pred::Predicate;
use resource::{Resource, RouteId};
use router::ResourceDef;
use resource::{DefaultResource, Resource};
use router::{ResourceDef, Router};
use server::Request;
type ScopeResource<S> = Rc<Resource<S>>;
type Route<S> = Box<RouteHandler<S>>;
type ScopeResources<S> = Rc<Vec<(ResourceDef, ScopeResource<S>)>>;
type NestedInfo<S> = (ResourceDef, Route<S>, Vec<Box<Predicate<S>>>);
/// Resources scope
///
/// Scope is a set of resources with common root path.
@@ -53,29 +48,31 @@ type NestedInfo<S> = (ResourceDef, Route<S>, Vec<Box<Predicate<S>>>);
/// * /{project_id}/path2 - `GET` requests
/// * /{project_id}/path3 - `HEAD` requests
///
#[derive(Default)]
pub struct Scope<S: 'static> {
pub struct Scope<S> {
rdef: ResourceDef,
router: Rc<Router<S>>,
filters: Vec<Box<Predicate<S>>>,
nested: Vec<NestedInfo<S>>,
middlewares: Rc<Vec<Box<Middleware<S>>>>,
default: Option<ScopeResource<S>>,
resources: ScopeResources<S>,
}
#[cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
impl<S: 'static> Scope<S> {
/// Create a new scope
// TODO: Why is this not exactly the default impl?
pub fn new() -> Scope<S> {
pub fn new(path: &str) -> Scope<S> {
Scope {
rdef: ResourceDef::prefix(path),
router: Rc::new(Router::new()),
filters: Vec::new(),
nested: Vec::new(),
resources: Rc::new(Vec::new()),
middlewares: Rc::new(Vec::new()),
default: None,
}
}
#[inline]
pub(crate) fn rdef(&self) -> &ResourceDef {
&self.rdef
}
#[inline]
pub(crate) fn take_filters(&mut self) -> Vec<Box<Predicate<S>>> {
mem::replace(&mut self.filters, Vec::new())
@@ -132,11 +129,10 @@ impl<S: 'static> Scope<S> {
F: FnOnce(Scope<T>) -> Scope<T>,
{
let scope = Scope {
rdef: ResourceDef::prefix(path),
filters: Vec::new(),
nested: Vec::new(),
resources: Rc::new(Vec::new()),
router: Rc::new(Router::new()),
middlewares: Rc::new(Vec::new()),
default: None,
};
let mut scope = f(scope);
@@ -146,8 +142,12 @@ impl<S: 'static> Scope<S> {
filters: scope.take_filters(),
})];
let handler = Box::new(Wrapper { scope, state });
self.nested
.push((ResourceDef::prefix("", &path), handler, filters));
Rc::get_mut(&mut self.router).unwrap().register_handler(
path,
handler,
Some(filters),
);
self
}
@@ -175,17 +175,14 @@ impl<S: 'static> Scope<S> {
F: FnOnce(Scope<S>) -> Scope<S>,
{
let scope = Scope {
rdef: ResourceDef::prefix(&path),
filters: Vec::new(),
nested: Vec::new(),
resources: Rc::new(Vec::new()),
router: Rc::new(Router::new()),
middlewares: Rc::new(Vec::new()),
default: None,
};
let mut scope = f(scope);
let filters = scope.take_filters();
self.nested
.push((ResourceDef::prefix("", &path), Box::new(scope), filters));
Rc::get_mut(&mut self.router)
.unwrap()
.register_scope(f(scope));
self
}
@@ -223,39 +220,9 @@ impl<S: 'static> Scope<S> {
R: Responder + 'static,
T: FromRequest<S> + 'static,
{
// check if we have resource handler
let mut found = false;
for &(ref pattern, _) in self.resources.iter() {
if pattern.pattern() == path {
found = true;
break;
}
}
if found {
let resources = Rc::get_mut(&mut self.resources)
.expect("Multiple scope references are not allowed");
for &mut (ref pattern, ref mut resource) in resources.iter_mut() {
if pattern.pattern() == path {
let res = Rc::get_mut(resource)
.expect("Multiple scope references are not allowed");
res.method(method).with(f);
break;
}
}
} else {
let mut handler = Resource::default();
handler.method(method).with(f);
let pattern = ResourceDef::with_prefix(
handler.get_name(),
path,
if path.is_empty() { "" } else { "/" },
false,
);
Rc::get_mut(&mut self.resources)
.expect("Can not use after configuration")
.push((pattern, Rc::new(handler)));
}
Rc::get_mut(&mut self.router)
.unwrap()
.register_route(path, method, f);
self
}
@@ -286,20 +253,18 @@ impl<S: 'static> Scope<S> {
where
F: FnOnce(&mut Resource<S>) -> R + 'static,
{
// add resource handler
let mut handler = Resource::default();
f(&mut handler);
// add resource
let pattern = ResourceDef::with_prefix(
handler.get_name(),
path,
if path.is_empty() { "" } else { "/" },
false,
);
Rc::get_mut(&mut self.resources)
.expect("Can not use after configuration")
.push((pattern, Rc::new(handler)));
let mut resource = Resource::new(pattern);
f(&mut resource);
Rc::get_mut(&mut self.router)
.unwrap()
.register_resource(resource);
self
}
@@ -308,14 +273,14 @@ impl<S: 'static> Scope<S> {
where
F: FnOnce(&mut Resource<S>) -> R + 'static,
{
if self.default.is_none() {
self.default = Some(Rc::new(Resource::default_not_found()));
}
{
let default = Rc::get_mut(self.default.as_mut().unwrap())
.expect("Multiple copies of default handler");
f(default);
}
// create and configure default resource
let mut resource = Resource::new(ResourceDef::new(""));
f(&mut resource);
Rc::get_mut(&mut self.router)
.expect("Multiple copies of scope router")
.register_default_resource(resource.into());
self
}
@@ -339,64 +304,33 @@ impl<S: 'static> RouteHandler<S> for Scope<S> {
let tail = req.match_info().tail as usize;
// recognize resources
for &(ref pattern, ref resource) in self.resources.iter() {
if let Some(params) = pattern.match_with_params(req, tail, false) {
let req2 = req.with_route_info(req.route().merge(&params));
if let Some(id) = resource.get_route_id(&req2) {
if self.middlewares.is_empty() {
return resource.handle(id, &req2);
} else {
return AsyncResult::async(Box::new(Compose::new(
id,
req2,
Rc::clone(&self.middlewares),
Rc::clone(&resource),
)));
}
}
}
let info = self.router.match_with_params(req, req.state(), tail, false);
let req2 = req.with_route_info(info);
if self.middlewares.is_empty() {
self.router.handle(&req2)
} else {
AsyncResult::async(Box::new(Compose::new(
req2,
Rc::clone(&self.router),
Rc::clone(&self.middlewares),
)))
}
// nested scopes
'outer: for &(ref prefix, ref handler, ref filters) in &self.nested {
if let Some(params) = prefix.match_prefix_with_params(req, tail) {
let req2 = req.with_route_info(req.route().merge(&params));
let state = req.state();
for filter in filters {
if !filter.check(&req2, state) {
continue 'outer;
}
}
return handler.handle(&req2);
}
}
// default handler
if let Some(ref resource) = self.default {
if let Some(id) = resource.get_route_id(req) {
if self.middlewares.is_empty() {
return resource.handle(id, req);
} else {
return AsyncResult::async(Box::new(Compose::new(
id,
req.clone(),
Rc::clone(&self.middlewares),
Rc::clone(resource),
)));
}
}
}
AsyncResult::ok(HttpResponse::new(StatusCode::NOT_FOUND))
}
fn has_default_resource(&self) -> bool {
self.default.is_some()
self.router.has_default_resource()
}
fn default_resource(&mut self, default: ScopeResource<S>) {
self.default = Some(default);
fn default_resource(&mut self, default: DefaultResource<S>) {
Rc::get_mut(&mut self.router)
.expect("Can not use after configuration")
.register_default_resource(default);
}
fn finish(&mut self) {
Rc::get_mut(&mut self.router)
.expect("Can not use after configuration")
.finish();
}
}
@@ -436,10 +370,9 @@ struct Compose<S: 'static> {
struct ComposeInfo<S: 'static> {
count: usize,
id: RouteId,
req: HttpRequest<S>,
router: Rc<Router<S>>,
mws: Rc<Vec<Box<Middleware<S>>>>,
resource: Rc<Resource<S>>,
}
enum ComposeState<S: 'static> {
@@ -464,14 +397,12 @@ impl<S: 'static> ComposeState<S> {
impl<S: 'static> Compose<S> {
fn new(
id: RouteId, req: HttpRequest<S>, mws: Rc<Vec<Box<Middleware<S>>>>,
resource: Rc<Resource<S>>,
req: HttpRequest<S>, router: Rc<Router<S>>, mws: Rc<Vec<Box<Middleware<S>>>>,
) -> Self {
let mut info = ComposeInfo {
id,
mws,
req,
resource,
router,
count: 0,
};
let state = StartMiddlewares::init(&mut info);
@@ -513,7 +444,7 @@ impl<S: 'static> StartMiddlewares<S> {
loop {
if info.count == len {
let reply = info.resource.handle(info.id, &info.req);
let reply = info.router.handle(&info.req);
return WaitingResponse::init(info, reply);
} else {
let result = info.mws[info.count].start(&info.req);
@@ -552,7 +483,7 @@ impl<S: 'static> StartMiddlewares<S> {
}
loop {
if info.count == len {
let reply = { info.resource.handle(info.id, &info.req) };
let reply = info.router.handle(&info.req);
return Some(WaitingResponse::init(info, reply));
} else {
let result = info.mws[info.count].start(&info.req);
@@ -979,9 +910,9 @@ mod tests {
})
.finish();
let req = TestRequest::with_uri("/app/t1").request();
let resp = app.run(req);
assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
//let req = TestRequest::with_uri("/app/t1").request();
//let resp = app.run(req);
//assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
let req = TestRequest::with_uri("/app/t1/").request();
let resp = app.run(req);