mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
asset work
This commit is contained in:
parent
6485612898
commit
1648eeffab
6 changed files with 144 additions and 46 deletions
87
src/asset.rs
Normal file
87
src/asset.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
use hyper::header::{CACHE_CONTROL, CONTENT_TYPE, ETAG};
|
||||
use hyper::http::{HeaderName, HeaderValue};
|
||||
|
||||
macro_rules! saved_asset {
|
||||
($name:expr) => {
|
||||
include_str!(concat!(env!("OUT_DIR"), "/", $name))
|
||||
};
|
||||
}
|
||||
macro_rules! saved_asset_url {
|
||||
($name:expr) => {
|
||||
concat!("/", $name, "?v=", crate::asset::saved_asset_hash!($name))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! saved_asset_hash {
|
||||
($name:expr) => {
|
||||
concat!(
|
||||
r#"""#,
|
||||
include_str!(concat!(env!("OUT_DIR"), "/", $name, ".hash")),
|
||||
r#"""#
|
||||
)
|
||||
};
|
||||
($name:expr, quoted) => {
|
||||
concat!(r#"""#, crate::asset::saved_asset_hash!($name), r#"""#)
|
||||
};
|
||||
}
|
||||
|
||||
pub const fn cache_headers(
|
||||
content_type: &'static str,
|
||||
etag: &'static str,
|
||||
) -> [(HeaderName, HeaderValue); 3] {
|
||||
[
|
||||
(CONTENT_TYPE, HeaderValue::from_static(content_type)),
|
||||
(ETAG, HeaderValue::from_static(etag)),
|
||||
(
|
||||
CACHE_CONTROL,
|
||||
HeaderValue::from_static("public, max-age=2592000, immutable"),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
pub const fn guess_mime(path: &'static str) -> &'static str {
|
||||
use const_str::ends_with;
|
||||
if ends_with!(path, "svg") {
|
||||
return "image/svg+xml";
|
||||
} else if ends_with!(path, "png") {
|
||||
return "image/png";
|
||||
} else if ends_with!(path, "css") {
|
||||
return "text/css";
|
||||
}
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
macro_rules! serve_static {
|
||||
($name:expr) => {
|
||||
|| async {
|
||||
const CONTENT: &[u8] = include_bytes!($name);
|
||||
const HASH: u32 = const_fnv1a_hash::fnv1a_hash_32(&CONTENT, None);
|
||||
const HASH_S: const_base::ArrayStr<8> = const_base::WrongOutputLength::unwrap(
|
||||
const_base::encode(&HASH.to_le_bytes(), const_base::Config::HEX),
|
||||
);
|
||||
(
|
||||
crate::asset::cache_headers(crate::asset::guess_mime($name), HASH_S.as_str()),
|
||||
CONTENT,
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! serve_compiled {
|
||||
($name:expr) => {
|
||||
|| async {
|
||||
let style = crate::asset::saved_asset!($name);
|
||||
let etag = crate::asset::saved_asset_hash!($name, quoted);
|
||||
(
|
||||
crate::asset::cache_headers(crate::asset::guess_mime($name), etag),
|
||||
style,
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use saved_asset;
|
||||
pub(crate) use saved_asset_hash;
|
||||
pub(crate) use saved_asset_url;
|
||||
pub(crate) use serve_compiled;
|
||||
pub(crate) use serve_static;
|
||||
29
src/main.rs
29
src/main.rs
|
|
@ -1,3 +1,4 @@
|
|||
mod asset;
|
||||
mod config;
|
||||
mod data;
|
||||
mod error;
|
||||
|
|
@ -9,12 +10,12 @@ use crate::data::demo::{Demo, ListDemo};
|
|||
use crate::pages::demo::DemoPage;
|
||||
use crate::pages::index::Index;
|
||||
use crate::pages::render;
|
||||
use asset::{serve_compiled, serve_static};
|
||||
use axum::extract::{MatchedPath, Path};
|
||||
use axum::http::{HeaderValue, Request};
|
||||
use axum::http::Request;
|
||||
use axum::response::IntoResponse;
|
||||
use axum::{extract::State, routing::get, Router, Server};
|
||||
pub use error::Error;
|
||||
use hyper::header::{CACHE_CONTROL, CONTENT_TYPE, ETAG};
|
||||
use hyperlocal::UnixServerExt;
|
||||
use maud::Markup;
|
||||
use sqlx::PgPool;
|
||||
|
|
@ -52,7 +53,9 @@ async fn main() -> Result<()> {
|
|||
|
||||
let app = Router::new()
|
||||
.route("/", get(index))
|
||||
.route("/style.:version.css", get(style))
|
||||
.route("/style.css", get(serve_compiled!("style.css")))
|
||||
.route("/images/logo.png", get(serve_static!("../images/logo.png")))
|
||||
.route("/images/logo.svg", get(serve_static!("../images/logo.svg")))
|
||||
.route("/:id", get(demo))
|
||||
.layer(
|
||||
TraceLayer::new_for_http().make_span_with(|request: &Request<_>| {
|
||||
|
|
@ -94,26 +97,6 @@ async fn main() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn style() -> impl IntoResponse {
|
||||
let style = include_str!(concat!(env!("OUT_DIR"), "/style.css"));
|
||||
let etag = concat!(
|
||||
r#"""#,
|
||||
include_str!(concat!(env!("OUT_DIR"), "/style.md5")),
|
||||
r#"""#
|
||||
);
|
||||
(
|
||||
[
|
||||
(CONTENT_TYPE, HeaderValue::from_static("text/css")),
|
||||
(ETAG, HeaderValue::from_static(etag)),
|
||||
(
|
||||
CACHE_CONTROL,
|
||||
HeaderValue::from_static("public, max-age=2592000, immutable"),
|
||||
),
|
||||
],
|
||||
style,
|
||||
)
|
||||
}
|
||||
|
||||
async fn index(State(app): State<Arc<App>>) -> Result<Markup> {
|
||||
let demos = ListDemo::list(&app.connection, None).await?;
|
||||
Ok(render(Index { demos }))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
pub mod demo;
|
||||
pub mod index;
|
||||
|
||||
use crate::asset::saved_asset_url;
|
||||
use maud::{html, Markup, DOCTYPE};
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
|
@ -10,17 +11,14 @@ pub trait Page {
|
|||
}
|
||||
|
||||
pub fn render<T: Page>(page: T) -> Markup {
|
||||
let style_url = concat!(
|
||||
"/style.",
|
||||
include_str!(concat!(env!("OUT_DIR"), "/style.md5")),
|
||||
".css",
|
||||
);
|
||||
let style_url = saved_asset_url!("style.css");
|
||||
html! {
|
||||
(DOCTYPE)
|
||||
html {
|
||||
head {
|
||||
title { (page.title()) }
|
||||
link rel="stylesheet" type="text/css" href=(style_url);
|
||||
link rel="shortcut icon" type="image/svg+xml" href="images/logo.svg";
|
||||
}
|
||||
body {
|
||||
header {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue