greyhound 0.0.1

al3x's personal backend framework
Documentation
use crate::{
	endpoint::{Handler, HandlerOutput},
	middleware::{Middleware, MiddlewareArc, MiddlewareHandler},
	request::Request,
	router::Router,
	server::{state::State, Server},
};
use async_std::sync::{Arc, RwLock, Weak};

pub struct Route<S: State> {
	pub(crate) router: Weak<RwLock<Router<S>>>,
	pub(crate) path: String,
	pub(crate) middleware: MiddlewareArc<S, Request<S>, HandlerOutput>,

	pub(crate) prefix: bool,
}

impl<S: State> Route<S> {
	pub(crate) fn new(router: Weak<RwLock<Router<S>>>, path: &str) -> Self {
		Self {
			router,
			path: path.to_owned(),
			middleware: Arc::new(RwLock::new(vec![])),
			prefix: false,
		}
	}

	/// Extend the route with the given `path`.
	pub fn at(&mut self, path: &str) -> Route<S> {
		let mut p = self.path.clone();

		if !p.ends_with('/') && !path.starts_with('/') {
			p.push('/');
		}

		if path != "/" {
			p.push_str(path);
		}

		let router = Weak::clone(&self.router);

		Route {
			router,
			path: p,
			middleware: self.middleware.clone(),
			prefix: false,
		}
	}

	/*pub fn strip_prefix(&mut self) -> &mut Self {
		self.prefix = true;
		self
	}*/

	pub async fn with<M>(&mut self, middleware: M) -> &mut Self
	where
		M: Middleware<S, Request<S>, HandlerOutput>,
	{
		log::trace!(
			"Adding middleware {} to route {:?}",
			middleware.name(),
			self.path
		);
		self.middleware.write().await.push(Arc::new(middleware));

		// self.middleware.push(Arc::new(middleware));
		self
	}

	pub async fn nest<ST: State>(&mut self, service: Server<ST>) -> &mut Self {
		let prefix = self.prefix;

		self.prefix = true;
		self.all(service).await;
		self.prefix = prefix;

		self
	}

	pub async fn method(
		&mut self,
		method: http_types::Method,
		ep: impl Handler<Request<S>, HandlerOutput>,
	) -> &mut Route<S> {
		if self.prefix {
			let ep = StripPrefixEndpoint::new(ep);
			let wildcard = self.at("*");

			let router = Weak::clone(&wildcard.router)
				.upgrade()
				.expect("router is not accessible");

			let middleware = Arc::clone(&wildcard.middleware);

			router.write().await.add(
				&wildcard.path,
				method,
				MiddlewareHandler::wrap_with_middleware(ep, middleware).await,
			);
		} else {
			let router = Weak::clone(&self.router)
				.upgrade()
				.expect("router is not accessible");

			let middleware = Arc::clone(&self.middleware);

			router.write().await.add(
				&self.path,
				method,
				MiddlewareHandler::wrap_with_middleware(ep, middleware).await,
			);
		}

		self
	}

	pub async fn all(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		if self.prefix {
			let ep = StripPrefixEndpoint::new(ep);
			let wildcard = self.at("*");
			let router = Weak::clone(&wildcard.router)
				.upgrade()
				.expect("router is not accessible");

			let middleware = Arc::clone(&wildcard.middleware);

			router.write().await.add_all(
				&wildcard.path,
				MiddlewareHandler::wrap_with_middleware(ep, middleware).await,
			);
		} else {
			let router = Weak::clone(&self.router)
				.upgrade()
				.expect("router is not accessible");

			let middleware = Arc::clone(&self.middleware);

			router.write().await.add_all(
				&self.path,
				MiddlewareHandler::wrap_with_middleware(ep, middleware).await,
			);
		}
		self
	}

	/// Add an endpoint for `GET` requests
	pub async fn get(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Get, ep).await;
		self
	}

	/// Add an endpoint for `HEAD` requests
	pub async fn head(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Head, ep).await;
		self
	}

	/// Add an endpoint for `PUT` requests
	pub async fn put(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Put, ep).await;
		self
	}

	/// Add an endpoint for `POST` requests
	pub async fn post(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Post, ep).await;
		self
	}

	/// Add an endpoint for `DELETE` requests
	pub async fn delete(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Delete, ep).await;
		self
	}

	/// Add an endpoint for `OPTIONS` requests
	pub async fn options(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Options, ep).await;
		self
	}

	/// Add an endpoint for `CONNECT` requests
	pub async fn connect(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Connect, ep).await;
		self
	}

	/// Add an endpoint for `PATCH` requests
	pub async fn patch(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Patch, ep).await;
		self
	}

	/// Add an endpoint for `TRACE` requests
	pub async fn trace(&mut self, ep: impl Handler<Request<S>, HandlerOutput>) -> &mut Self {
		self.method(http_types::Method::Trace, ep).await;
		self
	}
}

#[derive(Debug)]
struct StripPrefixEndpoint<E>(Arc<E>);

impl<E> StripPrefixEndpoint<E> {
	fn new(ep: E) -> Self {
		Self(Arc::new(ep))
	}
}

impl<E> Clone for StripPrefixEndpoint<E> {
	fn clone(&self) -> Self {
		Self(self.0.clone())
	}
}

#[async_trait::async_trait]
impl<S: State, E> Handler<Request<S>, HandlerOutput> for StripPrefixEndpoint<E>
where
	E: Handler<Request<S>, HandlerOutput>,
{
	async fn call(&self, args: Request<S>) -> HandlerOutput {
		let Request {
			state,
			mut req,
			captures,
		} = args;

		let rest = captures
			.iter()
			.rev()
			.find_map(|captures| captures.wildcard())
			.unwrap_or_default();

		req.url_mut().set_path(rest);

		self.0
			.call(Request {
				state,
				req,
				captures,
			})
			.await
	}
}