use std::error::Error; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; use log::{debug, info, warn}; use tokio::{fs, io}; mod arch; mod manifest; use arch::JRE_ARCH; use manifest::JavaRuntimesManifest; use crate::launcher::jre::manifest::JavaRuntimeManifest; use super::constants; pub struct JavaRuntimeRepository { home: PathBuf, manifest: JavaRuntimesManifest } impl JavaRuntimeRepository { pub async fn new(home: impl AsRef) -> Result { info!("Java runtime architecture is \"{}\".", JRE_ARCH); fs::create_dir_all(&home).await.map_err(|e| JavaRuntimeError::IO { what: "creating home directory", error: e })?; let manifest: JavaRuntimesManifest = reqwest::get(constants::URL_JRE_MANIFEST).await .map_err(|e| JavaRuntimeError::Download { what: "runtime manifest (all.json)", error: e })?.json().await .map_err(|e| JavaRuntimeError::Download { what: "runtime manifest (all.json)", error: e })?; Ok(JavaRuntimeRepository { home: home.as_ref().to_path_buf(), manifest }) } pub async fn choose_runtime(&self, component: &str) -> Result { let Some(runtime_components) = self.manifest.get(JRE_ARCH) else { return Err(JavaRuntimeError::UnsupportedArch(JRE_ARCH)); }; let Some(runtime_component) = runtime_components.get(component) else { return Err(JavaRuntimeError::UnsupportedComponent { arch: JRE_ARCH, component: component.to_owned() }); }; let Some(runtime) = runtime_component.iter().filter(|r| r.availability.progress == 100).next() else { if !runtime_components.is_empty() { warn!("Weird: the only java runtimes in {JRE_ARCH}.{component} has a progress of less than 100!"); } return Err(JavaRuntimeError::UnsupportedComponent { arch: JRE_ARCH, component: component.to_owned() }); }; let Some(ref url) = runtime.manifest.url else { return Err(JavaRuntimeError::MalformedManifest); }; debug!("Ensuring manifest for runtime {JRE_ARCH}.{component}: {url}"); // hmm maybe todo!() } } #[derive(Debug)] pub enum JavaRuntimeError { IO { what: &'static str, error: io::Error }, Download { what: &'static str, error: reqwest::Error }, UnsupportedArch(&'static str), UnsupportedComponent { arch: &'static str, component: String }, MalformedManifest } impl Display for JavaRuntimeError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { JavaRuntimeError::IO { what, error } => write!(f, "i/o error ({}): {}", what, error), JavaRuntimeError::Download { what, error } => write!(f, "error downloading {}: {}", what, error), JavaRuntimeError::UnsupportedArch(arch) => write!(f, r#"unsupported architecture "{arch}""#), JavaRuntimeError::UnsupportedComponent { arch, component } => write!(f, r#"unsupported component "{component}" for architecture "{arch}""#), JavaRuntimeError::MalformedManifest => f.write_str("malformed runtime manifest (launcher bug?)"), } } } impl Error for JavaRuntimeError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { JavaRuntimeError::IO { error, .. } => Some(error), JavaRuntimeError::Download { error, .. } => Some(error), _ => None } } }