greyhound 0.0.1

al3x's personal backend framework
Documentation
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
	}

	/// # Errors
	///
	/// TODO
	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(())
	}

	/// # Errors
	///
	/// TODO
	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)
	}

	/// # Errors
	///
	/// TODO
	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
	}
}