diff --git a/Cargo.lock b/Cargo.lock index f299f4e..8c173cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" -dependencies = [ - "memchr", -] - [[package]] name = "anstream" version = "0.3.2" @@ -452,15 +443,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - [[package]] name = "fsevent-sys" version = "4.1.0" @@ -677,16 +659,6 @@ dependencies = [ "want", ] -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -857,18 +829,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] -name = "meowy-webring" -version = "0.2.0" +name = "meowy-assets" +version = "0.1.0" dependencies = [ "askama", "askama_rocket", "hex", - "log", - "notify", "proc_macros", "rocket", - "rocket_cors", "rust-embed", + "sha2", + "shared", +] + +[[package]] +name = "meowy-webring" +version = "0.2.0" +dependencies = [ + "meowy-assets", + "notify", + "rocket", "serde", "serde_json", "shared", @@ -1206,8 +1186,6 @@ version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ - "aho-corasick", - "memchr", "regex-syntax 0.7.2", ] @@ -1287,20 +1265,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "rocket_cors" -version = "0.6.0-alpha2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12771b47f52e34d5d0e0e444aeba382863e73263cb9e18847e7d5b74aa2cbd0" -dependencies = [ - "http", - "log", - "regex", - "rocket", - "unicase", - "url", -] - [[package]] name = "rocket_http" version = "0.5.0-rc.3" @@ -1464,6 +1428,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]] @@ -1640,21 +1614,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.29.0" @@ -1851,44 +1810,18 @@ dependencies = [ "version_check", ] -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - [[package]] name = "unicode-ident" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "url" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 5d9d969..510a1d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["cli", "shared", "proc-macros"] +members = ["crates/*"] [package] name = "meowy-webring" @@ -7,47 +7,24 @@ version = "0.2.0" edition = "2021" rust-version = "1.70" -[profile.dev] -lto = false [profile.release] lto = "thin" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] -hex = "0.4" -log = "0.4" - [dependencies.rocket] version = "=0.5.0-rc.3" default-features = false features = ["json"] -[dependencies.rust-embed] -version = "6" -features = ["debug-embed"] - [dependencies.serde] version = "1.0" [dependencies.serde_json] version = "1.0" -[dependencies.askama_rocket] -git = "https://github.com/djc/askama.git" -package = "askama_rocket" -rev = "b9e51601560398766eac445517fb17c35090a952" -default-features = false - -[dependencies.askama] -git = "https://github.com/djc/askama.git" -package = "askama" -rev = "b9e51601560398766eac445517fb17c35090a952" -version = "0.12" -default-features = false - [dependencies.shared] -path = "./shared" +path = "./crates/shared" [dependencies.simple_logger] version = "4" @@ -58,9 +35,5 @@ version = "6" default-features = false features = ["macos_fsevent"] -[dependencies.rocket_cors] -version = "=0.6.0-alpha2" -default_features = false - -[dependencies.proc_macros] -path = "./proc-macros" +[dependencies.meowy-assets] +path = "./crates/meowy-assets" diff --git a/cli/Cargo.toml b/crates/cli/Cargo.toml similarity index 100% rename from cli/Cargo.toml rename to crates/cli/Cargo.toml diff --git a/cli/src/arguments.rs b/crates/cli/src/arguments.rs similarity index 100% rename from cli/src/arguments.rs rename to crates/cli/src/arguments.rs diff --git a/cli/src/commands/add.rs b/crates/cli/src/commands/add.rs similarity index 100% rename from cli/src/commands/add.rs rename to crates/cli/src/commands/add.rs diff --git a/cli/src/commands/mod.rs b/crates/cli/src/commands/mod.rs similarity index 100% rename from cli/src/commands/mod.rs rename to crates/cli/src/commands/mod.rs diff --git a/cli/src/commands/print.rs b/crates/cli/src/commands/print.rs similarity index 100% rename from cli/src/commands/print.rs rename to crates/cli/src/commands/print.rs diff --git a/cli/src/commands/remove.rs b/crates/cli/src/commands/remove.rs similarity index 100% rename from cli/src/commands/remove.rs rename to crates/cli/src/commands/remove.rs diff --git a/cli/src/commands/utils.rs b/crates/cli/src/commands/utils.rs similarity index 100% rename from cli/src/commands/utils.rs rename to crates/cli/src/commands/utils.rs diff --git a/cli/src/logging.rs b/crates/cli/src/logging.rs similarity index 100% rename from cli/src/logging.rs rename to crates/cli/src/logging.rs diff --git a/cli/src/main.rs b/crates/cli/src/main.rs similarity index 100% rename from cli/src/main.rs rename to crates/cli/src/main.rs diff --git a/crates/meowy-assets/Cargo.toml b/crates/meowy-assets/Cargo.toml new file mode 100644 index 0000000..1f29b66 --- /dev/null +++ b/crates/meowy-assets/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "meowy-assets" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hex = "0.4" + +[dependencies.rocket] +version = "=0.5.0-rc.3" +default-features = false + +[dependencies.askama_rocket] +git = "https://github.com/djc/askama.git" +package = "askama_rocket" +rev = "b9e51601560398766eac445517fb17c35090a952" +default-features = false + +[dependencies.askama] +git = "https://github.com/djc/askama.git" +package = "askama" +rev = "b9e51601560398766eac445517fb17c35090a952" +version = "0.12" +default-features = false + +[dependencies.rust-embed] +version = "6" +features = ["debug-embed"] + +[dependencies.sha2] +version = "0.10" +features = ["asm"] + +[dependencies.shared] +path = "../shared" + +[dependencies.proc_macros] +path = "../proc-macros" diff --git a/public/atkinson-hyperlegible-all-400-normal.woff b/crates/meowy-assets/public/atkinson-hyperlegible-all-400-normal.woff similarity index 100% rename from public/atkinson-hyperlegible-all-400-normal.woff rename to crates/meowy-assets/public/atkinson-hyperlegible-all-400-normal.woff diff --git a/public/atkinson-hyperlegible-latin-400-normal.woff2 b/crates/meowy-assets/public/atkinson-hyperlegible-latin-400-normal.woff2 similarity index 100% rename from public/atkinson-hyperlegible-latin-400-normal.woff2 rename to crates/meowy-assets/public/atkinson-hyperlegible-latin-400-normal.woff2 diff --git a/public/atkinson-hyperlegible-latin-ext-400-normal.woff2 b/crates/meowy-assets/public/atkinson-hyperlegible-latin-ext-400-normal.woff2 similarity index 100% rename from public/atkinson-hyperlegible-latin-ext-400-normal.woff2 rename to crates/meowy-assets/public/atkinson-hyperlegible-latin-ext-400-normal.woff2 diff --git a/public/style.css b/crates/meowy-assets/public/style.css similarity index 100% rename from public/style.css rename to crates/meowy-assets/public/style.css diff --git a/crates/meowy-assets/src/files.rs b/crates/meowy-assets/src/files.rs new file mode 100644 index 0000000..c71bbf8 --- /dev/null +++ b/crates/meowy-assets/src/files.rs @@ -0,0 +1,148 @@ +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)] +#[folder = "public/"] +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, +} + +#[derive(Debug, Clone)] +pub struct FileMetadata { + pub filename: String, + pub extension: String, + pub hash: String, +} + +impl FileMetadata { + pub fn get_hash_filename(&self) -> String { + let mut hash = self.hash.clone(); + hash.truncate(8); + format!("{}.{}.{}", self.filename, hash, self.extension) + } +} + +#[derive(Debug)] +pub struct BinaryFile { + pub data: Cow<'static, [u8]>, + pub metadata: FileMetadata, +} + +#[derive(Debug, Clone)] +pub struct TextFile { + pub text: String, + 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, + }) + } + 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> { + match FILES.get() { + Some(files) => Ok(files), + None => Err(Status::InternalServerError), + } +} + +fn get_sha256_hash(string: &String) -> String { + let mut hasher = Sha256::new(); + hasher.update(string); + let result = hasher.finalize(); + hex::encode(result) +} + +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 { + 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/crates/meowy-assets/src/lib.rs similarity index 71% rename from src/assets/mod.rs rename to crates/meowy-assets/src/lib.rs index 2e4d45e..984cfc6 100644 --- a/src/assets/mod.rs +++ b/crates/meowy-assets/src/lib.rs @@ -1,7 +1,11 @@ pub mod files; +mod responders; mod routes; pub mod templates; +#[macro_use] +extern crate rocket; + pub use routes::style; pub use routes::woff2_font; pub use routes::woff_font; diff --git a/crates/meowy-assets/src/responders.rs b/crates/meowy-assets/src/responders.rs new file mode 100644 index 0000000..15b6b73 --- /dev/null +++ b/crates/meowy-assets/src/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 { + Self { inner: value } + } +} diff --git a/crates/meowy-assets/src/routes.rs b/crates/meowy-assets/src/routes.rs new file mode 100644 index 0000000..b53a3d0 --- /dev/null +++ b/crates/meowy-assets/src/routes.rs @@ -0,0 +1,51 @@ +use crate::{ + files::get_file_wrapper, + responders::{CachedResponse, RawWoff2Font, RawWoffFont}, +}; +use rocket::{http::Status, response::content::RawCss}; + +#[get("/css/ - - {% endblock %} - - - {% block content %} - {% endblock %} - -