diff --git a/Cargo.lock b/Cargo.lock index ca1bc52..f37aedd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1121,6 +1121,8 @@ dependencies = [ "gpio-cdev", "hackdose-sml-parser", "hackdose_server_shared", + "include_dir", + "mime_guess", "rand", "reqwest", "serde", @@ -1423,6 +1425,25 @@ dependencies = [ "syn 2.0.43", ] +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "2.1.0" diff --git a/server/Cargo.toml b/server/Cargo.toml index f91713b..28c34df 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -28,6 +28,8 @@ async-trait = "0.1.64" serde_json = "1.0.107" axum = "0.7.3" tower-http = { version="0.5.0", features=["fs", "cors"] } +include_dir = "0.7.3" +mime_guess = "2.0.4" [profile.release] lto = true diff --git a/server/src/rest/mod.rs b/server/src/rest/mod.rs index 8d39146..e158e12 100644 --- a/server/src/rest/mod.rs +++ b/server/src/rest/mod.rs @@ -1,8 +1,10 @@ use std::{collections::HashMap, sync::Arc}; use axum::{ - extract::{FromRef, State}, - response::Html, + body::Body, + extract::{FromRef, Path, State}, + http::{header, HeaderValue, StatusCode}, + response::{Html, IntoResponse, Response}, routing::get, Json, Router, }; @@ -10,13 +12,39 @@ use chrono::{Duration, Utc}; use hackdose_server_shared::DataPoint; use hackdose_sml_parser::application::{domain::AnyValue, obis::Obis}; use tokio::sync::Mutex; +use tokio_stream::Empty; use tower_http::{ + body::{self, Full}, cors::CorsLayer, services::{ServeDir, ServeFile}, }; use crate::{data::EnergyData, Configuration}; +use include_dir::{include_dir, Dir}; + +static STATIC_DIR: Dir<'_> = include_dir!("app/dist/"); + +async fn static_path(Path(path): Path) -> Response { + let path = path.trim_start_matches('/'); + let mime_type = mime_guess::from_path(path).first_or_text_plain(); + + match STATIC_DIR.get_file(path) { + None => Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .unwrap(), + Some(file) => Response::builder() + .status(StatusCode::OK) + .header( + header::CONTENT_TYPE, + HeaderValue::from_str(mime_type.as_ref()).unwrap(), + ) + .body(Body::from(file.contents())) + .unwrap(), + } +} + #[derive(Clone)] struct SmartMeterState(Arc>>); @@ -54,7 +82,7 @@ pub(crate) async fn serve_rest_endpoint( .route("/api/data_raw", get(data_raw)) .layer(CorsLayer::permissive()) .nest_service("/api/log", ServeFile::new(config.log_location.clone())) - .nest_service("/", ServeDir::new("../app/dist")) + .route("/*path", get(static_path)) .with_state(app_state); let _ = axum::serve(listener, app).await;