use async_std::io;
use async_std::sync::Arc;
use crate::cookies;
use crate::listener::{Listener, ToListener};
use crate::log;
use crate::middleware::{Middleware, Next};
use crate::router::{Router, Selection};
use crate::{Endpoint, Request, Route};
#[allow(missing_debug_implementations)]
pub struct Server<State> {
router: Arc<Router<State>>,
state: State,
middleware: Arc<Vec<Arc<dyn Middleware<State>>>>,
}
impl Server<()> {
#[must_use]
pub fn new() -> Self {
Self::with_state(())
}
}
impl Default for Server<()> {
fn default() -> Self {
Self::new()
}
}
impl<State: Clone + Send + Sync + 'static> Server<State> {
pub fn with_state(state: State) -> Self {
let mut server = Self {
router: Arc::new(Router::new()),
middleware: Arc::new(vec![]),
state,
};
server.with(cookies::CookiesMiddleware::new());
#[cfg(feature = "logger")]
server.with(log::LogMiddleware::new());
server
}
pub fn at<'a>(&'a mut self, path: &str) -> Route<'a, State> {
let router = Arc::get_mut(&mut self.router)
.expect("Registering routes is not possible after the Server has started");
Route::new(router, path.to_owned())
}
pub fn with<M>(&mut self, middleware: M) -> &mut Self
where
M: Middleware<State>,
{
log::trace!("Adding middleware {}", middleware.name());
let m = Arc::get_mut(&mut self.middleware)
.expect("Registering middleware is not possible after the Server has started");
m.push(Arc::new(middleware));
self
}
pub async fn listen<TL: ToListener<State>>(self, listener: TL) -> io::Result<()> {
listener.to_listener()?.listen(self).await
}
pub async fn respond<R>(&self, req: impl Into<http_types::Request>) -> http_types::Result<R>
where
R: From<http_types::Response>,
{
let req = req.into();
let Self {
router,
state,
middleware,
} = self.clone();
let method = req.method().to_owned();
let Selection { endpoint, params } = router.route(&req.url().path(), method);
let route_params = vec![params];
let req = Request::new(state, req, route_params);
let next = Next {
endpoint,
next_middleware: &middleware,
};
let res = next.run(req).await;
let res: http_types::Response = res.into();
Ok(res.into())
}
}
impl<State: Clone> Clone for Server<State> {
fn clone(&self) -> Self {
Self {
router: self.router.clone(),
state: self.state.clone(),
middleware: self.middleware.clone(),
}
}
}
#[async_trait::async_trait]
impl<State: Clone + Sync + Send + 'static, InnerState: Clone + Sync + Send + 'static>
Endpoint<State> for Server<InnerState>
{
async fn call(&self, req: Request<State>) -> crate::Result {
let Request {
req,
mut route_params,
..
} = req;
let path = req.url().path().to_owned();
let method = req.method().to_owned();
let router = self.router.clone();
let middleware = self.middleware.clone();
let state = self.state.clone();
let Selection { endpoint, params } = router.route(&path, method);
route_params.push(params);
let req = Request::new(state, req, route_params);
let next = Next {
endpoint,
next_middleware: &middleware,
};
Ok(next.run(req).await)
}
}
#[cfg(test)]
mod test {
use crate as tide;
#[test]
fn allow_nested_server_with_same_state() {
let inner = tide::new();
let mut outer = tide::new();
outer.at("/foo").get(inner);
}
#[test]
fn allow_nested_server_with_different_state() {
let inner = tide::with_state(1);
let mut outer = tide::new();
outer.at("/foo").get(inner);
}
}