#[cfg(feature = "websocket")]
use crate::ws::{WebSocketReceiver, WebSocketSender};
use crate::{
context::{Context, HandlerMetadata, RouteId, State},
controller::{Controller, DynControllerHandler},
error::Error,
handler::DynHandler,
request::Request,
resolver::{Resolver, ResolverResult},
responder::{DynResponder, Responder},
Result,
};
use futures::future::BoxFuture;
use hyper::Method;
use std::{collections::HashMap, sync::Arc};
pub trait Route {
fn dispatch(
&'static self,
resolver_id: u64,
req: Request,
) -> Option<BoxFuture<'static, Box<dyn DynResponder + Send>>>;
fn add_handler(
&mut self,
handler_id: u64,
method: Method,
handler: Box<dyn DynHandler + Send + Sync>,
);
}
pub struct RouterBuilder<'a,T>
where
T: Route + Send + Sync + Unpin + 'static,
{
prefix: &'a str,
resolver: HashMap<String, Resolver>,
route: T,
}
impl<'a> Default for RouterBuilder<'a,ImplRoute> {
#[inline]
fn default() -> Self {
Self {
prefix: "",
resolver: Default::default(),
route: ImplRoute {
handlers: Default::default(),
},
}
}
}
macro_rules! method {
($($(#[$m:meta])* $v:vis fn $n:ident = $method:expr;)+) => {
$(
$(#[$m])* $v fn $n<H>(self,path: &str,handler: H) -> Self
where
H: 'static + DynHandler + Send + Sync,
{
self.add(path,$method,handler)
}
)+
};
}
impl<'a,T> RouterBuilder<'a,T>
where
T: 'static + Route + Send + Sync + Unpin,
{
#[inline]
fn add<H>(mut self, path: &str, method: Method, handler: H) -> Self
where
H: 'static + DynHandler + Send + Sync,
{
let path = &format!("{}/{}",self.prefix,path);
let handler_id = if let Some(resolver) = self.resolver.get_mut(path) {
let _ = resolver.add_method(method.clone());
resolver.id()
} else {
let resolver =
Resolver::new(path, method.clone()).expect("Unable to construct endpoint resolver");
let resolver_id = resolver.id();
self.resolver.insert(path.to_string(), resolver);
resolver_id
};
self.route
.add_handler(handler_id, method, Box::new(handler));
self
}
#[inline]
pub fn group(self, prefix: &str) -> RouterBuilder<ImplRoute> {
RouterBuilder {
prefix,
resolver: Default::default(),
route: ImplRoute {
handlers: Default::default(),
},
}
}
method![
#[inline]
pub fn get = Method::GET;
#[inline]
pub fn post = Method::POST;
#[inline]
pub fn options = Method::OPTIONS;
#[inline]
pub fn put = Method::PUT;
#[inline]
pub fn delete = Method::DELETE;
#[inline]
pub fn head = Method::HEAD;
#[inline]
pub fn trace = Method::TRACE;
#[inline]
pub fn connect = Method::CONNECT;
#[inline]
pub fn patch = Method::PATCH;
];
#[cfg(not(feature = "athene_body"))]
#[cfg(feature = "static_file")]
#[inline]
pub fn static_files(self, uri_path: &str, dir_path: impl Into<std::path::PathBuf>) -> Self {
let prefix = &format!("{}/{}",self.prefix,uri_path);
self.add(
uri_path,
Method::GET,
crate::static_file::StaticFile::new(prefix, dir_path),
)
}
#[cfg(feature = "websocket")]
#[inline]
pub fn ws<H, F>(self, path: &str, handler: H) -> Self
where
H: Send + Sync + 'static + Fn(Request, WebSocketSender, WebSocketReceiver) -> F,
F: std::future::Future<Output = Result<()>> + Send + 'static,
{
self.add(path, Method::GET, crate::ws::new_ws(handler))
}
#[inline]
pub fn controller<C>(mut self, controller: C) -> RouterBuilder<'a,RouterChain<C, T>>
where
C: Controller + Send + Sync + Unpin,
{
let mut handlers = HashMap::new();
for (name, method, sub_path, handler) in controller.method() {
let path = format!("{}{}", C::BASE_PATH, sub_path);
let meta = name.map(|name| HandlerMetadata {
route_id: Default::default(),
name: Some(name),
});
let handler_id = if let Some(resolver) = self.resolver.get_mut(&path) {
let _ = resolver.add_method_with_metadata(method.clone(), meta);
resolver.id()
} else {
let resolver = Resolver::new_with_metadata(&path, method.clone(), meta)
.expect("Unable to construct endpoint resolver");
let resolver_id = resolver.id();
self.resolver.insert(path, resolver);
resolver_id
};
handlers.insert((handler_id, method), handler);
}
RouterBuilder {
prefix: "",
resolver: self.resolver,
route: RouterChain {
controller,
handlers,
route: self.route,
},
}
}
#[inline]
pub(crate) fn build(self) -> Router {
let RouterBuilder {
resolver,
route: controllers,
..
} = self;
let mut resolvers = resolver.into_values().collect::<Vec<_>>();
resolvers.sort_unstable();
Router {
inner: Arc::new((resolvers, Box::new(controllers))),
}
}
}
#[doc(hidden)]
#[derive(Clone)]
pub struct Router {
inner: Arc<(Vec<Resolver>, Box<dyn Route + Send + Sync + Unpin>)>,
}
impl<'a> Router {
#[inline]
pub fn builder() -> RouterBuilder<'a,ImplRoute> {
RouterBuilder::default()
}
#[inline]
pub fn resolve(&self, req: &mut Request) -> Result<u64, u16> {
let mut method_not_allowed = false;
for resolver in &self.inner.0 {
match resolver.resolve(req) {
ResolverResult::InvalidPath => continue,
ResolverResult::MethodNotAllowed => method_not_allowed = true,
ResolverResult::Match(_) => return Ok(resolver.id()),
}
}
if method_not_allowed {
Err(405)
} else {
Err(404)
}
}
#[inline]
pub fn resolve_metadata(&self, req: &mut Request) -> HandlerMetadata {
let mut method_not_allowed = false;
for resolver in &self.inner.0 {
match resolver.resolve(req) {
ResolverResult::InvalidPath => continue,
ResolverResult::MethodNotAllowed => method_not_allowed = true,
ResolverResult::Match(meta) => return meta.clone(),
}
}
if method_not_allowed {
HandlerMetadata::not_allowed()
} else {
HandlerMetadata::not_found()
}
}
#[inline]
pub async fn dispatch(&self, mut ctx: Context) -> Result<Context, Error> {
let req = ctx
.state
.take_request()
.ok_or_else(|| Error::Other(String::from("Request moved before handler")))?;
let static_self = unsafe { std::mem::transmute::<&'_ Self, &'static Self>(self) };
let builder: crate::response::Builder = crate::response::Builder::new();
let route_id = match ctx.metadata.route_id {
RouteId::Id(id) => id,
RouteId::Error(e) => {
return e.response(builder, &ctx).build().map(|r| {
ctx.state = State::After(Box::new(r));
ctx
});
}
};
let res = if let Some(responder) = static_self.inner.1.dispatch(route_id, req) {
responder.await.response(builder, &ctx)
} else {
404.response(builder, &ctx)
}
.build();
res.map(|r| {
ctx.state = State::After(Box::new(r));
ctx
})
}
}
#[doc(hidden)]
pub struct ImplRoute {
handlers: HashMap<(u64, Method), Box<dyn DynHandler + Send + Sync>>,
}
impl Route for ImplRoute {
#[inline]
fn dispatch(
&'static self,
resolver_id: u64,
req: Request,
) -> Option<BoxFuture<'static, Box<dyn DynResponder + Send>>> {
if let Some(handler) = self.handlers.get(&(resolver_id, req.method().clone())) {
Some(handler.handle(req))
} else {
None
}
}
#[inline]
fn add_handler(
&mut self,
endpoint_id: u64,
method: Method,
handler: Box<dyn DynHandler + Send + Sync>,
) {
self.handlers.insert((endpoint_id, method), handler);
}
}
#[doc(hidden)]
pub struct RouterChain<C, T: Route> {
controller: C,
route: T,
handlers: HashMap<(u64, Method), Box<dyn DynControllerHandler<C> + Send + Sync>>,
}
impl<C: Sync + Send, Rest: Route + Sync + Send> Route for RouterChain<C, Rest> {
#[inline]
fn dispatch(
&'static self,
resolver_id: u64,
req: Request,
) -> Option<BoxFuture<'static, Box<dyn DynResponder + Send>>> {
if let Some(handler) = self.handlers.get(&(resolver_id, req.method().clone())) {
Some(handler.handle(&self.controller, req))
} else {
self.route.dispatch(resolver_id, req)
}
}
#[inline]
fn add_handler(
&mut self,
handler_id: u64,
method: Method,
handler: Box<dyn DynHandler + Send + Sync>,
) {
self.route.add_handler(handler_id, method, handler);
}
}