use std::fmt;
use hyper;
use futures::{future, Future, IntoFuture};
use error::Error;
use request::{params, Params, Request};
use response::Response;
use server::{Server, Listening};
use prefix_tree;
pub type HandlerResult = Box<Future<Item = hyper::Response, Error = hyper::Error>>;
pub type BoxHandler = Box<Fn(hyper::Request, usize) -> HandlerResult + Sync + Send>;
pub type Routes = prefix_tree::Tree<Endpoint>;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Method {
Head,
Get,
Post,
Patch,
Delete,
Put,
Options,
}
impl fmt::Display for Method {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use self::Method::*;
write!(fmt, "{}", match *self {
Head => "HEAD",
Get => "GET",
Post => "POST",
Delete => "DELETE",
Put => "PUT",
Patch => "PATCH",
Options => "OPTIONS",
})
}
}
impl<'a> From<&'a hyper::Method> for Method {
fn from(method: &'a hyper::Method) -> Self {
use self::Method::*;
match *method {
hyper::Method::Head => Head,
hyper::Method::Get => Get,
hyper::Method::Post => Post,
hyper::Method::Delete => Delete,
hyper::Method::Put => Put,
hyper::Method::Patch => Patch,
hyper::Method::Options => Options,
_ => Get,
}
}
}
const MAX_NUMBER_OF_ENDPOINTS: usize = 6;
pub enum EndpointHandler {
None,
Some {
method: Method,
params: (usize, String),
handler: BoxHandler,
}
}
impl fmt::Debug for EndpointHandler {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
EndpointHandler::None => write!(fmt, "none"),
EndpointHandler::Some { ref method, .. } => write!(fmt, "{} handler", method),
}
}
}
#[derive(Debug)]
pub struct Endpoint {
pub handlers: [EndpointHandler; MAX_NUMBER_OF_ENDPOINTS],
}
impl fmt::Display for Endpoint {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
for i in 0..MAX_NUMBER_OF_ENDPOINTS {
match self.handlers[i] {
EndpointHandler::None if i == 0 => {
return writeln!(fmt, " ?empty handler?");
},
EndpointHandler::None => {
return Ok(());
},
EndpointHandler::Some { ref method, ref params, .. } => {
writeln!(fmt, " {} {}", method, if params.0 == 0 { "/" } else { ¶ms.1 })?;
}
}
}
Ok(())
}
}
impl Endpoint {
pub fn new() -> Self {
use self::EndpointHandler::None;
Endpoint {
handlers: [None, None, None, None, None, None],
}
}
pub fn add(&mut self, method: Method, params: (usize, String), handler: BoxHandler) -> bool {
for i in 0..MAX_NUMBER_OF_ENDPOINTS {
match self.handlers[i] {
EndpointHandler::Some { .. } => continue,
EndpointHandler::None => {},
}
self.handlers[i] = EndpointHandler::Some {
method,
params,
handler,
};
return true;
}
false
}
pub fn handle(&self, m: Method, req: hyper::Request, prefix: usize) -> HandlerResult {
let expected = {
let path = &req.path()[prefix..];
if path.is_empty() {
0
} else {
path.split('/').count()
}
};
let mut method_found = false;
for i in 0..MAX_NUMBER_OF_ENDPOINTS {
match self.handlers[i] {
EndpointHandler::None => break,
EndpointHandler::Some { ref method, ref params, ref handler } => {
if method != &m {
continue;
}
method_found = true;
if params.0 != expected {
continue;
}
return handler(req, prefix);
},
}
}
if method_found {
Box::new(future::ok(Error::not_found("Unable to find a handler.").into()))
} else {
Box::new(future::ok(Error::method_not_allowed(
format!("Method {} is not allowed.", m),
format!("Allowed methods: {}", self.allowed_methods())
).into()))
}
}
fn allowed_methods(&self) -> String {
let mut string = self.handlers.iter()
.filter_map(|h| match *h {
EndpointHandler::None => None,
EndpointHandler::Some { ref method, .. } => Some(format!("{}", method)),
})
.fold(String::new(), |acc, s| acc + &s + ",");
string.pop();
string
}
}
#[derive(Default, Debug)]
pub struct Router {
routes: Routes,
}
impl Router {
pub fn new() -> Self {
Router::default()
}
pub fn routes(&self) -> String {
let mut s = String::new();
let mut it = self.routes.iter();
while let Some((prefix, route)) = it.next() {
let prefix = ::std::str::from_utf8(&prefix).expect("Storing only strings in tree; qed");
s.push_str(&format!("{}\n{}\n", prefix, route));
}
s
}
pub fn add(&mut self, prefix: &str, router: Router) {
self.routes.merge(prefix, router.routes);
}
pub fn bind<T: ::std::net::ToSocketAddrs>(self, address: T) -> Result<Listening, hyper::Error> {
let server = Server::new(self.routes);
server.bind(address)
}
pub fn on<'a, F, I, R, E, D, P>(&mut self, method: Method, params: D, fun: F) where
F: Fn(Request<P::Params>) -> I + Sync + Send + 'static,
I: IntoFuture<Item = R, Error = E>,
R: Into<Response>,
E: Into<Error>,
D: Into<Params<'a, P>>,
P: params::Parser,
I::Future: 'static,
{
let params = params.into();
let parser = params.parser;
let mut endpoint = self.routes.remove(params.prefix).unwrap_or_else(Endpoint::new);
let added = endpoint.add(method, parser.expected_params(), Box::new(move |request, prefix_len| {
let params = match parser.parse(request.uri(), prefix_len) {
Ok(params) => params,
Err(err) => return Box::new(future::ok(Error::from(err).into())),
};
let req = Request::new(request, params);
Box::new(fun(req).into_future().then(|result| {
future::ok(match result {
Ok(res) => res.into(),
Err(err) => err.into().into(),
}.into())
}))
}));
assert!(added, "The server does not support more than {} handlers for single prefix.", MAX_NUMBER_OF_ENDPOINTS);
self.routes.insert(params.prefix, endpoint);
}
pub fn get<'a, F, I, R, E, D, P>(&mut self, prefix: D, fun: F) where
F: Fn(Request<P::Params>) -> I + Sync + Send + 'static,
I: IntoFuture<Item = R, Error = E>,
R: Into<Response>,
E: Into<Error>,
D: Into<Params<'a, P>>,
P: params::Parser,
I::Future: 'static,
{
self.on(Method::Get, prefix, fun)
}
pub fn post<'a, F, I, R, E, D, P>(&mut self, prefix: D, fun: F) where
F: Fn(Request<P::Params>) -> I + Sync + Send + 'static,
I: IntoFuture<Item = R, Error = E>,
R: Into<Response>,
E: Into<Error>,
D: Into<Params<'a, P>>,
P: params::Parser,
I::Future: 'static,
{
self.on(Method::Post, prefix, fun)
}
pub fn put<'a, F, I, R, E, D, P>(&mut self, prefix: D, fun: F) where
F: Fn(Request<P::Params>) -> I + Sync + Send + 'static,
I: IntoFuture<Item = R, Error = E>,
R: Into<Response>,
E: Into<Error>,
D: Into<Params<'a, P>>,
P: params::Parser,
I::Future: 'static,
{
self.on(Method::Put, prefix, fun)
}
pub fn patch<'a, F, I, R, E, D, P>(&mut self, prefix: D, fun: F) where
F: Fn(Request<P::Params>) -> I + Sync + Send + 'static,
I: IntoFuture<Item = R, Error = E>,
R: Into<Response>,
E: Into<Error>,
D: Into<Params<'a, P>>,
P: params::Parser,
I::Future: 'static,
{
self.on(Method::Patch, prefix, fun)
}
pub fn delete<'a, F, I, R, E, D, P>(&mut self, prefix: D, fun: F) where
F: Fn(Request<P::Params>) -> I + Sync + Send + 'static,
I: IntoFuture<Item = R, Error = E>,
R: Into<Response>,
E: Into<Error>,
D: Into<Params<'a, P>>,
P: params::Parser,
I::Future: 'static,
{
self.on(Method::Delete, prefix, fun)
}
}