use rootcause::prelude::*;
pub fn fetch_versioned_constants_blocking(build: u32) -> Result<(serde_json::Value, u32), rootcause::Report> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.attach_with(|| "Failed to create tokio runtime")?;
runtime.block_on(fetch_versioned_constants(build))
}
pub async fn fetch_versioned_constants(target_build: u32) -> Result<(serde_json::Value, u32), rootcause::Report> {
let available = list_available_builds().await?;
if available.contains(&target_build)
&& let Some(data) = fetch_build(target_build).await
{
return Ok((data, target_build));
}
for &build in available.iter().rev() {
if build >= target_build {
continue;
}
if let Some(data) = fetch_build(build).await {
return Ok((data, build));
}
}
bail!("No constants found for build {target_build} or any older build")
}
pub async fn list_available_builds() -> Result<Vec<u32>, rootcause::Report> {
let items = octocrab::instance()
.repos("padtrack", "wows-constants")
.get_content()
.path("data/versions")
.r#ref("main")
.send()
.await
.attach_with(|| "Failed to list constants builds from GitHub")?;
let mut builds: Vec<u32> =
items.items.iter().filter_map(|item| item.name.strip_suffix(".json")?.parse::<u32>().ok()).collect();
builds.sort();
Ok(builds)
}
pub async fn fetch_build(build: u32) -> Option<serde_json::Value> {
use http_body_util::BodyExt;
use octocrab::params::repos::Reference;
let path = format!("data/versions/{build}.json");
let response = octocrab::instance()
.repos("padtrack", "wows-constants")
.raw_file(Reference::Branch("main".to_string()), &path)
.await
.ok()?;
let mut body = response.into_body();
let mut result = Vec::new();
while let Some(frame) = body.frame().await {
match frame {
Ok(frame) => {
if let Some(data) = frame.data_ref() {
result.extend_from_slice(data);
}
}
Err(_) => return None,
}
}
serde_json::from_slice(&result).ok()
}