const API_BASE_URL: &str = "https://api.alhp.dev"; const API_PACKAGES_EXT: &str = "/packages?"; const API_GENERAL_EXT: &str = "/stats?"; pub mod packages { use crate::{API_BASE_URL, API_PACKAGES_EXT}; use log::{error, info}; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use std::error::Error; use std::fmt; use std::io::ErrorKind; #[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)] #[serde(rename_all = "lowercase")] pub enum PackageStatus { Latest, Failed, Built, Skipped, Delayed, Building, Signing, Unknown, Queued, } impl fmt::Display for PackageStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", match self { PackageStatus::Latest => "latest", PackageStatus::Failed => "failed", PackageStatus::Built => "build", PackageStatus::Skipped => "skipped", PackageStatus::Delayed => "delayed", PackageStatus::Building => "building", PackageStatus::Signing => "signing", PackageStatus::Unknown => "unknown", PackageStatus::Queued => "queued", } ) } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Package { pub pkgbase: String, pub repo: String, pub split_packages: Vec, pub status: PackageStatus, pub skip_reason: Option, pub lto: String, pub debug_symbols: String, pub arch_version: String, pub repo_version: String, pub build_date: Option, pub peak_mem: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PackageResponse { pub total: usize, pub offset: usize, pub limit: usize, pub packages: Vec, } #[derive(Debug, Serialize, Default)] pub struct PackageRequest { pub status: Vec, pub pkgbase: Option, pub exact: bool, pub repo: Option, pub offset: usize, pub limit: usize, } impl PackageRequest { fn query_string(&self) -> String { let mut params = Vec::new(); for status in &self.status { params.push(format!("status={}", status)); } if let Some(pkgbase) = &self.pkgbase { params.push(format!("pkgbase={}", pkgbase)); } if self.exact { params.push("exact".to_string()); } if let Some(repo) = &self.repo { params.push(format!("repo={}", repo)); } params.push(format!("offset={}", self.offset)); params.push(format!("limit={}", self.limit)); params.join("&") } pub fn response(&self) -> Result> { let query_url = format!( "{}{}{}", API_BASE_URL, API_PACKAGES_EXT, self.query_string() ); info!("Fetching URL: {}", query_url); let response = reqwest::blocking::get(query_url)?; match response.status() { StatusCode::OK => { let response = response.text()?; match serde_json::from_str(&response) { Ok(json) => Ok(json), Err(e) => { error!("Failed to deserialize JSON: {}", e); error!("Response body: {}", response); Err(Box::new(e)) } } } StatusCode::NOT_FOUND => { info!("No packages found"); Ok(PackageResponse { total: 0, offset: 0, limit: 0, packages: vec![], }) } StatusCode::INTERNAL_SERVER_ERROR => { error!("Internal server error"); Err(Box::new(std::io::Error::new( ErrorKind::ConnectionAborted, "Internal server error", ))) } _ => { error!("Unexpected status: {}", response.status()); Err(Box::new(std::io::Error::new( ErrorKind::Unsupported, "Unexpected server response" ))) } } } } } pub mod general { use crate::{API_BASE_URL, API_GENERAL_EXT}; use log::error; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use std::error::Error; use std::io::ErrorKind; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LtoStats { pub enabled: usize, pub disabled: usize, pub unknown: usize, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GeneralResponse { pub failed: usize, pub skipped: usize, pub latest: usize, pub queued: usize, pub lto: LtoStats, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GeneralRequest { //No params yet. } impl GeneralRequest { pub fn response(&self) -> Result> { let query_url = format!("{}{}", API_BASE_URL, API_GENERAL_EXT); let response = reqwest::blocking::get(query_url)?; match response.status() { StatusCode::OK => { let response = response.text()?; match serde_json::from_str(&response) { Ok(json) => Ok(json), Err(e) => { error!("Failed to deserialize JSON: {}", e); error!("Response body: {}", response); Err(Box::new(e)) } } } StatusCode::INTERNAL_SERVER_ERROR => { error!("Internal server error"); Err(Box::new(std::io::Error::new( ErrorKind::ConnectionAborted, "Internal server error", ))) } _ => { error!("Unexpected status: {}", response.status()); Err(Box::new(std::io::Error::new( ErrorKind::Unsupported, "Unexpected server response" ))) } } } } }