Added JS hashes for better browser caching
parent
630439bc48
commit
fd33426219
|
@ -11,6 +11,7 @@ toml = "0.8"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
itertools = "0.14"
|
itertools = "0.14"
|
||||||
|
blake3 = "1.8"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["bbs", "ddd", "kh3", "kh2", "kh1"]
|
default = ["bbs", "ddd", "kh3", "kh2", "kh1"]
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import {
|
||||||
|
kindFilter,
|
||||||
|
showOnlyTracked,
|
||||||
|
track,
|
||||||
|
} from "./modules/common/mat-kind-filter.js";
|
||||||
|
|
||||||
|
Object.assign(window, { track });
|
16
src/bbs.rs
16
src/bbs.rs
|
@ -1,13 +1,14 @@
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, sync::OnceLock};
|
||||||
|
|
||||||
use ability::Ability;
|
use ability::Ability;
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use blake3::Hash;
|
||||||
use command::Command;
|
use command::Command;
|
||||||
use finisher::Finisher;
|
use finisher::Finisher;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::create_file;
|
use crate::{RuntimeModule, create_file, create_hashes};
|
||||||
|
|
||||||
mod ability;
|
mod ability;
|
||||||
mod command;
|
mod command;
|
||||||
|
@ -17,6 +18,7 @@ mod melding;
|
||||||
const ABILITIES_PATH: &str = "./input/bbs/abilities.json";
|
const ABILITIES_PATH: &str = "./input/bbs/abilities.json";
|
||||||
const FINISHERS_PATH: &str = "./input/bbs/finish-commands.json";
|
const FINISHERS_PATH: &str = "./input/bbs/finish-commands.json";
|
||||||
const COMMANDS_PATH: &str = "./input/bbs/commands.json";
|
const COMMANDS_PATH: &str = "./input/bbs/commands.json";
|
||||||
|
static JS_HASH: OnceLock<Hash> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||||
enum Character {
|
enum Character {
|
||||||
|
@ -35,7 +37,10 @@ struct CommandsTemplate {
|
||||||
pub crystals: Vec<String>,
|
pub crystals: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub struct Module;
|
||||||
|
|
||||||
|
impl RuntimeModule for Module {
|
||||||
|
fn start_module() {
|
||||||
tracing::info!("Loading abilities data from {}", ABILITIES_PATH);
|
tracing::info!("Loading abilities data from {}", ABILITIES_PATH);
|
||||||
let abilities_str = std::fs::read_to_string(ABILITIES_PATH).unwrap();
|
let abilities_str = std::fs::read_to_string(ABILITIES_PATH).unwrap();
|
||||||
let abilities = serde_json::from_str::<Vec<Ability>>(&abilities_str).unwrap();
|
let abilities = serde_json::from_str::<Vec<Ability>>(&abilities_str).unwrap();
|
||||||
|
@ -67,4 +72,9 @@ pub fn init() {
|
||||||
let melding_template = CommandsTemplate { commands, crystals };
|
let melding_template = CommandsTemplate { commands, crystals };
|
||||||
|
|
||||||
create_file("./out/bbs", "melding", melding_template.render().unwrap()).unwrap();
|
create_file("./out/bbs", "melding", melding_template.render().unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_js_hash() -> String {
|
||||||
|
JS_HASH.get_or_init(|| create_hashes("bbs")).to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/ddd.rs
16
src/ddd.rs
|
@ -1,8 +1,10 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use crate::create_file;
|
|
||||||
use crate::ddd::ability::AbilityType;
|
use crate::ddd::ability::AbilityType;
|
||||||
|
use crate::{RuntimeModule, create_file, create_hashes};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use blake3::Hash;
|
||||||
use board::Board;
|
use board::Board;
|
||||||
|
|
||||||
mod ability;
|
mod ability;
|
||||||
|
@ -11,6 +13,7 @@ mod board_position;
|
||||||
mod route;
|
mod route;
|
||||||
|
|
||||||
const ABILITIES_PATH: &str = "./input/ddd/abilities";
|
const ABILITIES_PATH: &str = "./input/ddd/abilities";
|
||||||
|
static JS_HASH: OnceLock<Hash> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "pages/ddd/boards.html")]
|
#[template(path = "pages/ddd/boards.html")]
|
||||||
|
@ -18,7 +21,10 @@ struct AbilitiesTemplate {
|
||||||
pub boards: Vec<Board>,
|
pub boards: Vec<Board>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub struct Module;
|
||||||
|
|
||||||
|
impl RuntimeModule for Module {
|
||||||
|
fn start_module() {
|
||||||
tracing::info!("Loading ability boards data from {}", ABILITIES_PATH);
|
tracing::info!("Loading ability boards data from {}", ABILITIES_PATH);
|
||||||
let mut boards: Vec<Board> = vec![];
|
let mut boards: Vec<Board> = vec![];
|
||||||
// Loading multiple files into one vector due to the size of each board
|
// Loading multiple files into one vector due to the size of each board
|
||||||
|
@ -42,7 +48,6 @@ pub fn init() {
|
||||||
board.init_stats();
|
board.init_stats();
|
||||||
board.init_ability_help();
|
board.init_ability_help();
|
||||||
|
|
||||||
// dbg!(&board);
|
|
||||||
boards.push(board);
|
boards.push(board);
|
||||||
}
|
}
|
||||||
boards.sort_by(|a, b| a.order.cmp(&b.order));
|
boards.sort_by(|a, b| a.order.cmp(&b.order));
|
||||||
|
@ -51,4 +56,9 @@ pub fn init() {
|
||||||
let boards_template = AbilitiesTemplate { boards };
|
let boards_template = AbilitiesTemplate { boards };
|
||||||
|
|
||||||
create_file("./out/ddd", "boards", boards_template.render().unwrap()).unwrap();
|
create_file("./out/ddd", "boards", boards_template.render().unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_js_hash() -> String {
|
||||||
|
JS_HASH.get_or_init(|| create_hashes("ddd")).to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/kh1.rs
16
src/kh1.rs
|
@ -1,14 +1,16 @@
|
||||||
use std::path::PathBuf;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use blake3::Hash;
|
||||||
|
|
||||||
use crate::{common::materials::MaterialDrops, create_file};
|
use crate::{RuntimeModule, common::materials::MaterialDrops, create_file, create_hashes};
|
||||||
|
|
||||||
const MATERIAL_KINDS: &[&str] = &[
|
const MATERIAL_KINDS: &[&str] = &[
|
||||||
"lucid", "spirit", "power", "blaze", "frost", "thunder", "shiny", "bright", "mystery", "gale",
|
"lucid", "spirit", "power", "blaze", "frost", "thunder", "shiny", "bright", "mystery", "gale",
|
||||||
"mythril",
|
"mythril",
|
||||||
];
|
];
|
||||||
const DROPS_PATH: &str = "./input/kh1/drops";
|
const DROPS_PATH: &str = "./input/kh1/drops";
|
||||||
|
static JS_HASH: OnceLock<Hash> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "pages/kh1/drops.html")]
|
#[template(path = "pages/kh1/drops.html")]
|
||||||
|
@ -16,7 +18,10 @@ struct DropsTemplate {
|
||||||
pub drops: Vec<MaterialDrops>,
|
pub drops: Vec<MaterialDrops>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub struct Module;
|
||||||
|
|
||||||
|
impl RuntimeModule for Module {
|
||||||
|
fn start_module() {
|
||||||
tracing::info!("Loading enemy drops data from {}", DROPS_PATH);
|
tracing::info!("Loading enemy drops data from {}", DROPS_PATH);
|
||||||
let drops = MaterialDrops::import(DROPS_PATH);
|
let drops = MaterialDrops::import(DROPS_PATH);
|
||||||
|
|
||||||
|
@ -24,4 +29,9 @@ pub fn init() {
|
||||||
let drops_template = DropsTemplate { drops };
|
let drops_template = DropsTemplate { drops };
|
||||||
|
|
||||||
create_file("./out/kh1", "drops", drops_template.render().unwrap()).unwrap();
|
create_file("./out/kh1", "drops", drops_template.render().unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_js_hash() -> String {
|
||||||
|
JS_HASH.get_or_init(|| create_hashes("kh1")).to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/kh2.rs
16
src/kh2.rs
|
@ -1,8 +1,9 @@
|
||||||
use std::path::PathBuf;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use blake3::Hash;
|
||||||
|
|
||||||
use crate::{common::materials::MaterialDrops, create_file};
|
use crate::{RuntimeModule, common::materials::MaterialDrops, create_file, create_hashes};
|
||||||
|
|
||||||
const MATERIAL_KINDS: &[&str] = &[
|
const MATERIAL_KINDS: &[&str] = &[
|
||||||
"blazing",
|
"blazing",
|
||||||
|
@ -19,6 +20,7 @@ const MATERIAL_KINDS: &[&str] = &[
|
||||||
"twilight",
|
"twilight",
|
||||||
];
|
];
|
||||||
const DROPS_PATH: &str = "./input/kh2/drops";
|
const DROPS_PATH: &str = "./input/kh2/drops";
|
||||||
|
static JS_HASH: OnceLock<Hash> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "pages/kh2/drops.html")]
|
#[template(path = "pages/kh2/drops.html")]
|
||||||
|
@ -26,7 +28,10 @@ struct DropsTemplate {
|
||||||
pub drops: Vec<MaterialDrops>,
|
pub drops: Vec<MaterialDrops>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub struct Module;
|
||||||
|
|
||||||
|
impl RuntimeModule for Module {
|
||||||
|
fn start_module() {
|
||||||
tracing::info!("Loading enemy drops data from {}", DROPS_PATH);
|
tracing::info!("Loading enemy drops data from {}", DROPS_PATH);
|
||||||
let drops = MaterialDrops::import(DROPS_PATH);
|
let drops = MaterialDrops::import(DROPS_PATH);
|
||||||
|
|
||||||
|
@ -34,4 +39,9 @@ pub fn init() {
|
||||||
let drops_template = DropsTemplate { drops };
|
let drops_template = DropsTemplate { drops };
|
||||||
|
|
||||||
create_file("./out/kh2", "drops", drops_template.render().unwrap()).unwrap();
|
create_file("./out/kh2", "drops", drops_template.render().unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_js_hash() -> String {
|
||||||
|
JS_HASH.get_or_init(|| create_hashes("kh2")).to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/kh3.rs
16
src/kh3.rs
|
@ -1,11 +1,15 @@
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use blake3::Hash;
|
||||||
use food::Recipes;
|
use food::Recipes;
|
||||||
|
|
||||||
use crate::create_file;
|
use crate::{RuntimeModule, create_file, create_hashes};
|
||||||
|
|
||||||
mod food;
|
mod food;
|
||||||
|
|
||||||
const RECIPES_PATH: &str = "./input/kh3/recipes.toml";
|
const RECIPES_PATH: &str = "./input/kh3/recipes.toml";
|
||||||
|
static JS_HASH: OnceLock<Hash> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "pages/kh3/food-sim.html")]
|
#[template(path = "pages/kh3/food-sim.html")]
|
||||||
|
@ -13,7 +17,10 @@ struct RecipesTemplate {
|
||||||
pub recipes: Recipes,
|
pub recipes: Recipes,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub struct Module;
|
||||||
|
|
||||||
|
impl RuntimeModule for Module {
|
||||||
|
fn start_module() {
|
||||||
tracing::info!("Loading recipes data from {}", RECIPES_PATH);
|
tracing::info!("Loading recipes data from {}", RECIPES_PATH);
|
||||||
let recipes_str = std::fs::read_to_string(RECIPES_PATH).unwrap();
|
let recipes_str = std::fs::read_to_string(RECIPES_PATH).unwrap();
|
||||||
let recipes = toml::from_str::<Recipes>(&recipes_str).unwrap();
|
let recipes = toml::from_str::<Recipes>(&recipes_str).unwrap();
|
||||||
|
@ -22,4 +29,9 @@ pub fn init() {
|
||||||
let food_template = RecipesTemplate { recipes };
|
let food_template = RecipesTemplate { recipes };
|
||||||
|
|
||||||
create_file("./out/kh3", "food-sim", food_template.render().unwrap()).unwrap();
|
create_file("./out/kh3", "food-sim", food_template.render().unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_js_hash() -> String {
|
||||||
|
JS_HASH.get_or_init(|| create_hashes("kh3")).to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
54
src/main.rs
54
src/main.rs
|
@ -1,6 +1,9 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use blake3::{Hash, Hasher};
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
@ -22,6 +25,12 @@ mod kh3;
|
||||||
|
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
pub trait RuntimeModule {
|
||||||
|
fn start_module();
|
||||||
|
|
||||||
|
fn get_js_hash() -> String;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "pages/index.html")]
|
#[template(path = "pages/index.html")]
|
||||||
struct IndexTemplate {}
|
struct IndexTemplate {}
|
||||||
|
@ -43,19 +52,54 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "bbs")]
|
#[cfg(feature = "bbs")]
|
||||||
bbs::init();
|
start_module::<bbs::Module>();
|
||||||
|
|
||||||
#[cfg(feature = "ddd")]
|
#[cfg(feature = "ddd")]
|
||||||
ddd::init();
|
start_module::<ddd::Module>();
|
||||||
|
|
||||||
#[cfg(feature = "kh1")]
|
#[cfg(feature = "kh1")]
|
||||||
kh1::init();
|
start_module::<kh1::Module>();
|
||||||
|
|
||||||
#[cfg(feature = "kh2")]
|
#[cfg(feature = "kh2")]
|
||||||
kh2::init();
|
start_module::<kh2::Module>();
|
||||||
|
|
||||||
#[cfg(feature = "kh3")]
|
#[cfg(feature = "kh3")]
|
||||||
kh3::init();
|
start_module::<kh3::Module>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_module<M: RuntimeModule>() {
|
||||||
|
M::start_module();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_hashes(module: &str) -> Hash {
|
||||||
|
let mut hasher = blake3::Hasher::new();
|
||||||
|
hash_file(format!("./public/scripts/{module}.js").into(), &mut hasher);
|
||||||
|
hash_files_in_dir("./public/scripts/modules/common".into(), &mut hasher);
|
||||||
|
hash_files_in_dir(
|
||||||
|
format!("./public/scripts/modules/{module}").into(),
|
||||||
|
&mut hasher,
|
||||||
|
);
|
||||||
|
hasher.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_files_in_dir(path: PathBuf, hasher: &mut Hasher) {
|
||||||
|
if let Ok(paths) = fs::read_dir(path) {
|
||||||
|
for path in paths.flatten() {
|
||||||
|
let path = path.path();
|
||||||
|
if path.metadata().is_ok_and(|p| p.is_dir()) {
|
||||||
|
hash_files_in_dir(path, hasher);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_file(path, hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_file(path: PathBuf, hasher: &mut Hasher) {
|
||||||
|
if let Ok(file) = fs::read(path) {
|
||||||
|
hasher.update(&file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_file(dir: &str, file: &str, buf: String) -> std::io::Result<()> {
|
fn create_file(dir: &str, file: &str, buf: String) -> std::io::Result<()> {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<style> {% include "components/bbs/style.css" %}</style>
|
<style> {% include "components/bbs/style.css" %}</style>
|
||||||
<script type="module" src="/public/scripts/bbs.js"></script>
|
<script type="module" src="/public/scripts/bbs.js?v={{Module::get_js_hash()}}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<style>{% include "components/kh2/style.css" %}</style>
|
<style>{% include "components/kh2/style.css" %}</style>
|
||||||
|
<script type="module" src="/public/scripts/kh1.js?v={{Module::get_js_hash()}}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{#
|
{% include "components/common/only-tracked-filter.html" %}
|
||||||
{% include "components/kh2/only-tracked-filter.html" %}
|
|
||||||
<br />
|
<br />
|
||||||
{% include "components/kh2/kind-filters.html" %}
|
{% include "components/common/kind-filters.html" %}
|
||||||
<br />
|
<br />
|
||||||
#}
|
|
||||||
{% for category in drops %}
|
{% for category in drops %}
|
||||||
{% call macros::drop("shard") %}
|
{% call macros::drop("shard") %}
|
||||||
{% call macros::drop("stone") %}
|
{% call macros::drop("stone") %}
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<style>{% include "components/kh2/style.css" %}</style>
|
<style>{% include "components/kh2/style.css" %}</style>
|
||||||
<script type="module" src="/public/scripts/kh2.js"></script>
|
<script type="module" src="/public/scripts/kh2.js?v={{Module::get_js_hash()}}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include "components/kh2/only-tracked-filter.html" %}
|
{% include "components/common/only-tracked-filter.html" %}
|
||||||
<br />
|
<br />
|
||||||
{% include "components/kh2/kind-filters.html" %}
|
{% include "components/common/kind-filters.html" %}
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{% for category in drops %}
|
{% for category in drops %}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<style>{% include "components/kh3/style.css" %}</style>
|
<style>{% include "components/kh3/style.css" %}</style>
|
||||||
<script type="module" src="/public/scripts/kh3.js"></script>
|
<script type="module" src="/public/scripts/kh3.js?v={{Module::get_js_hash()}}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
Loading…
Reference in New Issue