use axum::body::Body;
use axum::http::{header, Response, StatusCode};
use axum::response::IntoResponse;
#[cfg(feature = "embedded-assets")]
use axum::http::HeaderValue;
#[cfg(feature = "embedded-assets")]
use rust_embed::RustEmbed;
#[cfg(feature = "embedded-assets")]
#[derive(RustEmbed)]
#[folder = "../../web/dist/"]
struct WebAssets;
#[cfg(feature = "embedded-assets")]
pub fn serve_embedded(path: &str) -> Option<Response<Body>> {
let path = path.trim_start_matches('/');
let (file, served_path) = match WebAssets::get(path) {
Some(f) => (f, path),
None => {
if !path.starts_with("assets/") && !path.starts_with("favicon") && !path.contains('.') {
let f = WebAssets::get("index.html")?;
(f, "index.html")
} else {
return None;
}
}
};
let mime = mime_guess::from_path(served_path).first_or_octet_stream();
let mut response = Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, mime.as_ref())
.body(Body::from(file.data.into_owned()))
.ok()?;
if served_path.starts_with("assets/") {
let val = HeaderValue::from_static("public, max-age=31536000, immutable");
response.headers_mut().insert(header::CACHE_CONTROL, val);
}
Some(response)
}
#[cfg(not(feature = "embedded-assets"))]
pub fn serve_embedded(_path: &str) -> Option<Response<Body>> {
None
}
#[cfg(feature = "embedded-assets")]
pub fn has_embedded() -> bool {
WebAssets::iter().next().is_some()
}
#[cfg(not(feature = "embedded-assets"))]
pub fn has_embedded() -> bool {
false
}
pub async fn embedded_fallback(uri: axum::http::Uri) -> impl IntoResponse {
let path = uri.path();
if let Some(resp) = serve_embedded(path) {
return resp;
}
let web_dir = std::env::var("MADHYAMAS_WEB_DIR").unwrap_or_else(|_| "web/dist".to_string());
let disk_path = format!("{}/{}", web_dir, path.trim_start_matches('/'));
if let Ok(metadata) = std::fs::metadata(&disk_path) {
if metadata.is_file() {
if let Ok(data) = std::fs::read(&disk_path) {
let mime = mime_guess::from_path(&disk_path).first_or_octet_stream();
return Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, mime.as_ref())
.body(Body::from(data))
.unwrap_or_else(|_| StatusCode::NOT_FOUND.into_response());
}
}
}
if let Some(resp) = serve_embedded("index.html") {
return resp;
}
let index_path = format!("{}/index.html", web_dir);
if let Ok(data) = std::fs::read(&index_path) {
return Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, "text/html; charset=utf-8")
.body(Body::from(data))
.unwrap_or_else(|_| StatusCode::NOT_FOUND.into_response());
}
StatusCode::NOT_FOUND.into_response()
}