feat: Serve index.html at root
This commit is contained in:
parent
f42924cd3b
commit
256aca663c
1 changed files with 23 additions and 8 deletions
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue