use crate::{
endpoint::{Handler, HandlerOutput},
listener::{Listener, ToListener},
middleware::{Middleware, MiddlewareArc, Next},
request::Request,
router::{Route, Router, Selection},
};
use async_std::{
io,
sync::{Arc, RwLock},
};
use async_trait::async_trait;
pub mod state;
use state::State;
#[derive(Clone)]
pub struct Server<S: State> {
pub(crate) state: S,
pub(crate) router: Arc<RwLock<Router<S>>>,
pub(crate) middleware: MiddlewareArc<S, Request<S>, HandlerOutput>,
}
impl<S: State + Default> Default for Server<S> {
fn default() -> Self {
Self::with_state(S::default())
}
}
impl Server<()> {
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
impl<S: State> Server<S> {
pub fn with_state(state: S) -> Self {
Self {
state,
router: Arc::new(RwLock::new(Router::new())),
middleware: Arc::new(RwLock::new(vec![])),
}
}
pub fn at(&mut self, path: &str) -> Route<S> {
Route::new(Arc::downgrade(&self.router), path)
}
pub async fn with<M>(&mut self, middleware: M) -> &mut Self
where
M: Middleware<S, Request<S>, HandlerOutput>,
{
log::trace!("Adding middleware {}", middleware.name());
Arc::clone(&self.middleware)
.write()
.await
.push(Arc::new(middleware));
self
}
pub async fn listen<L: ToListener<S>>(self, listener: L) -> io::Result<()> {
let mut listener = listener.to_listener()?;
listener.bind(self).await?;
for info in &listener.info() {
log::info!("Server listening on {info}");
}
listener.accept().await?;
Ok(())
}
pub async fn bind<L: ToListener<S>>(
self,
listener: L,
) -> io::Result<<L as ToListener<S>>::Listener> {
let mut listener = listener.to_listener()?;
listener.bind(self).await?;
Ok(listener)
}
pub async fn process<Req>(&self, req: Req) -> HandlerOutput
where
Req: Into<http_types::Request>,
{
let req = req.into();
let Self {
state,
router,
middleware,
} = self.clone();
let method = req.method();
let reader = router.read().await;
let Selection { handler, params } = reader.route(req.url().path(), method);
let req = Request {
state,
req,
captures: vec![params.into_owned()],
};
let next_middleware = middleware.read().await;
let next = Next {
handler,
next_middleware: next_middleware.as_ref(),
};
next.run(req).await
}
}
#[async_trait]
impl<S, ST> Handler<Request<S>, HandlerOutput> for Server<ST>
where
S: State,
ST: State,
{
async fn call(&self, args: Request<S>) -> HandlerOutput {
let Request {
req, mut captures, ..
} = args;
let path = req.url().path().to_owned();
let method = req.method();
let router = Arc::clone(&self.router);
let middleware = Arc::clone(&self.middleware);
let state = self.state.clone();
let reader = router.read().await;
let Selection { handler, params } = reader.route(&path, method);
captures.push(params.into_owned());
let req = Request {
state,
req,
captures,
};
let next_middleware = middleware.read().await;
let next = Next {
handler,
next_middleware: next_middleware.as_ref(),
};
next.run(req).await
}
}