OneLauncher-Cracked/packages/oneclient_java/src/vendors/adoptium.rs

170 lines
5.2 KiB
Rust

use reqwest::{Method, Request};
use serde::Deserialize;
use url::Url;
use oneclient_net::RequestClient;
use polyio::Checksum;
use crate::data::{JavaPackage, PackageArchive};
use crate::error::JavaResult;
use crate::platform::{HostArch, HostOs, HostTarget};
use crate::vendors::{JavaRuntimeProvider, JavaVendor};
pub struct AdoptiumRuntimeProvider;
#[derive(Debug, Deserialize)]
struct AdoptiumAvailableReleases {
available_releases: Vec<u32>,
}
#[derive(Debug, Deserialize)]
struct AdoptiumRelease {
version_data: AdoptiumVersionData,
binaries: Vec<AdoptiumBinary>,
}
#[derive(Debug, Deserialize)]
struct AdoptiumVersionData {
semver: String,
major: u32,
}
#[derive(Debug, Deserialize)]
struct AdoptiumBinary {
package: AdoptiumPackage,
}
#[derive(Debug, Deserialize)]
struct AdoptiumPackage {
name: String,
link: String,
/// Always SHA-256 the API has no algorithm field
#[serde(default)]
checksum: Option<String>,
#[serde(default)]
size: Option<u64>,
}
#[async_trait::async_trait]
impl JavaRuntimeProvider for AdoptiumRuntimeProvider {
fn vendor(&self) -> JavaVendor {
JavaVendor::Adoptium
}
#[tracing::instrument(level = "debug", skip(self, net))]
async fn list_packages(
&self,
major: Option<u32>,
net: &RequestClient,
) -> JavaResult<Vec<JavaPackage>> {
let (low, high) = match major {
Some(major) => (major, major),
None => {
let info = net
.send_as::<AdoptiumAvailableReleases>(Request::new(
Method::GET,
Url::parse("https://api.adoptium.net/v3/info/available_releases")?,
))
.await?;
let low = info.available_releases.iter().copied().min().unwrap_or(8);
let high = info.available_releases.iter().copied().max().unwrap_or(low);
(low, high)
}
};
let url = adoptium_url(low, high)?;
let releases = net
.send_as::<Vec<AdoptiumRelease>>(Request::new(Method::GET, url))
.await?;
let mut packages = Vec::new();
for release in releases {
let mut java_version: Vec<u32> = release
.version_data
.semver
.split(|c: char| !c.is_numeric())
.filter_map(|s| s.parse::<u32>().ok())
.collect();
if java_version.first() != Some(&release.version_data.major) {
java_version.insert(0, release.version_data.major);
}
for binary in release.binaries {
let checksum = binary.package.checksum.as_deref().map(Checksum::sha256);
packages.push(
JavaPackage {
archive: PackageArchive::from_filename(&binary.package.name),
download_url: binary.package.link,
java_version: java_version.clone(),
name: binary.package.name,
vendor: JavaVendor::Adoptium,
checksum: None,
size: binary.package.size,
}
.with_checksum(checksum),
);
}
}
tracing::debug!(count = packages.len(), "listed Adoptium packages");
Ok(packages)
}
}
// A version range spans every GA major in one request instead of one per major
fn adoptium_url(low: u32, high: u32) -> JavaResult<Url> {
let range = format!("%5B{low}%2C{}%5D", high + 1);
let mut url = Url::parse(&format!(
"https://api.adoptium.net/v3/assets/version/{range}"
))?;
url.query_pairs_mut()
.append_pair("os", ADOPTIUM_OS)
.append_pair("architecture", ADOPTIUM_ARCH)
// Kits only a JRE lacks tooling mod loaders expect
.append_pair("image_type", "jdk")
.append_pair("jvm_impl", "hotspot")
.append_pair("project", "jdk")
.append_pair("heap_size", "normal")
.append_pair("vendor", "eclipse")
.append_pair("release_type", "ga")
.append_pair("sort_method", "DATE")
.append_pair("sort_order", "DESC")
.append_pair("page", "0")
.append_pair("page_size", "50");
Ok(url)
}
/// Adoptium alone spells 32-bit x86 `x32`
const ADOPTIUM_ARCH: &str = match HostTarget::CURRENT.arch {
HostArch::X86 => "x32",
HostArch::X86_64 => "x64",
HostArch::Arm => "arm",
HostArch::Aarch64 => "aarch64",
};
/// Adoptium says `mac` where the other vendors say `macos` and publishes musl
/// builds under `alpine-linux` rather than `linux-musl`
const ADOPTIUM_OS: &str = match HostTarget::CURRENT.os {
HostOs::Windows => "windows",
HostOs::MacOs => "mac",
HostOs::Linux { musl: true } => "alpine-linux",
HostOs::Linux { musl: false } => "linux",
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_kits_are_ever_requested() {
let url = adoptium_url(21, 21).expect("a valid url");
assert!(url.query().is_some_and(|q| q.contains("image_type=jdk")));
assert!(!url.query().is_some_and(|q| q.contains("image_type=jre")));
}
}