feat: Serve index.html at root

This commit is contained in:
Ashhhleyyy 2022-07-05 11:36:57 +01:00
parent f42924cd3b
commit 256aca663c
Signed by: ash
GPG key ID: 83B789081A0878FB

View file

@ -1,6 +1,6 @@
use std::{io::{self, Read}, path::PathBuf, path, fs::File}; use std::{io::{self, Read}, path::PathBuf, path, fs::File};
use axum::{http::{StatusCode, HeaderMap, HeaderValue}, extract::{Multipart, Path}, body::Bytes, BoxError, Router, routing::{post, get}}; use axum::{http::{StatusCode, HeaderMap, HeaderValue}, extract::{Multipart, Path}, body::Bytes, BoxError, Router, routing::{post, get}, response::Redirect};
use futures::{Stream, TryStreamExt}; use futures::{Stream, TryStreamExt};
use tokio::io::{BufWriter, AsyncWriteExt}; use tokio::io::{BufWriter, AsyncWriteExt};
use tokio_util::io::StreamReader; use tokio_util::io::StreamReader;
@ -11,29 +11,44 @@ use crate::projects::Authed;
pub fn router() -> Router { pub fn router() -> Router {
Router::new() Router::new()
.route("/:project", post(upload_project)) .route("/:project", post(upload_project))
.route("/:project", get(project_redirect))
.route("/:project/*path", get(get_asset)) .route("/:project/*path", get(get_asset))
} }
async fn project_redirect(Path(path): Path<String>) -> Redirect {
Redirect::to(&format!("/{}/", path))
}
async fn get_asset(Path((project, filename)): Path<(String, String)>) -> Result<(HeaderMap, Vec<u8>), StatusCode> { async fn get_asset(Path((project, filename)): Path<(String, String)>) -> Result<(HeaderMap, Vec<u8>), StatusCode> {
let path = path::Path::new("project-archives") let path = path::Path::new("project-archives")
.join(format!("{project}.zip")); .join(format!("{project}.zip"));
if path.exists() { if path.exists() {
let data = { let asset = {
let filename = filename.clone(); let filename = filename.clone();
move || { move || {
let zip = ZipArchive::new(File::open(path)?)?; let mut zip = ZipArchive::new(File::open(path)?)?;
let asset = find_asset(zip, &filename.clone())?; let asset = find_asset(&mut zip, &filename.clone())?;
let asset = if let Some(asset) = asset {
Some((mime_guess::from_path(filename).first_or_octet_stream(), asset))
} else if filename.ends_with("/") {
let changed_name = format!("{filename}index.html");
find_asset(&mut zip, &changed_name)?
.map(|data| (mime_guess::from_path(changed_name).first_or_octet_stream(), data))
} else {
None
};
Ok::<_, color_eyre::Report>(asset) Ok::<_, color_eyre::Report>(asset)
} }
}; };
let data = tokio::task::spawn_blocking(data).await
let asset = tokio::task::spawn_blocking(asset).await
.unwrap() .unwrap()
.map_err(|e| { .map_err(|e| {
tracing::error!(%e, "failed to find asset in zip"); tracing::error!(%e, "failed to find asset in zip");
StatusCode::INTERNAL_SERVER_ERROR StatusCode::INTERNAL_SERVER_ERROR
})?; })?;
if let Some(data) = data {
let mime = mime_guess::from_path(filename).first_or_octet_stream(); if let Some((mime, data)) = asset {
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.append("content-type", HeaderValue::from_str(mime.essence_str()).unwrap()); headers.append("content-type", HeaderValue::from_str(mime.essence_str()).unwrap());
Ok((headers, data)) Ok((headers, data))
@ -45,7 +60,7 @@ async fn get_asset(Path((project, filename)): Path<(String, String)>) -> Result<
} }
} }
fn find_asset(mut zip: ZipArchive<impl std::io::Read + std::io::Seek>, filename: &str) -> color_eyre::Result<Option<Vec<u8>>> { fn find_asset(zip: &mut ZipArchive<impl std::io::Read + std::io::Seek>, filename: &str) -> color_eyre::Result<Option<Vec<u8>>> {
let filename = if filename.starts_with("/") { let filename = if filename.starts_with("/") {
&filename[1..] &filename[1..]
} else { } else {