meowy-webring/crates/meowy-assets/src/files.rs

149 lines
3.5 KiB
Rust

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<Self>
where
Self: Sized;
}
impl GetFile for BinaryFile {
fn get(filename: &str, extension: &str) -> Option<Self> {
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<Self> {
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<Files> = 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();
}