OneLauncher-Cracked/packages/oneclient_java/src/vendors/liberica.rs
2026-08-08 11:33:24 +07:00

142 lines
4.5 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 LibericaRuntimeProvider;
#[derive(Debug, Deserialize)]
struct LibericaRelease {
#[serde(rename = "downloadUrl")]
download_url: String,
filename: String,
#[serde(rename = "featureVersion")]
feature_version: u32,
#[serde(rename = "updateVersion", default)]
update_version: u32,
#[serde(rename = "buildVersion", default)]
build_version: u32,
version: String,
/// Liberica is the one vendor that publishes SHA-1 rather than SHA-256
#[serde(default)]
sha1: Option<String>,
#[serde(default)]
size: Option<u64>,
}
#[async_trait::async_trait]
impl JavaRuntimeProvider for LibericaRuntimeProvider {
fn vendor(&self) -> JavaVendor {
JavaVendor::Liberica
}
#[tracing::instrument(level = "debug", skip(self, net))]
async fn list_packages(
&self,
major: Option<u32>,
net: &RequestClient,
) -> JavaResult<Vec<JavaPackage>> {
let url = liberica_url(major)?;
let releases = net
.send_as::<Vec<LibericaRelease>>(Request::new(Method::GET, url))
.await?;
let mut releases = releases;
releases.sort_by_key(|r| {
std::cmp::Reverse((r.feature_version, r.update_version, r.build_version))
});
let packages: Vec<JavaPackage> = releases
.into_iter()
.map(|r| {
let mut java_version: Vec<u32> = r
.version
.split(|c: char| !c.is_numeric())
.filter_map(|s| s.parse::<u32>().ok())
.collect();
if java_version.first() != Some(&r.feature_version) {
java_version.insert(0, r.feature_version);
}
let checksum = r.sha1.as_deref().map(Checksum::sha1);
JavaPackage {
archive: PackageArchive::from_filename(&r.filename),
download_url: r.download_url,
java_version,
name: r.filename,
vendor: JavaVendor::Liberica,
checksum: None,
size: r.size,
}
.with_checksum(checksum)
})
.collect();
tracing::debug!(count = packages.len(), "listed Liberica packages");
Ok(packages)
}
}
fn liberica_url(major: Option<u32>) -> JavaResult<Url> {
let mut url = Url::parse("https://api.bell-sw.com/v1/liberica/releases")?;
{
let mut q = url.query_pairs_mut();
q.append_pair("os", LIBERICA_OS)
.append_pair("arch", LIBERICA_ARCH)
// Kits only never a bare runtime image
.append_pair("bundle-type", "jdk")
.append_pair("bitness", LIBERICA_BITNESS)
.append_pair("package-type", LIBERICA_PACKAGE)
.append_pair("installation-type", "archive")
.append_pair(
"fields",
// `sha1` and `size` are only returned when named here
"downloadUrl,filename,featureVersion,updateVersion,buildVersion,version,sha1,size",
)
.append_pair("output", "json");
if let Some(major) = major {
q.append_pair("version-feature", &major.to_string());
}
}
Ok(url)
}
/// Liberica takes architecture family and bitness as separate parameters so
/// x86/x86_64 collapse to `x86` and both ARM variants to `arm`
const LIBERICA_ARCH: &str = match HostTarget::CURRENT.arch {
HostArch::X86 | HostArch::X86_64 => "x86",
HostArch::Arm | HostArch::Aarch64 => "arm",
};
const LIBERICA_BITNESS: &str = HostTarget::CURRENT.bitness();
const LIBERICA_OS: &str = match HostTarget::CURRENT.os {
HostOs::Windows => "windows",
HostOs::MacOs => "macos",
HostOs::Linux { musl: true } => "linux-musl",
HostOs::Linux { musl: false } => "linux",
};
const LIBERICA_PACKAGE: &str = HostTarget::CURRENT.archive_ext();
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_kits_are_ever_requested() {
let url = liberica_url(Some(21)).expect("a valid url");
assert!(url.query().is_some_and(|q| q.contains("bundle-type=jdk")));
assert!(!url.query().is_some_and(|q| q.contains("bundle-type=jre")));
}
}