use std::io;
use crate::context::basic_context::{generate_context, BasicContext};
use crate::core::context::Context;
use crate::core::errors::Error;
use crate::core::middleware::MiddlewareChain;
use crate::core::request::{Request, RequestWithParams};
use crate::core::route_parser::{MatchedRoute, RouteParser};
use std::future::Future;
enum Method {
DELETE,
GET,
OPTIONS,
POST,
PUT,
PATCH,
}
fn _add_method_to_route(method: &Method, path: &str) -> String {
let prefix = match method {
Method::DELETE => "__DELETE__",
Method::GET => "__GET__",
Method::OPTIONS => "__OPTIONS__",
Method::POST => "__POST__",
Method::PUT => "__PUT__",
Method::PATCH => "__PATCH__",
};
match &path[0..1] {
"/" => format!("{}{}", prefix, path),
_ => format!("{}/{}", prefix, path),
}
}
#[inline]
fn _add_method_to_route_from_str(method: &str, path: &str) -> String {
templatify!("__" ; method ; "__" ; path ; "")
}
pub struct App<R: RequestWithParams, T: 'static + Context + Send, S: Send> {
pub _route_parser: RouteParser<T>,
pub context_generator: fn(R, &S, &str) -> T,
pub state: S,
}
impl<R: RequestWithParams, T: Context + Send, S: Send> App<R, T, S> {
pub fn new_basic() -> App<Request, BasicContext, ()> {
App::create(generate_context, ())
}
pub fn create(generate_context: fn(R, &S, &str) -> T, state: S) -> App<R, T, S> {
App {
_route_parser: RouteParser::new(),
context_generator: generate_context,
state,
}
}
pub fn use_middleware(
&mut self,
path: &str,
middleware: MiddlewareChain<T>,
) -> &mut App<R, T, S> {
self._route_parser
.add_method_agnostic_middleware(path, middleware);
self
}
pub fn use_sub_app(&mut self, prefix: &str, app: App<R, T, S>) -> &mut App<R, T, S> {
self._route_parser
.route_tree
.add_route_tree(prefix, app._route_parser.route_tree);
self
}
pub fn get_route_parser(&self) -> &RouteParser<T> {
&self._route_parser
}
pub fn get(&mut self, path: &str, middlewares: MiddlewareChain<T>) -> &mut App<R, T, S> {
self._route_parser
.add_route(&_add_method_to_route(&Method::GET, path), middlewares);
self
}
pub fn options(
&mut self,
path: &str,
middlewares: MiddlewareChain<T>,
) -> &mut App<R, T, S> {
self._route_parser
.add_route(&_add_method_to_route(&Method::OPTIONS, path), middlewares);
self
}
pub fn post(&mut self, path: &str, middlewares: MiddlewareChain<T>) -> &mut App<R, T, S> {
self._route_parser
.add_route(&_add_method_to_route(&Method::POST, path), middlewares);
self
}
pub fn put(&mut self, path: &str, middlewares: MiddlewareChain<T>) -> &mut App<R, T, S> {
self._route_parser
.add_route(&_add_method_to_route(&Method::PUT, path), middlewares);
self
}
pub fn delete(
&mut self,
path: &str,
middlewares: MiddlewareChain<T>,
) -> &mut App<R, T, S> {
self._route_parser
.add_route(&_add_method_to_route(&Method::DELETE, path), middlewares);
self
}
pub fn patch(
&mut self,
path: &str,
middlewares: MiddlewareChain<T>,
) -> &mut App<R, T, S> {
self._route_parser
.add_route(&_add_method_to_route(&Method::PATCH, path), middlewares);
self
}
pub fn set404(&mut self, middlewares: MiddlewareChain<T>) -> &mut App<R, T, S> {
self._route_parser.add_route(
&_add_method_to_route(&Method::GET, "/*"),
middlewares.clone(),
);
self._route_parser.add_route(
&_add_method_to_route(&Method::POST, "/*"),
middlewares.clone(),
);
self._route_parser.add_route(
&_add_method_to_route(&Method::PUT, "/*"),
middlewares.clone(),
);
self._route_parser.add_route(
&_add_method_to_route(&Method::PATCH, "/*"),
middlewares.clone(),
);
self._route_parser
.add_route(&_add_method_to_route(&Method::DELETE, "/*"), middlewares);
self
}
pub fn resolve_from_method_and_path(&self, method: &str, path: &str) -> MatchedRoute<T> {
let path_with_method = _add_method_to_route_from_str(method, path);
self._route_parser.match_route(path_with_method)
}
#[cfg(feature = "hyper_server")]
pub fn resolve(
&self,
request: R,
matched_route: MatchedRoute<T>,
) -> impl Future<Output = Result<T::Response, io::Error>> + Send {
self._resolve(request, matched_route)
}
#[cfg(not(feature = "hyper_server"))]
pub fn resolve(
&self,
request: R,
matched_route: MatchedRoute<T>,
) -> impl Future<Output = Result<T::Response, io::Error>> + Send {
self._resolve(request, matched_route)
}
fn _resolve(
&self,
mut request: R,
matched_route: MatchedRoute<T>,
) -> impl Future<Output = Result<T::Response, io::Error>> + Send {
request.set_params(matched_route.params);
let context = (self.context_generator)(request, &self.state, matched_route.path);
let copy = matched_route.middleware.clone();
async move {
let ctx = copy.run(context).await;
let ctx = match ctx {
Ok(val) => val,
Err(e) => e.build_context(),
};
Ok(ctx.get_response())
}
}
}