use super::{IndexError, PackageIndex, PackageMeta, VersionMeta};
use crate::cache;
use std::time::Duration;
const CACHE_TTL: Duration = Duration::from_secs(60 * 60);
pub struct ChaoticAur;
impl ChaoticAur {
const API_URL: &'static str =
"https://chaotic-backend.garudalinux.org/builder/packages?repo=true";
fn parse_package(pkg: &serde_json::Value) -> Option<PackageMeta> {
let name = pkg["pkgname"].as_str()?;
let version = pkg["version"].as_str().unwrap_or("unknown");
let pkgrel = pkg["pkgrel"].as_u64().unwrap_or(1);
let metadata = &pkg["metadata"];
let description = metadata["desc"].as_str().map(String::from);
let homepage = metadata["url"].as_str().map(String::from);
let license = metadata["license"].as_str().map(String::from);
let filename = metadata["filename"].as_str();
let archive_url = filename.map(|f| {
format!(
"https://builds.garudalinux.org/repos/chaotic-aur/x86_64/{}",
f
)
});
Some(PackageMeta {
name: name.to_string(),
version: format!("{}-{}", version, pkgrel),
description,
homepage,
repository: Some("https://aur.chaotic.cx/".to_string()),
license,
binaries: Vec::new(),
keywords: Vec::new(),
maintainers: Vec::new(),
published: None,
downloads: None,
archive_url,
checksum: None,
extra: Default::default(),
})
}
fn load_packages() -> Result<Vec<PackageMeta>, IndexError> {
let (data, _was_cached) =
cache::fetch_with_cache("chaotic-aur", "packages", Self::API_URL, CACHE_TTL)
.map_err(IndexError::Network)?;
let packages: Vec<serde_json::Value> =
serde_json::from_slice(&data).map_err(|e| IndexError::Parse(e.to_string()))?;
Ok(packages
.iter()
.filter(|p| p["isActive"].as_bool().unwrap_or(false))
.filter_map(Self::parse_package)
.collect())
}
}
impl PackageIndex for ChaoticAur {
fn ecosystem(&self) -> &'static str {
"chaotic-aur"
}
fn display_name(&self) -> &'static str {
"Chaotic-AUR"
}
fn fetch(&self, name: &str) -> Result<PackageMeta, IndexError> {
let packages = Self::load_packages()?;
packages
.into_iter()
.find(|p| p.name.eq_ignore_ascii_case(name))
.ok_or_else(|| IndexError::NotFound(name.to_string()))
}
fn fetch_versions(&self, name: &str) -> Result<Vec<VersionMeta>, IndexError> {
let pkg = self.fetch(name)?;
Ok(vec![VersionMeta {
version: pkg.version,
released: None,
yanked: false,
}])
}
fn search(&self, query: &str) -> Result<Vec<PackageMeta>, IndexError> {
let packages = Self::load_packages()?;
let query_lower = query.to_lowercase();
Ok(packages
.into_iter()
.filter(|p| {
p.name.to_lowercase().contains(&query_lower)
|| p.description
.as_ref()
.map(|d| d.to_lowercase().contains(&query_lower))
.unwrap_or(false)
})
.take(50)
.collect())
}
fn fetch_all(&self) -> Result<Vec<PackageMeta>, IndexError> {
Self::load_packages()
}
}