diff --git a/Cargo.lock b/Cargo.lock index 879061e..4484287 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,50 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", + "humansize", + "num-traits", + "percent-encoding", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -121,6 +165,15 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -387,6 +440,7 @@ name = "http-horse" version = "0.1.2" dependencies = [ "anyhow", + "askama", "async-stream", "bytes", "clap", @@ -416,6 +470,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" version = "1.4.1" @@ -501,6 +564,12 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "lock_api" version = "0.4.12" @@ -523,6 +592,28 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -544,6 +635,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "normpath" version = "1.3.0" @@ -563,6 +664,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.3" @@ -619,6 +729,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pin-project" version = "1.1.5" @@ -961,6 +1077,15 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -979,6 +1104,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index cd5ad66..28e48c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,4 @@ tokio-stream = "0.1.15" async-stream = "0.3.5" opener = "0.7.2" anyhow = "1.0.86" +askama = "0.12.1" diff --git a/src/main.rs b/src/main.rs index e05d13f..7395004 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use anyhow::{anyhow, Context}; +use askama::Template; use async_stream::stream; use bytes::Bytes; use clap::{crate_version, Parser}; @@ -26,11 +27,18 @@ use tokio::{fs::File, net::TcpListener}; use tokio_util::io::ReaderStream; use tracing::{debug, error, info, warn}; +#[derive(Template)] +#[template(path = "status-webui/index.htm")] +struct StatusWebUiIndex<'a> { + project_dir: &'a str, +} + +static INTERNAL_INDEX_PAGE: OnceLock> = OnceLock::new(); + static NOT_FOUND_BODY_TEXT: &[u8] = b"HTTP 404. File not found."; static METHOD_NOT_ALLOWED_BODY_TEXT: &[u8] = b"HTTP 405. Method not allowed."; static INTERNAL_SERVER_ERROR_BODY_TEXT: &[u8] = b"HTTP 500. Internal server error."; -static INTERNAL_INDEX_PAGE: &[u8] = include_bytes!("../webui-src/html/index.htm"); static INTERNAL_STYLESHEET: &[u8] = include_bytes!("../webui-src/style/main.css"); static INTERNAL_JAVASCRIPT: &[u8] = include_bytes!("../webui-src/js/main.js"); @@ -121,6 +129,13 @@ async fn main() -> anyhow::Result<()> { .inspect_err(|e| error!(os_string = ?e, "Fatal: Failed to convert PathBuf to String.")) .map_err(|_| anyhow!("Failed to convert PathBuf to String."))?; + let internal_index_page = StatusWebUiIndex { project_dir: &pdir }; + let internal_index_page_rendered = internal_index_page.render()?.as_bytes().to_vec(); + INTERNAL_INDEX_PAGE + .set(internal_index_page_rendered) + .inspect_err(|e| error!(existing_value = ?e, "Fatal: OnceLock has existing value.")) + .map_err(|_| anyhow!("Failed to set value of OnceLock."))?; + let status_addr = SocketAddr::new(args.status_listen_addr, args.status_listen_port); let status_tcp = TcpListener::bind(status_addr) .await @@ -452,9 +467,19 @@ async fn request_handler_status( ); match (method, uri_path) { - (&Method::GET, "") => response_builder - .header(header::CONTENT_TYPE, HeaderValue::from_static(TEXT_HTML)) - .body(Either::Left(INTERNAL_INDEX_PAGE.into())), + (&Method::GET, "") => match INTERNAL_INDEX_PAGE.get() { + None => { + error!("Failed to get rendered index page for status web-ui!"); + let (status, content_type, body) = server_error(); + response_builder + .header(header::CONTENT_TYPE, content_type) + .status(status) + .body(Either::Left(body)) + } + Some(internal_index_page) => response_builder + .header(header::CONTENT_TYPE, HeaderValue::from_static(TEXT_HTML)) + .body(Either::Left(internal_index_page.as_slice().into())), + }, (&Method::GET, "favicon.ico") => response_builder .header(header::CONTENT_TYPE, HeaderValue::from_static(IMAGE_X_ICON)) .status(StatusCode::NO_CONTENT) diff --git a/webui-src/html/index.htm b/templates/status-webui/index.htm similarity index 87% rename from webui-src/html/index.htm rename to templates/status-webui/index.htm index d3d06ba..398ed15 100644 --- a/webui-src/html/index.htm +++ b/templates/status-webui/index.htm @@ -1,18 +1,21 @@ -example/out/ – http-horse +Project {{ project_dir }} – http-horse
-

Status for example/out/

+
+

http-horse 🐴

+

Project {{ project_dir }}

+
-

Pages and their resources

+

Pages and their resources

  • @@ -35,7 +38,7 @@
-

Recent file system event history

+

Recent file system event history

entry

entry

diff --git a/webui-src/style/main.css b/webui-src/style/main.css index 0747f01..70de0b9 100644 --- a/webui-src/style/main.css +++ b/webui-src/style/main.css @@ -194,13 +194,17 @@ h1, h2, h3, h4, h5, h6 { } h1 { - font-size: 1.6rem; + font-size: 1.829rem; } h2 { font-size: 1.4rem; } +h3 { + font-size: 1.225rem; +} + /* * ## General list appearance */ @@ -222,10 +226,14 @@ li > ul { } #header-main { - padding: 0.618rem 1rem; + padding: 1.618rem 1rem; overflow-x: hidden; } +#header-main > h2 { + margin-top: 0.618rem; +} + #inner-main { padding: 1rem; }