Use a hashmap for asset files and clean up index code.
technically, the file structs are stored in a vector but the hashmaps contain the index so I can ask the hashmap for the index via the filename or hashed filename string.
This commit is contained in:
parent
b8682f3960
commit
132dcdf412
|
@ -3,7 +3,7 @@ use askama::Template;
|
|||
use rocket::http::Status;
|
||||
use rust_embed::RustEmbed;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{borrow::Cow, sync::OnceLock};
|
||||
use std::{collections::HashMap, sync::OnceLock};
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "public/"]
|
||||
|
@ -11,11 +11,32 @@ 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,
|
||||
file_vector: Vec<File>,
|
||||
hash_filename_dictionary: HashMap<String, usize>,
|
||||
filename_dictionary: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl Files {
|
||||
pub fn hash_filename_get(&self, name: &str) -> Option<&File> {
|
||||
match self.hash_filename_dictionary.get(name) {
|
||||
Some(index) => Some(&self.file_vector[*index]),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
pub fn filename_get(&self, name: &str) -> Option<&File> {
|
||||
match self.filename_dictionary.get(name) {
|
||||
Some(index) => Some(&self.file_vector[*index]),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
pub fn insert_file_into_hashmap(&mut self, file: File) {
|
||||
let index = self.file_vector.len();
|
||||
self.hash_filename_dictionary
|
||||
.insert(file.metadata.get_hash_filename(), index);
|
||||
self.filename_dictionary
|
||||
.insert(file.metadata.filename.clone(), index);
|
||||
self.file_vector.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -34,25 +55,16 @@ impl FileMetadata {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinaryFile {
|
||||
pub data: Cow<'static, [u8]>,
|
||||
pub struct File {
|
||||
pub metadata: FileMetadata,
|
||||
data: Box<[u8]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TextFile {
|
||||
pub text: String,
|
||||
pub metadata: FileMetadata,
|
||||
}
|
||||
|
||||
trait GetFile {
|
||||
impl File {
|
||||
fn get(filename: &str, extension: &str) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl GetFile for BinaryFile {
|
||||
fn get(filename: &str, extension: &str) -> Option<Self> {
|
||||
Self: Sized,
|
||||
{
|
||||
match Assets::get(&format!("{}.{}", filename, extension)) {
|
||||
Some(file) => {
|
||||
let metadata = FileMetadata {
|
||||
|
@ -60,24 +72,22 @@ impl GetFile for BinaryFile {
|
|||
extension: extension.into(),
|
||||
hash: hex::encode(file.metadata.sha256_hash()),
|
||||
};
|
||||
Some(BinaryFile {
|
||||
data: file.data,
|
||||
Some(File {
|
||||
data: file.data.into(),
|
||||
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,
|
||||
}),
|
||||
pub fn get_data(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn get_text(&self) -> Option<String> {
|
||||
match std::str::from_utf8(&self.data) {
|
||||
Ok(str) => Some(str.into()),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +113,7 @@ fn get_hyperlegible(
|
|||
latin_woff2_filename: String,
|
||||
latin_ext_woff2_filename: String,
|
||||
all_woff_filename: String,
|
||||
) -> TextFile {
|
||||
) -> File {
|
||||
let hyperlegible_template = HyperlegibleTemplate {
|
||||
atkinson_latin_woff2_filename: latin_woff2_filename,
|
||||
atkinson_latin_ext_woff2_filename: latin_ext_woff2_filename,
|
||||
|
@ -119,30 +129,32 @@ fn get_hyperlegible(
|
|||
hash,
|
||||
};
|
||||
|
||||
TextFile {
|
||||
text: rendered_template,
|
||||
File {
|
||||
data: rendered_template.as_bytes().into(),
|
||||
metadata,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_files() {
|
||||
pub fn initialize_files() -> Result<(), Files> {
|
||||
let atkinson_latin_woff2 =
|
||||
BinaryFile::get("atkinson-hyperlegible-latin-400-normal", "woff2").unwrap();
|
||||
File::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();
|
||||
File::get("atkinson-hyperlegible-latin-ext-400-normal", "woff2").unwrap();
|
||||
let atkinson_all_woff = File::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,
|
||||
let mut files = Files {
|
||||
file_vector: Vec::new(),
|
||||
hash_filename_dictionary: HashMap::new(),
|
||||
filename_dictionary: HashMap::new(),
|
||||
};
|
||||
FILES.set(files).unwrap();
|
||||
files.insert_file_into_hashmap(File::get("style", "css").unwrap());
|
||||
files.insert_file_into_hashmap(get_hyperlegible(
|
||||
atkinson_latin_woff2.metadata.get_hash_filename(),
|
||||
atkinson_latin_ext_woff2.metadata.get_hash_filename(),
|
||||
atkinson_all_woff.metadata.get_hash_filename(),
|
||||
));
|
||||
files.insert_file_into_hashmap(atkinson_latin_woff2);
|
||||
files.insert_file_into_hashmap(atkinson_latin_ext_woff2);
|
||||
files.insert_file_into_hashmap(atkinson_all_woff);
|
||||
return FILES.set(files);
|
||||
}
|
||||
|
|
|
@ -4,15 +4,14 @@ use rocket::{
|
|||
response::{self, Responder},
|
||||
Response,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = 200, content_type = "font/woff2")]
|
||||
pub struct RawWoff2Font(pub Cow<'static, [u8]>);
|
||||
pub struct RawWoff2Font(pub &'static [u8]);
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = 200, content_type = "font/woff")]
|
||||
pub struct RawWoffFont(pub Cow<'static, [u8]>);
|
||||
pub struct RawWoffFont(pub &'static [u8]);
|
||||
|
||||
#[derive(Responder)]
|
||||
pub struct ErrorTemplateResponder<'a> {
|
||||
|
|
|
@ -6,46 +6,45 @@ use rocket::{http::Status, response::content::RawCss};
|
|||
|
||||
#[get("/css/<style>")]
|
||||
pub fn style(style: &str) -> Result<CachedResponse<RawCss<String>>, Status> {
|
||||
let style_file = &get_file_wrapper()?.style;
|
||||
let hyperlegible_file = &get_file_wrapper()?.hyperlegible;
|
||||
|
||||
let style_name = style_file.metadata.get_hash_filename();
|
||||
let hyperlegible_name = hyperlegible_file.metadata.get_hash_filename();
|
||||
|
||||
if style == style_name {
|
||||
Ok(RawCss::<String>(style_file.text.clone()).into())
|
||||
} else if style == hyperlegible_name {
|
||||
Ok(RawCss::<String>(hyperlegible_file.text.clone()).into())
|
||||
} else {
|
||||
Err(Status::NotFound)
|
||||
let file_wrapper = get_file_wrapper()?;
|
||||
match file_wrapper.hash_filename_get(style) {
|
||||
Some(style) => {
|
||||
if style.metadata.extension != "css" {
|
||||
return Err(Status::NotFound);
|
||||
}
|
||||
match style.get_text() {
|
||||
Some(text) => Ok(RawCss::<String>(text).into()),
|
||||
None => Err(Status::NotFound),
|
||||
}
|
||||
}
|
||||
None => Err(Status::NotFound),
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/woff2/<font>")]
|
||||
pub fn woff2_font(font: &str) -> Result<CachedResponse<RawWoff2Font>, Status> {
|
||||
let latin_file = &get_file_wrapper()?.atkinson_latin_woff2;
|
||||
let latin_ext_file = &get_file_wrapper()?.atkinson_latin_ext_woff2;
|
||||
|
||||
let latin = latin_file.metadata.get_hash_filename();
|
||||
let latin_ext = latin_file.metadata.get_hash_filename();
|
||||
|
||||
if font == latin {
|
||||
Ok(RawWoff2Font(latin_file.data.clone()).into())
|
||||
} else if font == latin_ext {
|
||||
Ok(RawWoff2Font(latin_ext_file.data.clone()).into())
|
||||
} else {
|
||||
Err(Status::NotFound)
|
||||
let file_wrapper = get_file_wrapper()?;
|
||||
match file_wrapper.hash_filename_get(font) {
|
||||
Some(font) => {
|
||||
if font.metadata.extension != "woff2" {
|
||||
return Err(Status::NotFound);
|
||||
}
|
||||
Ok(RawWoff2Font(font.get_data()).into())
|
||||
}
|
||||
None => Err(Status::NotFound),
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/woff/<font>")]
|
||||
pub fn woff_font(font: &str) -> Result<CachedResponse<RawWoffFont>, Status> {
|
||||
let all_file = &get_file_wrapper()?.atkinson_all_woff;
|
||||
let all = all_file.metadata.get_hash_filename();
|
||||
|
||||
if font == all {
|
||||
Ok(RawWoffFont(all_file.data.clone()).into())
|
||||
} else {
|
||||
Err(Status::NotFound)
|
||||
let file_wrapper = get_file_wrapper()?;
|
||||
match file_wrapper.hash_filename_get(font) {
|
||||
Some(font) => {
|
||||
if font.metadata.extension != "woff" {
|
||||
return Err(Status::NotFound);
|
||||
}
|
||||
Ok(RawWoffFont(font.get_data()).into())
|
||||
}
|
||||
None => Err(Status::NotFound),
|
||||
}
|
||||
}
|
||||
|
|
39
src/links.rs
39
src/links.rs
|
@ -1,9 +1,29 @@
|
|||
use shared::names::Site;
|
||||
|
||||
trait IndexArithmetic {
|
||||
fn index_add(self, length: usize, num: usize) -> usize;
|
||||
fn index_subtract(self, length: usize, num: usize) -> usize;
|
||||
}
|
||||
|
||||
impl IndexArithmetic for usize {
|
||||
fn index_add(self, length: usize, num: usize) -> usize {
|
||||
if self > (length - 1) {
|
||||
return 0;
|
||||
}
|
||||
return self + num;
|
||||
}
|
||||
|
||||
fn index_subtract(self, length: usize, num: usize) -> usize {
|
||||
match self.checked_sub(num) {
|
||||
Some(num) => num,
|
||||
None => length - 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn previous_url(source_url: &String, names: &Vec<Site>) -> Option<String> {
|
||||
match names.iter().position(|r| &r.url == source_url) {
|
||||
Some(index) if index == 0 => Some(names[names.len() - 1].url.to_string()),
|
||||
Some(index) => Some(names[index - 1].url.to_string()),
|
||||
Some(index) => Some(names[index.index_subtract(names.len(), 1)].url.clone()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
@ -11,19 +31,14 @@ pub fn previous_url(source_url: &String, names: &Vec<Site>) -> Option<String> {
|
|||
pub fn next_url(source_url: &String, names: &Vec<Site>) -> Option<String> {
|
||||
// this is gay
|
||||
match names.iter().position(|r| &r.url == source_url) {
|
||||
Some(index) if index == names.len() - 1 => Some(names[0].url.to_string()),
|
||||
Some(index) => Some(names[index + 1].url.to_string()),
|
||||
Some(index) => Some(names[index.index_add(names.len(), 1)].url.clone()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn previous_name(source_url: &String, names: &Vec<Site>) -> Option<String> {
|
||||
match names.iter().position(|r| &r.url == source_url) {
|
||||
Some(index) if index == 0 => match &names[names.len() - 1].name {
|
||||
Some(name) => Some(name.clone()),
|
||||
None => previous_url(source_url, names),
|
||||
},
|
||||
Some(index) => match &names[index - 1].name {
|
||||
Some(index) => match &names[index.index_subtract(names.len(), 1)].name {
|
||||
Some(name) => Some(name.clone()),
|
||||
None => previous_url(source_url, names),
|
||||
},
|
||||
|
@ -33,11 +48,7 @@ pub fn previous_name(source_url: &String, names: &Vec<Site>) -> Option<String> {
|
|||
|
||||
pub fn next_name(source_url: &String, names: &Vec<Site>) -> Option<String> {
|
||||
match names.iter().position(|r| &r.url == source_url) {
|
||||
Some(index) if index == names.len() - 1 => match &names[0].name {
|
||||
Some(name) => Some(name.clone()),
|
||||
None => next_url(source_url, names),
|
||||
},
|
||||
Some(index) => match &names[index + 1].name {
|
||||
Some(index) => match &names[index.index_add(names.len(), 1)].name {
|
||||
Some(name) => Some(name.clone()),
|
||||
None => next_url(source_url, names),
|
||||
},
|
||||
|
|
|
@ -15,7 +15,7 @@ mod watcher;
|
|||
#[launch]
|
||||
async fn rocket() -> _ {
|
||||
init_names().unwrap();
|
||||
initialize_files();
|
||||
initialize_files().unwrap();
|
||||
tokio::task::spawn_blocking(hot_reloading);
|
||||
|
||||
rocket::build()
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
sites::get_global_names,
|
||||
};
|
||||
use meowy_assets::{
|
||||
files::{get_file_wrapper, FileMetadata},
|
||||
files::{get_file_wrapper, File},
|
||||
templates::{BaseTemplate, ErrorTemplate, IndexTemplate},
|
||||
};
|
||||
use rocket::{
|
||||
|
@ -13,15 +13,18 @@ use rocket::{
|
|||
serde::{json::Json, Serialize},
|
||||
};
|
||||
|
||||
fn get_hash_filename(metadata: &FileMetadata) -> Result<String, Status> {
|
||||
Ok(metadata.get_hash_filename())
|
||||
fn get_file(filename: &str) -> Result<&File, Status> {
|
||||
let files = get_file_wrapper()?;
|
||||
|
||||
match files.filename_get(filename) {
|
||||
Some(file) => Ok(file),
|
||||
None => Err(Status::NotFound),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_base_template() -> Result<BaseTemplate, Status> {
|
||||
let files = get_file_wrapper()?;
|
||||
|
||||
let hyperlegible_filename = get_hash_filename(&files.hyperlegible.metadata)?;
|
||||
let style_filename = get_hash_filename(&files.style.metadata)?;
|
||||
let hyperlegible_filename = get_file("hyperlegible")?.metadata.get_hash_filename();
|
||||
let style_filename = get_file("style")?.metadata.get_hash_filename();
|
||||
|
||||
let template = BaseTemplate {
|
||||
hyperlegible_filename,
|
||||
|
|
Loading…
Reference in a new issue