From 5fd7a4476d1dcbdb4853e2da5413427d73d81e2a Mon Sep 17 00:00:00 2001 From: Matthias Puchstein Date: Thu, 27 Mar 2025 05:31:53 +0100 Subject: [PATCH] transferred to its own repo --- .gitignore | 3 +- .idea/.gitignore | 8 ++ .idea/ALHP_API_RS.iml | 8 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 7 ++ Cargo.lock | 96 ++++++++++++++++++++ Cargo.toml | 11 +++ src/lib.rs | 205 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/ALHP_API_RS.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore index 489f321..5afd1d1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock +# Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk @@ -99,3 +99,4 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser +!/Cargo.lock diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/ALHP_API_RS.iml b/.idea/ALHP_API_RS.iml new file mode 100644 index 0000000..6102194 --- /dev/null +++ b/.idea/ALHP_API_RS.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..24735be --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..8306744 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a9a9099 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "alhp_api" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f6ad11a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "alhp_api" +version = "0.1.0" +edition = "2024" +authors = ["mpuchstein"] + +[dependencies] +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.140" +reqwest = { version = "0.12.15" , features = ["blocking"] } +log = "0.4.27" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..b3afe67 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,205 @@ +use log::{error, info}; +use reqwest::StatusCode; +use serde::{Deserialize, Serialize}; +use std::error::Error; +use std::fmt; +use std::io::ErrorKind; + +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 super::*; + + #[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(pkgResponse) => Ok(pkgResponse), + 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 super::*; + + #[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(genResponse) => Ok(genResponse), + 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" + ))) + } + } + } + } +} \ No newline at end of file