From f4e9ef6af9389bdb1f52b834c7ca9732b7c75a6d Mon Sep 17 00:00:00 2001 From: Fries Date: Wed, 12 Jul 2023 18:41:39 -0700 Subject: [PATCH] seperate the hyperlegible font-face to a template this lets me make the base html code cleaner and it lets me keep using a seperate file for font-face stuff so the style.css is cleaner. this is implemented by using the askama template engine with the same syntax that was used in the style tag in base.html, but i render the template to text instead of directly to a rocket responder and i hash it with the sha2 crate. this hashing should only run once, at startup, so it shouldn't be much of a performance hit. --- Cargo.lock | 11 +++ Cargo.toml | 4 + src/assets/files.rs | 122 ++++++++++++++++++------- src/assets/mod.rs | 1 + src/assets/responders.rs | 44 +++++++++ src/assets/routes.rs | 47 +--------- src/assets/templates.rs | 5 + src/routes.rs | 9 +- templates/base.html | 46 +--------- {public => templates}/hyperlegible.css | 8 +- 10 files changed, 162 insertions(+), 135 deletions(-) create mode 100644 src/assets/responders.rs rename {public => templates}/hyperlegible.css (62%) diff --git a/Cargo.lock b/Cargo.lock index 1ccbaa5..cf81bad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -870,6 +870,7 @@ dependencies = [ "rust-embed", "serde", "serde_json", + "sha2", "shared", "simple_logger", ] @@ -1463,6 +1464,16 @@ dependencies = [ "cfg-if", "cpufeatures", "digest", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea" +dependencies = [ + "cc", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a4cf50b..2cc9f94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,3 +63,7 @@ default_features = false [dependencies.proc_macros] path = "./crates/proc-macros" + +[dependencies.sha2] +version = "0.10" +features = ["asm"] diff --git a/src/assets/files.rs b/src/assets/files.rs index f09e22e..40eee58 100644 --- a/src/assets/files.rs +++ b/src/assets/files.rs @@ -1,5 +1,8 @@ +use super::templates::HyperlegibleTemplate; +use askama::Template; use rocket::http::Status; use rust_embed::RustEmbed; +use sha2::{Digest, Sha256}; use std::{borrow::Cow, sync::OnceLock}; #[derive(RustEmbed)] @@ -8,11 +11,11 @@ struct Assets; #[derive(Debug)] pub struct Files { + pub style: TextFile, + pub hyperlegible: TextFile, pub atkinson_latin_woff2: BinaryFile, pub atkinson_latin_ext_woff2: BinaryFile, pub atkinson_all_woff: BinaryFile, - pub style: TextFile, - pub hyperlegible: TextFile, } #[derive(Debug, Clone)] @@ -42,6 +45,44 @@ pub struct TextFile { pub metadata: FileMetadata, } +trait GetFile { + fn get(filename: &str, extension: &str) -> Option + where + Self: Sized; +} + +impl GetFile for BinaryFile { + fn get(filename: &str, extension: &str) -> Option { + match Assets::get(&format!("{}.{}", filename, extension)) { + Some(file) => { + let metadata = FileMetadata { + filename: filename.into(), + extension: extension.into(), + hash: hex::encode(file.metadata.sha256_hash()), + }; + Some(BinaryFile { + data: file.data, + metadata: metadata, + }) + } + None => None, + } + } +} + +impl GetFile for TextFile { + fn get(filename: &str, extension: &str) -> Option { + let file = BinaryFile::get(filename, extension)?; + match std::str::from_utf8(&file.data) { + Ok(string) => Some(TextFile { + text: string.into(), + metadata: file.metadata, + }), + Err(_) => None, + } + } +} + pub static FILES: OnceLock = OnceLock::new(); pub fn get_file_wrapper() -> Result<&'static Files, Status> { @@ -51,46 +92,57 @@ pub fn get_file_wrapper() -> Result<&'static Files, Status> { } } -fn get_binary_file(filename: &str, extension: &str) -> Option { - match Assets::get(&format!("{}.{}", filename, extension)) { - Some(file) => { - let metadata = FileMetadata { - filename: filename.into(), - extension: extension.into(), - hash: hex::encode(file.metadata.sha256_hash()), - }; - Some(BinaryFile { - data: file.data, - metadata: metadata, - }) - } - None => None, - } +fn get_sha256_hash(string: &String) -> String { + let mut hasher = Sha256::new(); + hasher.update(string); + let result = hasher.finalize(); + hex::encode(result) } -fn get_text_file(filename: &str, extension: &str) -> Option { - let file = get_binary_file(filename, extension)?; - match std::str::from_utf8(&file.data) { - Ok(string) => Some(TextFile { - text: string.into(), - metadata: file.metadata, - }), - Err(_) => None, +fn get_hyperlegible( + latin_woff2_filename: String, + latin_ext_woff2_filename: String, + all_woff_filename: String, +) -> TextFile { + let hyperlegible_template = HyperlegibleTemplate { + atkinson_latin_woff2_filename: latin_woff2_filename, + atkinson_latin_ext_woff2_filename: latin_ext_woff2_filename, + atkinson_all_woff_filename: all_woff_filename, + }; + + let rendered_template = hyperlegible_template.render().unwrap(); + let hash = get_sha256_hash(&rendered_template); + + let metadata = FileMetadata { + filename: "hyperlegible".into(), + extension: "css".into(), + hash, + }; + + TextFile { + text: rendered_template, + metadata, } } pub fn initialize_files() { + let atkinson_latin_woff2 = + BinaryFile::get("atkinson-hyperlegible-latin-400-normal", "woff2").unwrap(); + let atkinson_latin_ext_woff2 = + BinaryFile::get("atkinson-hyperlegible-latin-ext-400-normal", "woff2").unwrap(); + let atkinson_all_woff = + BinaryFile::get("atkinson-hyperlegible-all-400-normal", "woff").unwrap(); + let files = Files { - atkinson_latin_woff2: get_binary_file("atkinson-hyperlegible-latin-400-normal", "woff2") - .unwrap(), - atkinson_latin_ext_woff2: get_binary_file( - "atkinson-hyperlegible-latin-ext-400-normal", - "woff2", - ) - .unwrap(), - atkinson_all_woff: get_binary_file("atkinson-hyperlegible-all-400-normal", "woff").unwrap(), - style: get_text_file("style", "css").unwrap(), - hyperlegible: get_text_file("hyperlegible", "css").unwrap(), + style: TextFile::get("style", "css").unwrap(), + hyperlegible: get_hyperlegible( + atkinson_latin_woff2.metadata.get_hash_filename(), + atkinson_latin_ext_woff2.metadata.get_hash_filename(), + atkinson_all_woff.metadata.get_hash_filename(), + ), + atkinson_latin_woff2, + atkinson_latin_ext_woff2, + atkinson_all_woff, }; FILES.set(files).unwrap(); } diff --git a/src/assets/mod.rs b/src/assets/mod.rs index 2e4d45e..5ecc4a1 100644 --- a/src/assets/mod.rs +++ b/src/assets/mod.rs @@ -1,4 +1,5 @@ pub mod files; +mod responders; mod routes; pub mod templates; diff --git a/src/assets/responders.rs b/src/assets/responders.rs new file mode 100644 index 0000000..8a3006b --- /dev/null +++ b/src/assets/responders.rs @@ -0,0 +1,44 @@ +use super::templates::ErrorTemplate; +use rocket::{ + http::Header, + response::{self, Responder}, + Response, +}; +use std::borrow::Cow; + +#[derive(Responder)] +#[response(status = 200, content_type = "font/woff2")] +pub struct RawWoff2Font(pub Cow<'static, [u8]>); + +#[derive(Responder)] +#[response(status = 200, content_type = "font/woff")] +pub struct RawWoffFont(pub Cow<'static, [u8]>); + +#[derive(Responder)] +pub struct ErrorTemplateResponder<'a> { + template: ErrorTemplate<'a>, +} + +pub struct CachedResponse { + inner: T, +} + +impl<'r, T> Responder<'r, 'static> for CachedResponse +where + T: Responder<'r, 'static>, +{ + fn respond_to(self, request: &'r rocket::Request<'_>) -> response::Result<'static> { + Response::build_from(self.inner.respond_to(request)?) + .header(Header::new("Cache-Control", "max-age=31536000, immutable")) + .ok() + } +} + +impl<'r, T> From for CachedResponse +where + T: Responder<'r, 'static>, +{ + fn from(value: T) -> Self { + CachedResponse { inner: value } + } +} diff --git a/src/assets/routes.rs b/src/assets/routes.rs index db2be30..526a1a7 100644 --- a/src/assets/routes.rs +++ b/src/assets/routes.rs @@ -1,47 +1,6 @@ -use super::{files::get_file_wrapper, templates::ErrorTemplate}; -use rocket::{ - http::{Header, Status}, - response::{self, content::RawCss, Responder}, - Response, -}; -use std::borrow::Cow; - -#[derive(Responder)] -#[response(status = 200, content_type = "font/woff2")] -pub struct RawWoff2Font(pub Cow<'static, [u8]>); - -#[derive(Responder)] -#[response(status = 200, content_type = "font/woff")] -pub struct RawWoffFont(pub Cow<'static, [u8]>); - -#[derive(Responder)] -pub struct ErrorTemplateResponder<'a> { - template: ErrorTemplate<'a>, -} - -pub struct CachedResponse { - inner: T, -} - -impl<'r, T> Responder<'r, 'static> for CachedResponse -where - T: Responder<'r, 'static>, -{ - fn respond_to(self, request: &'r rocket::Request<'_>) -> response::Result<'static> { - Response::build_from(self.inner.respond_to(request)?) - .header(Header::new("Cache-Control", "max-age=31536000, immutable")) - .ok() - } -} - -impl<'r, T> From for CachedResponse -where - T: Responder<'r, 'static>, -{ - fn from(value: T) -> Self { - CachedResponse { inner: value } - } -} +use super::files::get_file_wrapper; +use crate::assets::responders::{CachedResponse, RawWoff2Font, RawWoffFont}; +use rocket::{http::Status, response::content::RawCss}; #[get("/css/ + {% endblock %} diff --git a/public/hyperlegible.css b/templates/hyperlegible.css similarity index 62% rename from public/hyperlegible.css rename to templates/hyperlegible.css index eca87f6..9205a4b 100644 --- a/public/hyperlegible.css +++ b/templates/hyperlegible.css @@ -3,8 +3,8 @@ font-style: normal; font-display: swap; font-weight: 400; - src: url(/public/woff2/atkinson-hyperlegible-latin-ext-400-normal.woff2) format("woff2"), - url(/public/woff/atkinson-hyperlegible-all-400-normal.woff) format("woff"); + src: url("/public/woff2/{{ atkinson_latin_ext_woff2_filename }}") format("woff2"), + url("/public/woff/{{ atkinson_all_woff_filename }}") format("woff"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, @@ -21,8 +21,8 @@ font-style: normal; font-display: swap; font-weight: 400; - src: url(/public/woff2/atkinson-hyperlegible-latin-400-normal.woff2) format("woff2"), - url(/public/woff/atkinson-hyperlegible-all-400-normal.woff) format("woff"); + src: url("/public/woff2/{{ atkinson_latin_woff2_filename }}") format("woff2"), + url("/public/woff/{{ atkinson_all_woff_filename }}") format("woff"); unicode-range: U+0000-00FF, U+0131, U+0152-0153,