diff --git a/Cargo.lock b/Cargo.lock index 61335b6..d806393 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -829,7 +829,7 @@ dependencies = [ [[package]] name = "site-backend" -version = "0.1.3" +version = "0.1.4" dependencies = [ "axum", "flate2", diff --git a/curl b/curl index f6ec314..f1cbcdd 100755 --- a/curl +++ b/curl @@ -2,7 +2,7 @@ curl \ -XPOST \ - -T test.tar.gz \ + -T default.tar.gz \ -H 'Authorization: Bearer test' \ -v \ - http://localhost:3000/api/deploy?dir=docs + http://localhost:3000/api/deploy diff --git a/src/api/deploy.rs b/src/api/deploy.rs index 47be32d..a88d4df 100644 --- a/src/api/deploy.rs +++ b/src/api/deploy.rs @@ -11,7 +11,7 @@ use serde::Deserialize; use tar::Archive; use tokio_util::io::StreamReader; -use crate::DEFAULT_STATIC_DIR_NAME; +use crate::{DEFAULT_STATIC_SITE, STATIC_DIR_NAME}; #[derive(Deserialize)] pub struct StaticDirParams @@ -34,11 +34,10 @@ pub async fn post_deploy( let mut file = tokio::fs::File::create(&file_path).await.unwrap(); tokio::io::copy(&mut read, &mut file).await; - let mut static_path = Path::new(&data_dir).join(DEFAULT_STATIC_DIR_NAME); - - if params.dir.is_some() { - static_path = static_path.join(params.dir.unwrap()); - } + // If no dir is provided, we use the default one. Otherwise, use the provided one. + let static_path = Path::new(&data_dir) + .join(STATIC_DIR_NAME) + .join(params.dir.unwrap_or(DEFAULT_STATIC_SITE.to_string())); // Make sure the static directory exists tokio::fs::create_dir_all(&static_path).await; diff --git a/src/main.rs b/src/main.rs index cbc95b9..a1e41a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,10 @@ mod api; mod matrix; mod metrics; -const DEFAULT_STATIC_DIR_NAME: &str = "static"; +/// Name of the directory where static sites are stored inside the data directory +const STATIC_DIR_NAME: &str = "static"; +/// Name of the subdir of STATIC_DIR_NAME where the default (fallback) site is located +const DEFAULT_STATIC_SITE: &str = "default"; #[tokio::main] async fn main() @@ -30,13 +33,14 @@ async fn main() // Get required variables from env vars let api_key = std::env::var("API_KEY").expect("No API_KEY was provided."); let data_dir = std::env::var("DATA_DIR").expect("No DATA_DIR was provided."); - let static_dir = format!("{}/{}", data_dir, DEFAULT_STATIC_DIR_NAME); + let static_dir = format!("{}/{}", data_dir, STATIC_DIR_NAME); std::fs::create_dir_all(&static_dir); + // Initialize metrics let recorder_handle = metrics::setup_metrics_recorder(); - let app = Router::new() + let mut app = Router::new() // Handle Matrix .well-known files .nest("/", matrix::router()) // Routes under /api path @@ -44,16 +48,42 @@ async fn main() "/api", api::router().layer(RequireAuthorizationLayer::bearer(&api_key)), ) - .route("/metrics", get(move || ready(recorder_handle.render()))) + .route("/metrics", get(move || ready(recorder_handle.render()))); + + // Each static site gets mounted explicitely so that the default site can be used as fallback + // Each entry is of the form (route, static dir name) + let sites = [("/docs", "docs")]; + + for (path, dir) in sites { + let full_path = format!("{}/{}", static_dir, dir); + + app = app.nest( + path, + get_service(ServeDir::new(full_path)).handle_error( + |error: std::io::Error| async move { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + ) + }, + ), + ); + } + + app = app // The fallback option is to serve the actual static files - .fallback(get_service(ServeDir::new(static_dir)).handle_error( - |error: std::io::Error| async move { + .fallback( + get_service(ServeDir::new(format!( + "{}/{}", + static_dir, DEFAULT_STATIC_SITE + ))) + .handle_error(|error: std::io::Error| async move { ( StatusCode::INTERNAL_SERVER_ERROR, format!("Unhandled internal error: {}", error), ) - }, - )) + }), + ) .layer(middleware::from_fn(metrics::track_metrics)) .layer(Extension(data_dir)) .layer(TraceLayer::new_for_http());