use std::path::PathBuf;
use axum::Router as AXRouter;
use serde::{Deserialize, Serialize};
use serde_json::json;
use tower_http::services::{ServeDir, ServeFile};
use crate::{app::AppContext, controller::middleware::MiddlewareLayer, Error, Result};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct StaticAssets {
#[serde(default)]
pub enable: bool,
#[serde(default = "default_must_exist")]
pub must_exist: bool,
#[serde(default = "default_folder_config")]
pub folder: FolderConfig,
#[serde(default = "default_fallback")]
pub fallback: PathBuf,
#[serde(default = "default_precompressed")]
pub precompressed: bool,
}
impl Default for StaticAssets {
fn default() -> Self {
serde_json::from_value(json!({})).unwrap()
}
}
fn default_must_exist() -> bool {
true
}
fn default_precompressed() -> bool {
false
}
fn default_fallback() -> PathBuf {
PathBuf::from("assets").join("static").join("404.html")
}
fn default_folder_config() -> FolderConfig {
FolderConfig {
uri: "/static".to_string(),
path: PathBuf::from("assets/static"),
}
}
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct FolderConfig {
pub uri: String,
pub path: PathBuf,
}
impl MiddlewareLayer for StaticAssets {
fn name(&self) -> &'static str {
"static"
}
fn is_enabled(&self) -> bool {
self.enable
}
fn config(&self) -> serde_json::Result<serde_json::Value> {
serde_json::to_value(self)
}
fn apply(&self, app: AXRouter<AppContext>) -> Result<AXRouter<AppContext>> {
if self.must_exist && (!&self.folder.path.exists() || !&self.fallback.exists()) {
return Err(Error::Message(format!(
"one of the static path are not found, Folder `{}` fallback: `{}`",
self.folder.path.display(),
self.fallback.display(),
)));
}
let serve_dir = ServeDir::new(&self.folder.path).fallback(ServeFile::new(&self.fallback));
if &self.folder.uri == "/" {
Ok(app.fallback_service(serve_dir))
} else {
Ok(app.nest_service(
&self.folder.uri,
if self.precompressed {
serve_dir.precompressed_gzip()
} else {
serve_dir
},
))
}
}
}