2024-06-30 22:47:28 +03:00
|
|
|
#![allow(dead_code)]
|
|
|
|
|
|
2025-06-29 15:18:43 +03:00
|
|
|
use std::{collections::HashMap, fs, path::PathBuf, sync::LazyLock};
|
2025-06-25 13:44:08 +03:00
|
|
|
|
2025-06-24 19:56:47 +03:00
|
|
|
use askama::Template;
|
2025-06-25 13:44:08 +03:00
|
|
|
use blake3::{Hash, Hasher};
|
2024-06-30 22:47:28 +03:00
|
|
|
use tracing_subscriber::EnvFilter;
|
|
|
|
|
|
2025-06-24 19:56:47 +03:00
|
|
|
mod common;
|
|
|
|
|
|
2025-01-31 14:50:31 +02:00
|
|
|
#[cfg(feature = "bbs")]
|
2024-09-28 16:32:23 +03:00
|
|
|
mod bbs;
|
2025-01-31 14:50:31 +02:00
|
|
|
|
|
|
|
|
#[cfg(feature = "ddd")]
|
2024-09-29 02:15:18 +03:00
|
|
|
mod ddd;
|
2025-01-31 14:50:31 +02:00
|
|
|
|
2025-06-25 02:15:27 +03:00
|
|
|
#[cfg(feature = "kh1")]
|
|
|
|
|
mod kh1;
|
|
|
|
|
|
2025-02-08 13:35:55 +02:00
|
|
|
#[cfg(feature = "kh2")]
|
|
|
|
|
mod kh2;
|
|
|
|
|
|
2025-01-31 14:50:31 +02:00
|
|
|
#[cfg(feature = "kh3")]
|
2025-01-27 14:55:10 +02:00
|
|
|
mod kh3;
|
2024-06-30 22:47:28 +03:00
|
|
|
|
2024-07-01 18:24:37 +03:00
|
|
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
2025-06-28 00:47:43 +03:00
|
|
|
pub const ASSETS_FOLDER_PATH: &str = "./public/assets";
|
2025-06-29 15:18:43 +03:00
|
|
|
pub const SCRIPTS_FOLDER_PATH: &str = "./public/scripts";
|
2025-06-29 16:20:23 +03:00
|
|
|
pub const STYLES_FOLDER_PATH: &str = "./public/styles";
|
2025-06-29 15:18:43 +03:00
|
|
|
static FILE_HASHES: LazyLock<HashMap<String, Hash>> = LazyLock::new(|| {
|
|
|
|
|
let mut map = HashMap::new();
|
|
|
|
|
|
|
|
|
|
fn parse_path(path: PathBuf, map: &mut HashMap<String, Hash>) {
|
|
|
|
|
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()) {
|
|
|
|
|
parse_path(path, map);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let dir = path.parent().unwrap().to_str().unwrap();
|
|
|
|
|
let path = path.to_str().unwrap();
|
|
|
|
|
let is_module = path.contains("/common");
|
|
|
|
|
|
|
|
|
|
let mut hasher = Hasher::new();
|
|
|
|
|
hash_file(path.to_string().into(), &mut hasher);
|
|
|
|
|
if !is_module {
|
|
|
|
|
hash_files_in_dir(format!("{dir}/common").into(), &mut hasher);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let hash = hasher.finalize();
|
|
|
|
|
map.insert(path.to_string(), hash);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parse_path(SCRIPTS_FOLDER_PATH.into(), &mut map);
|
2025-06-29 16:20:23 +03:00
|
|
|
parse_path(STYLES_FOLDER_PATH.into(), &mut map);
|
2025-06-29 15:18:43 +03:00
|
|
|
|
|
|
|
|
map
|
|
|
|
|
});
|
2024-06-30 22:47:28 +03:00
|
|
|
|
2025-06-25 13:44:08 +03:00
|
|
|
pub trait RuntimeModule {
|
|
|
|
|
fn start_module();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-31 14:50:31 +02:00
|
|
|
#[derive(Template)]
|
|
|
|
|
#[template(path = "pages/index.html")]
|
|
|
|
|
struct IndexTemplate {}
|
|
|
|
|
|
2024-06-30 22:47:28 +03:00
|
|
|
fn main() {
|
|
|
|
|
// Initialize tracing
|
|
|
|
|
tracing_subscriber::fmt()
|
|
|
|
|
.with_env_filter(EnvFilter::from_default_env())
|
|
|
|
|
.event_format(tracing_subscriber::fmt::format().with_source_location(true))
|
|
|
|
|
.init();
|
|
|
|
|
|
2025-01-31 14:50:31 +02:00
|
|
|
tracing::info!("Generating the main menu template");
|
|
|
|
|
let template = IndexTemplate {};
|
|
|
|
|
|
|
|
|
|
std::fs::write("./out/index.html", template.render().unwrap()).unwrap();
|
2025-02-10 00:47:36 +02:00
|
|
|
std::process::Command::new("cp")
|
|
|
|
|
.args(["-r", "./assets", "./out"])
|
|
|
|
|
.output()
|
|
|
|
|
.unwrap();
|
2025-01-31 14:50:31 +02:00
|
|
|
|
|
|
|
|
#[cfg(feature = "bbs")]
|
2025-06-25 13:44:08 +03:00
|
|
|
start_module::<bbs::Module>();
|
2025-01-31 14:50:31 +02:00
|
|
|
|
|
|
|
|
#[cfg(feature = "ddd")]
|
2025-06-25 13:44:08 +03:00
|
|
|
start_module::<ddd::Module>();
|
2025-01-31 14:50:31 +02:00
|
|
|
|
2025-06-25 02:15:27 +03:00
|
|
|
#[cfg(feature = "kh1")]
|
2025-06-25 13:44:08 +03:00
|
|
|
start_module::<kh1::Module>();
|
2025-06-25 02:15:27 +03:00
|
|
|
|
2025-02-08 13:35:55 +02:00
|
|
|
#[cfg(feature = "kh2")]
|
2025-06-25 13:44:08 +03:00
|
|
|
start_module::<kh2::Module>();
|
2025-02-08 13:35:55 +02:00
|
|
|
|
2025-01-31 14:50:31 +02:00
|
|
|
#[cfg(feature = "kh3")]
|
2025-06-25 13:44:08 +03:00
|
|
|
start_module::<kh3::Module>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn start_module<M: RuntimeModule>() {
|
|
|
|
|
M::start_module();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-29 15:18:43 +03:00
|
|
|
fn find_hash(file: &str) -> String {
|
|
|
|
|
let map = &*FILE_HASHES;
|
|
|
|
|
let hash = map.get(&format!(".{file}"));
|
|
|
|
|
if let Some(hash) = hash {
|
|
|
|
|
return format!("{file}?hash={hash}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file.to_string()
|
2025-06-25 13:44:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2024-06-30 22:47:28 +03:00
|
|
|
}
|
2025-01-31 15:06:04 +02:00
|
|
|
|
2025-06-29 14:03:58 +03:00
|
|
|
fn create_file(dir: &str, file: &str, buf: impl Template) -> std::io::Result<()> {
|
2025-01-31 15:06:04 +02:00
|
|
|
std::fs::create_dir_all(dir)?;
|
2025-06-29 14:03:58 +03:00
|
|
|
std::fs::write(format!("{}/{}.html", dir, file), buf.render().unwrap())?;
|
2025-01-31 15:06:04 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|