use http::*;
use utils::ToRegex;
use utils::RequestContinuation;
use regex::Regex;
use std::sync::RwLock;
pub trait Controller: Send + Sync {
fn handle(&self, req: &SyncRequest, res: &mut Response<Body>);
}
pub struct RequestGuardCollection {
guards: Vec<Box<RequestGuard>>
}
impl RequestGuardCollection {
pub fn new() -> Self {
RequestGuardCollection {
guards: Vec::new(),
}
}
pub fn add<G: 'static + RequestGuard>(&mut self, guard: G) {
self.guards.push(Box::new(guard));
}
}
impl<G: 'static + RequestGuard> From<G> for RequestGuardCollection {
fn from(guard: G) -> Self {
let mut reqg = RequestGuardCollection::new();
reqg.add(guard);
reqg
}
}
impl<'a, G: 'static + RequestGuard + Clone> From<&'a [G]> for RequestGuardCollection {
fn from(guards: &'a [G]) -> Self {
let mut reqg = RequestGuardCollection::new();
for guard in guards.to_vec() {
reqg.add(guard);
}
reqg
}
}
impl<G: 'static + RequestGuard> From<Vec<G>> for RequestGuardCollection {
fn from(guards: Vec<G>) -> Self {
let mut reqg = RequestGuardCollection::new();
for guard in guards {
reqg.add(guard);
}
reqg
}
}
use ::std::slice::Iter;
impl<'a> IntoIterator for &'a RequestGuardCollection {
type Item = &'a Box<RequestGuard>;
type IntoIter = Iter<'a, Box<RequestGuard>>;
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
self.guards.iter()
}
}
pub trait RequestGuard {
fn validate(&self, req: &SyncRequest, res: &mut Response<Body>) -> RequestContinuation;
}
type DelegateFunction<T> = Fn(&T, &SyncRequest, &mut Response<Body>);
type ControllerDelegate<T> = (Method, Regex, Option<RequestGuardCollection>, Box<DelegateFunction<T>>);
pub struct ControllerDispatch<T> {
delegate_context: T,
delegates: RwLock<Vec<ControllerDelegate<T>>>,
}
impl<T: Send + Sync> ControllerDispatch<T> {
pub fn new(delegate_context: T) -> Self {
ControllerDispatch {
delegate_context,
delegates: RwLock::new(Vec::new()),
}
}
pub fn add<F, R: ToRegex>(&self, method: Method, path: R, delegate_func: F)
where for<'r, 's, 't0> F: 'static + Fn(&'r T, &'s SyncRequest, &'t0 mut Response<Body>) {
self.delegates.write().unwrap().push((method, reg!(path), None, Box::new(delegate_func)));
}
pub fn add_with_guards<F, R: ToRegex>(&self, method: Method, path: R, guards: RequestGuardCollection, delegate_func: F)
where for<'r, 's, 't0> F: 'static + Fn(&'r T, &'s SyncRequest, &'t0 mut Response<Body>) {
self.delegates.write().unwrap().push((method, reg!(path), Some(guards), Box::new(delegate_func)));
}
pub fn dispatch(&self, req: &SyncRequest, res: &mut Response<Body>) {
use std::iter::FromIterator;
let delegates_list = self.delegates.read().unwrap();
let method = req.method().clone();
let retained_delegate = Vec::from_iter(delegates_list.iter().filter(move |x| {
x.0 == method
}));
if retained_delegate.len() == 0 {
res.set_status(StatusCode::MethodNotAllowed);
return;
}
for del in retained_delegate {
let (_, ref reg, ref op_guards, ref boxed_func) = del;
if reg.is_match(req.uri().path()) {
if let Some(ref guards) = op_guards {
for guard in guards {
if let RequestContinuation::None = guard.validate(req, res) {
return;
}
}
}
boxed_func(&self.delegate_context, req, res);
return;
}
}
res.set_status(StatusCode::BadRequest);
}
}
unsafe impl<T> Sync for ControllerDispatch<T> {}
unsafe impl<T> Send for ControllerDispatch<T> {}
pub struct BasicController<C> {
dispatch: ControllerDispatch<C>
}
impl<C: Send + Sync> Controller for BasicController<C> {
fn handle(&self, req: &SyncRequest, res: &mut Response<Body>) {
self.dispatch.dispatch(req, res);
}
}
impl<C: Send + Sync> BasicController<C> {
pub fn new(controller_context: C) -> Self {
BasicController {
dispatch: ControllerDispatch::new(controller_context),
}
}
pub fn add<F, R: ToRegex>(&self, method: Method, path: R, delegate_func: F)
where for<'r, 's, 't0> F: 'static + Fn(&'r C, &'s SyncRequest, &'t0 mut Response<Body>) {
self.dispatch.add(method, path, delegate_func);
}
pub fn add_with_guards<F, R: ToRegex>(&self, method: Method, path: R, guards: RequestGuardCollection, delegate_func: F)
where for<'r, 's, 't0> F: 'static + Fn(&'r C, &'s SyncRequest, &'t0 mut Response<Body>) {
self.dispatch.add_with_guards(method, path, guards, delegate_func);
}
}
pub struct BodyGuard;
impl RequestGuard for BodyGuard {
fn validate(&self, req: &SyncRequest, _res: &mut Response<Body>) -> RequestContinuation {
if req.body_ref().len() <= 0 {
return RequestContinuation::None
}
RequestContinuation::Next
}
}