feat(backend): load vehicle translation + icon caches

This commit is contained in:
FURRO404
2026-06-18 00:24:38 -07:00
parent 6745a2ff81
commit 8965c3c19b
+103
View File
@@ -29,6 +29,8 @@ struct AppState {
battles_db: PathBuf,
teams_db: PathBuf,
leaderboard_cache: Mutex<Option<CachedLeaderboard>>,
vehicle_names: HashMap<String, HashMap<String, String>>,
vehicle_icons: HashMap<String, String>,
}
struct CachedLeaderboard {
@@ -317,7 +319,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
battles_db: resolve_db_path("TSS_BATTLES_DB", "tss_battles.db"),
teams_db: resolve_db_path("TSS_TEAMS_DB", "tss_teams.db"),
leaderboard_cache: Mutex::new(None),
vehicle_names: load_vehicle_names(&resolve_db_path(
"VEHICLE_TRANSLATIONS_JSON",
"vehicle_translations.json",
)),
vehicle_icons: load_vehicle_icons(&resolve_db_path(
"VEHICLE_DATA_CACHE_JSON",
"vehicle_data_cache_all.json",
)),
});
tracing::info!(
"loaded {} vehicle name maps, {} vehicle icons",
state.vehicle_names.len(),
state.vehicle_icons.len()
);
spawn_leaderboard_refresh(state.clone());
let app = Router::new()
@@ -1621,6 +1636,54 @@ fn allowed_origins() -> AllowOrigin {
}
}
fn load_vehicle_names(path: &FsPath) -> HashMap<String, HashMap<String, String>> {
match fs::read_to_string(path) {
Ok(s) => serde_json::from_str(&s).unwrap_or_default(),
Err(_) => HashMap::new(),
}
}
fn load_vehicle_icons(path: &FsPath) -> HashMap<String, String> {
// vehicle_data_cache_all.json is [[cdk, name, icon, tags], ...]
let raw: Vec<serde_json::Value> = match fs::read_to_string(path) {
Ok(s) => serde_json::from_str(&s).unwrap_or_default(),
Err(_) => Vec::new(),
};
let mut out = HashMap::new();
for entry in raw {
if let (Some(cdk), Some(icon)) = (
entry.get(0).and_then(|v| v.as_str()),
entry.get(2).and_then(|v| v.as_str()),
) {
out.insert(cdk.to_string(), icon.to_string());
}
}
out
}
fn lookup_vehicle_name(
names: &HashMap<String, HashMap<String, String>>,
cdk: &str,
lang: &str,
) -> String {
if let Some(by_lang) = names.get(cdk) {
if let Some(n) = by_lang.get(lang) {
return n.clone();
}
if let Some(n) = by_lang.get("en") {
return n.clone();
}
}
cdk.to_string()
}
fn lookup_vehicle_icon(icons: &HashMap<String, String>, cdk: &str) -> String {
icons
.get(cdk)
.cloned()
.unwrap_or_else(|| format!("{cdk}.png"))
}
fn resolve_db_path(env_key: &str, default_file: &str) -> PathBuf {
let raw = env::var(env_key).unwrap_or_else(|_| default_file.to_string());
let expanded = expand_home(&raw);
@@ -1702,3 +1765,43 @@ fn load_env_file(path: &FsPath) {
env::set_var(key, value);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vehicle_name_prefers_lang_then_en_then_cdk() {
let mut names = HashMap::new();
let mut t = HashMap::new();
t.insert("en".to_string(), "T-34".to_string());
t.insert("ru".to_string(), "Т-34".to_string());
names.insert("ussr_t_34".to_string(), t);
assert_eq!(lookup_vehicle_name(&names, "ussr_t_34", "ru"), "Т-34");
assert_eq!(lookup_vehicle_name(&names, "ussr_t_34", "de"), "T-34");
assert_eq!(lookup_vehicle_name(&names, "unknown_cdk", "en"), "unknown_cdk");
}
#[test]
fn vehicle_icon_falls_back_to_cdk_png() {
let mut icons = HashMap::new();
icons.insert("ussr_t_34".to_string(), "ussr_t_34.png".to_string());
assert_eq!(lookup_vehicle_icon(&icons, "ussr_t_34"), "ussr_t_34.png");
assert_eq!(lookup_vehicle_icon(&icons, "germ_pz"), "germ_pz.png");
}
#[test]
fn load_vehicle_icons_parses_cache_array() {
let dir = std::env::temp_dir();
let p = dir.join("test_vehicle_cache_all.json");
fs::write(
&p,
r#"[["ussr_t_34","T-34","ussr_t_34.png",{}],["germ_pz","Pz","germ_pz.png",{}]]"#,
)
.unwrap();
let icons = load_vehicle_icons(&p);
assert_eq!(icons.get("ussr_t_34").unwrap(), "ussr_t_34.png");
assert_eq!(icons.len(), 2);
let _ = fs::remove_file(&p);
}
}