use std::fmt::Debug;
use std::str::FromStr;
use std::sync::Arc;
use hyper::Uri;
use crate::endpoint::MiddlewareEndpoint;
use crate::{router::Router, Endpoint, Middleware};
#[allow(missing_debug_implementations)]
pub struct Route<'a> {
router: &'a mut Router,
path: String,
middleware: Vec<Arc<dyn Middleware>>,
prefix: bool,
}
impl<'a> Route<'a> {
pub(crate) fn new(router: &'a mut Router, path: String) -> Route<'a> {
Route {
router,
path,
middleware: Vec::new(),
prefix: false,
}
}
pub fn at<'b>(&'b mut self, path: &str) -> Route<'b> {
let mut p = self.path.clone();
if !p.ends_with('/') && !path.starts_with('/') {
p.push('/');
}
if path != "/" {
p.push_str(path);
}
Route {
router: self.router,
path: p,
middleware: self.middleware.clone(),
prefix: false,
}
}
#[must_use]
pub fn path(&self) -> &str {
&self.path
}
pub fn with(&mut self, middleware: impl Middleware + 'static) -> &mut Self
{
self.middleware.push(Arc::new(middleware));
self
}
pub fn reset_middleware(&mut self) -> &mut Self {
self.middleware.clear();
self
}
pub fn nest(&mut self, service: crate::Server) -> &mut Self {
let prefix = self.prefix;
self.prefix = true;
self.all(service);
self.prefix = prefix;
self
}
pub fn method(&mut self, method: hyper::Method, ep: impl Endpoint + 'static) -> &mut Self {
if self.prefix {
let ep = StripPrefixEndpoint::new(ep);
let wildcard = self.at("*");
wildcard.router.add(
&wildcard.path,
method,
MiddlewareEndpoint::wrap_with_middleware(ep, wildcard.middleware),
);
} else {
self.router.add(
&self.path,
method,
MiddlewareEndpoint::wrap_with_middleware(ep, self.middleware.clone()),
);
}
self
}
pub fn all(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
if self.prefix {
let ep = StripPrefixEndpoint::new(ep);
let wildcard = self.at("*");
wildcard.router.add_all(
&wildcard.path,
MiddlewareEndpoint::wrap_with_middleware(ep, wildcard.middleware),
);
} else {
self.router.add_all(
&self.path,
MiddlewareEndpoint::wrap_with_middleware(ep, self.middleware.clone()),
);
}
self
}
pub fn get(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::GET, ep);
self
}
pub fn head(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::HEAD, ep);
self
}
pub fn put(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::PUT, ep);
self
}
pub fn post(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::POST, ep);
self
}
pub fn delete(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::DELETE, ep);
self
}
pub fn options(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::OPTIONS, ep);
self
}
pub fn connect(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::CONNECT, ep);
self
}
pub fn patch(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::PATCH, ep);
self
}
pub fn trace(&mut self, ep: impl Endpoint + 'static) -> &mut Self {
self.method(hyper::Method::TRACE, ep);
self
}
}
#[derive(Debug)]
struct StripPrefixEndpoint(std::sync::Arc<dyn Endpoint>);
impl StripPrefixEndpoint {
fn new(ep: impl Endpoint + 'static) -> Self {
Self(std::sync::Arc::new(ep))
}
}
impl Clone for StripPrefixEndpoint {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
#[async_trait::async_trait]
impl Endpoint for StripPrefixEndpoint
{
async fn call(&self, ctx: &mut crate::Context) -> crate::Result {
let rest = ctx.params
.iter()
.rev()
.find_map(|captures| captures.wildcard())
.unwrap_or_default();
*ctx.req.uri_mut() = Uri::from_str(rest)
.map_err(|err| anyhow::anyhow!("InvalidUri: {:#?}", err))?;
self.0
.call(ctx)
.await
}
}