use std::path::{Path, PathBuf};
use crate::error::Result;
const LISTFILE_URL_PRIMARY: &str =
"https://github.com/wowdev/wow-listfile/releases/latest/download/community-listfile.csv";
const LISTFILE_URL_FALLBACK: &str = "https://wago.tools/api/casc/listfile";
pub fn cache_path(output_dir: &Path) -> PathBuf {
output_dir.join(".casc-meta").join("listfile.csv")
}
pub fn is_cache_fresh(path: &Path, max_age: std::time::Duration) -> bool {
let Ok(meta) = std::fs::metadata(path) else {
return false;
};
let Ok(modified) = meta.modified() else {
return false;
};
let Ok(elapsed) = modified.elapsed() else {
return false;
};
elapsed < max_age
}
pub fn download_listfile(output_dir: &Path) -> Result<PathBuf> {
let dest = cache_path(output_dir);
if let Some(parent) = dest.parent() {
std::fs::create_dir_all(parent)?;
}
let body = match reqwest::blocking::get(LISTFILE_URL_PRIMARY) {
Ok(resp) if resp.status().is_success() => resp.text()?,
_ => {
tracing::warn!(
"Primary listfile URL failed, trying fallback: {}",
LISTFILE_URL_FALLBACK,
);
reqwest::blocking::get(LISTFILE_URL_FALLBACK)?.text()?
}
};
std::fs::write(&dest, &body)?;
tracing::info!("Downloaded listfile to {}", dest.display());
Ok(dest)
}
pub fn load_or_download(output_dir: &Path) -> Result<super::parser::Listfile> {
let path = cache_path(output_dir);
let max_age = std::time::Duration::from_secs(24 * 60 * 60);
if is_cache_fresh(&path, max_age) {
tracing::info!("Using cached listfile at {}", path.display());
} else {
download_listfile(output_dir)?;
}
super::parser::Listfile::load(&path)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_path_construction() {
let base = PathBuf::from("some_output");
let path = cache_path(&base);
assert_eq!(path, base.join(".casc-meta").join("listfile.csv"));
}
#[test]
fn cache_not_fresh_when_missing() {
let path = Path::new("nonexistent_dir/file.csv");
assert!(!is_cache_fresh(path, std::time::Duration::from_secs(86400)));
}
}