use crate::{RequestWithParams, ReusableBoxFuture};
use futures::FutureExt;
use std::io;
use crate::core::context::Context;
use crate::core::request::Request;
use crate::parser::{middleware_traits::MiddlewareTuple, tree::Node, tree::NodeOutput};
use crate::{
context::basic_context::{generate_context, BasicContext},
core::request::ThrusterRequest,
};
pub trait Middleware<CIn: Send, COut: Send, CErr: Send>:
FnOnce(CIn) -> ReusableBoxFuture<Result<COut, CErr>> + Send
{
fn val(&self) -> Self
where
Self: Sized + Copy,
{
panic!("Never use this.")
}
}
pub type ReturnValue<T> = T;
pub struct App<R: ThrusterRequest, T: 'static + Context + Clone + Send + Sync, S: Send> {
pub delete_root: Node<ReturnValue<T>>,
pub get_root: Node<ReturnValue<T>>,
pub options_root: Node<ReturnValue<T>>,
pub post_root: Node<ReturnValue<T>>,
pub put_root: Node<ReturnValue<T>>,
pub patch_root: Node<ReturnValue<T>>,
pub context_generator: fn(R, &S, &str) -> T,
pub state: std::sync::Arc<S>,
pub connection_timeout: u64,
}
impl<R: 'static + ThrusterRequest, T: Context + Clone + Send + Sync, S: 'static + 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) -> Self {
App {
delete_root: Node::default(),
get_root: Node::default(),
options_root: Node::default(),
post_root: Node::default(),
put_root: Node::default(),
patch_root: Node::default(),
context_generator: generate_context,
state: std::sync::Arc::new(state),
connection_timeout: 3600000,
}
}
pub fn middleware(mut self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self
where
T: Clone,
{
self.get_root
.add_non_leaf_value_at_path(path, middlewares.clone());
self.options_root
.add_non_leaf_value_at_path(path, middlewares.clone());
self.post_root
.add_non_leaf_value_at_path(path, middlewares.clone());
self.put_root
.add_non_leaf_value_at_path(path, middlewares.clone());
self.delete_root
.add_non_leaf_value_at_path(path, middlewares.clone());
self.patch_root
.add_non_leaf_value_at_path(path, middlewares);
self
}
#[deprecated(
note = "`use_middleware` is deprecated. Please migrate to use `middleware` in the future."
)]
pub fn use_middleware(self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self
where
T: Clone,
{
self.middleware(path, middlewares)
}
pub fn router(mut self, prefix: &str, app: App<R, T, S>) -> Self {
self.get_root.add_node_at_path(prefix, app.get_root);
self.options_root.add_node_at_path(prefix, app.options_root);
self.post_root.add_node_at_path(prefix, app.post_root);
self.put_root.add_node_at_path(prefix, app.put_root);
self.delete_root.add_node_at_path(prefix, app.delete_root);
self.patch_root.add_node_at_path(prefix, app.patch_root);
self
}
#[deprecated(
note = "`use_sub_app` is deprecated. Please migrate to use `router` in the future."
)]
pub fn use_sub_app(self, prefix: &str, app: App<R, T, S>) -> Self {
self.router(prefix, app)
}
pub fn get(mut self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self {
self.get_root.add_value_at_path(path, middlewares);
self
}
pub fn options(mut self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self {
self.options_root.add_value_at_path(path, middlewares);
self
}
pub fn post(mut self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self {
self.post_root.add_value_at_path(path, middlewares);
self
}
pub fn put(mut self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self {
self.put_root.add_value_at_path(path, middlewares);
self
}
pub fn delete(mut self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self {
self.delete_root.add_value_at_path(path, middlewares);
self
}
pub fn patch(mut self, path: &str, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self {
self.patch_root.add_value_at_path(path, middlewares);
self
}
pub fn set404(mut self, middlewares: MiddlewareTuple<ReturnValue<T>>) -> Self
where
T: Clone,
{
self.get_root.add_value_at_path("/*", middlewares.clone());
self.options_root
.add_value_at_path("/*", middlewares.clone());
self.post_root.add_value_at_path("/*", middlewares.clone());
self.put_root.add_value_at_path("/*", middlewares.clone());
self.delete_root
.add_value_at_path("/*", middlewares.clone());
self.patch_root.add_value_at_path("/*", middlewares);
self
}
pub fn set_strict_mode(mut self, strict_mode: bool) -> Self
where
T: Clone,
{
self.get_root.strict_mode = strict_mode;
self.options_root.strict_mode = strict_mode;
self.post_root.strict_mode = strict_mode;
self.put_root.strict_mode = strict_mode;
self.delete_root.strict_mode = strict_mode;
self.patch_root.strict_mode = strict_mode;
self
}
pub fn commit(mut self) -> Self {
self.get_root = self.get_root.commit();
self.options_root = self.options_root.commit();
self.post_root = self.post_root.commit();
self.put_root = self.put_root.commit();
self.delete_root = self.delete_root.commit();
self.patch_root = self.patch_root.commit();
self
}
pub fn resolve_from_method_and_path<'m>(
&'m self,
method: &str,
path: String,
) -> NodeOutput<'m, ReturnValue<T>> {
match method {
"OPTIONS" => self.options_root.get_value_at_path(path),
"POST" => self.post_root.get_value_at_path(path),
"PUT" => self.put_root.get_value_at_path(path),
"DELETE" => self.delete_root.get_value_at_path(path),
"PATCH" => self.patch_root.get_value_at_path(path),
_ => self.get_root.get_value_at_path(path),
}
}
pub fn match_and_resolve<'m>(
&'m self,
mut request: R,
) -> ReusableBoxFuture<Result<T::Response, io::Error>>
where
R: RequestWithParams,
{
let method = request.method();
let path = request.path();
let node = match method {
"OPTIONS" => self.options_root.get_value_at_path(path),
"POST" => self.post_root.get_value_at_path(path),
"PUT" => self.put_root.get_value_at_path(path),
"DELETE" => self.delete_root.get_value_at_path(path),
"PATCH" => self.patch_root.get_value_at_path(path),
_ => self.get_root.get_value_at_path(path),
};
request.set_params(node.params);
let context = (self.context_generator)(request, &self.state, &node.path);
ReusableBoxFuture::new((node.value)(context).map(|ctx| {
let ctx = match ctx {
Ok(val) => val,
Err(mut e) => {
e.context.set_body(e.message.into_bytes());
e.context
}
};
Ok(ctx.get_response())
}))
}
pub async fn resolve<'m>(
&self,
request: R,
matched_route: NodeOutput<'m, T>,
) -> Result<T::Response, io::Error> {
self._resolve(request, matched_route).await
}
async fn _resolve<'m>(
&self,
request: R,
matched_route: NodeOutput<'m, T>,
) -> Result<T::Response, io::Error> {
let context = (self.context_generator)(request, &self.state, &matched_route.path);
let copy = matched_route.value;
let ctx = (copy)(context).await;
let ctx = match ctx {
Ok(val) => val,
Err(mut e) => {
e.context.set_body(e.message.into_bytes());
e.context
}
};
Ok(ctx.get_response())
}
}