use super::prelude::*;
use neto::serde_json::Value;
pub async fn run_total_crates_io_downloads(user_login: &str) -> MyResult<u64> {
let http = crates_http()?;
let user_resp = http
.get(
&format!("/users/{}", user_login),
Vec::<(&str, &str)>::new(),
)
.await
.map_err(|e| format!("failed to fetch user: {}", e))?;
let user_json: Value = user_resp
.json()
.await
.map_err(|e| format!("failed to parse user JSON: {}", e))?;
let user_id = user_json
.get("user")
.and_then(|u| u.get("id"))
.and_then(|v| v.as_u64())
.ok_or_else(|| "missing user.id".to_string())?;
let mut total: u64 = 0;
let mut page = 1;
let per_page = 100;
loop {
let resp = http
.get(
&format!(
"/crates?per_page={}&page={}&user_id={}",
per_page, page, user_id
),
Vec::<(&str, &str)>::new(),
)
.await
.map_err(|e| format!("failed to fetch crates page {}: {}", page, e))?;
let json: Value = resp
.json()
.await
.map_err(|e| format!("failed to parse crates JSON: {}", e))?;
let crates_arr = json
.get("crates")
.and_then(|v| v.as_array())
.ok_or_else(|| "missing crates array".to_string())?;
if crates_arr.is_empty() {
break;
}
for c in crates_arr {
if let Some(dl) = c.get("downloads").and_then(|v| v.as_u64()) {
total += dl;
}
}
if crates_arr.len() < per_page as usize {
break;
}
page += 1;
}
Ok(total)
}