summaryrefslogtreecommitdiff
path: root/src/ui.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui.rs')
-rw-r--r--src/ui.rs134
1 files changed, 0 insertions, 134 deletions
diff --git a/src/ui.rs b/src/ui.rs
deleted file mode 100644
index 91d0eb8..0000000
--- a/src/ui.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-use axum::{
- extract::{Path, Request, State},
- http::{header, StatusCode},
- middleware::{self, Next},
- response::{IntoResponse, Redirect, Response},
- routing::get,
- Router,
-};
-use mime_guess::Mime;
-use rust_embed::EmbeddedFile;
-
-use crate::{app::App, channel, error::Internal, invite, login::Login};
-
-#[derive(rust_embed::Embed)]
-#[folder = "target/ui"]
-struct Assets;
-
-impl Assets {
- fn load(path: impl AsRef<str>) -> Result<Asset, NotFound<String>> {
- let path = path.as_ref();
- let mime = mime_guess::from_path(path).first_or_octet_stream();
-
- Self::get(path)
- .map(|file| Asset(mime, file))
- .ok_or(NotFound(format!("not found: {path}")))
- }
-
- fn index() -> Result<Asset, Internal> {
- // "not found" in this case really is an internal error, as it should
- // never happen. `index.html` is a known-valid path.
- Ok(Self::load("index.html")?)
- }
-}
-
-pub fn router(app: &App) -> Router<App> {
- [
- Router::new()
- .route("/*path", get(asset))
- .route("/setup", get(setup)),
- Router::new()
- .route("/", get(root))
- .route("/login", get(login))
- .route("/ch/:channel", get(channel))
- .route("/invite/:invite", get(invite))
- .route_layer(middleware::from_fn_with_state(app.clone(), setup_required)),
- ]
- .into_iter()
- .fold(Router::default(), Router::merge)
-}
-
-async fn asset(Path(path): Path<String>) -> Result<Asset, NotFound<String>> {
- Assets::load(path)
-}
-
-async fn root(login: Option<Login>) -> Result<impl IntoResponse, Internal> {
- if login.is_none() {
- Ok(Redirect::temporary("/login").into_response())
- } else {
- Ok(Assets::index()?.into_response())
- }
-}
-
-async fn login() -> Result<impl IntoResponse, Internal> {
- Assets::index()
-}
-
-async fn setup(State(app): State<App>) -> Result<impl IntoResponse, Internal> {
- if app.setup().completed().await? {
- Ok(Redirect::to("/login").into_response())
- } else {
- Ok(Assets::index().into_response())
- }
-}
-
-async fn channel(
- State(app): State<App>,
- login: Option<Login>,
- Path(channel): Path<channel::Id>,
-) -> Result<impl IntoResponse, Internal> {
- if login.is_none() {
- Ok(Redirect::temporary("/").into_response())
- } else if app.channels().get(&channel).await?.is_none() {
- Ok(NotFound(Assets::index()?).into_response())
- } else {
- Ok(Assets::index()?.into_response())
- }
-}
-
-async fn invite(
- State(app): State<App>,
- Path(invite): Path<invite::Id>,
-) -> Result<impl IntoResponse, Internal> {
- match app.invites().get(&invite).await {
- Ok(_) => Ok(Assets::index()?.into_response()),
- Err(invite::app::Error::NotFound(_)) => Ok(NotFound(Assets::index()?).into_response()),
- Err(other) => Err(Internal::from(other)),
- }
-}
-
-struct Asset(Mime, EmbeddedFile);
-
-impl IntoResponse for Asset {
- fn into_response(self) -> Response {
- let Self(mime, file) = self;
- (
- StatusCode::OK,
- [(header::CONTENT_TYPE, mime.as_ref())],
- file.data,
- )
- .into_response()
- }
-}
-
-#[derive(Debug, thiserror::Error)]
-#[error("{0}")]
-struct NotFound<E>(pub E);
-
-impl<E> IntoResponse for NotFound<E>
-where
- E: IntoResponse,
-{
- fn into_response(self) -> Response {
- let Self(response) = self;
- (StatusCode::NOT_FOUND, response).into_response()
- }
-}
-
-pub async fn setup_required(State(app): State<App>, request: Request, next: Next) -> Response {
- match app.setup().completed().await {
- Ok(true) => next.run(request).await,
- Ok(false) => Redirect::to("/setup").into_response(),
- Err(error) => Internal::from(error).into_response(),
- }
-}