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: String,
#[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() -> String {
"assets/static/404.html".to_string()
}
fn default_folder_config() -> FolderConfig {
FolderConfig {
uri: "/static".to_string(),
path: "assets/static".to_string(),
}
}
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct FolderConfig {
pub uri: String,
pub path: String,
}
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
&& (!PathBuf::from(&self.folder.path).exists()
|| !PathBuf::from(&self.fallback).exists())
{
return Err(Error::Message(format!(
"one of the static path are not found, Folder `{}` fallback: `{}`",
self.folder.path, self.fallback,
)));
}
let serve_dir =
ServeDir::new(&self.folder.path).not_found_service(ServeFile::new(&self.fallback));
Ok(app.nest_service(
&self.folder.uri,
if self.precompressed {
serve_dir.precompressed_gzip()
} else {
serve_dir
},
))
}
}