//! Authentication flow interface use reqwest::Method; use serde::Deserialize; use std::path::PathBuf; use crate::event::emit::{emit_loading, init_loading}; use crate::util::fetch::{fetch_advanced, fetch_json}; use crate::{ launcher::download, prelude::Profile, state::JavaGlobals, util::jre::{self, extract_java_majorminor_version, JavaVersion}, LoadingBarType, State, }; pub const JAVA_8_KEY: &str = "JAVA_8"; pub const JAVA_17_KEY: &str = "JAVA_17"; pub const JAVA_18PLUS_KEY: &str = "JAVA_18PLUS"; // Autodetect JavaSettings default // Make a guess for what the default Java global settings should be pub async fn autodetect_java_globals() -> crate::Result { let mut java_8 = find_java8_jres().await?; let mut java_17 = find_java17_jres().await?; let mut java_18plus = find_java18plus_jres().await?; // Simply select last one found for initial guess let mut java_globals = JavaGlobals::new(); if let Some(jre) = java_8.pop() { java_globals.insert(JAVA_8_KEY.to_string(), jre); } if let Some(jre) = java_17.pop() { java_globals.insert(JAVA_17_KEY.to_string(), jre); } if let Some(jre) = java_18plus.pop() { java_globals.insert(JAVA_18PLUS_KEY.to_string(), jre); } Ok(java_globals) } // Gets the optimal JRE key for the given profile, using Daedalus // Generally this would be used for profile_create, to get the optimal JRE key // this can be overwritten by the user a profile-by-profile basis pub async fn get_optimal_jre_key(profile: &Profile) -> crate::Result { let state = State::get().await?; let metadata = state.metadata.read().await; // Fetch version info from stored profile game_version let version = metadata .minecraft .versions .iter() .find(|it| it.id == profile.metadata.game_version) .ok_or_else(|| { crate::ErrorKind::LauncherError(format!( "Invalid or unknown Minecraft version: {}", profile.metadata.game_version )) })?; // Get detailed manifest info from Daedalus let version_info = download::download_version_info( &state, version, profile.metadata.loader_version.as_ref(), None, None, ) .await?; let optimal_key = match version_info .java_version .as_ref() .map(|it| it.major_version) .unwrap_or(0) { 0..=15 => JAVA_8_KEY.to_string(), 16..=17 => JAVA_17_KEY.to_string(), _ => JAVA_18PLUS_KEY.to_string(), }; Ok(optimal_key) } // Searches for jres on the system that are 1.18 or higher pub async fn find_java18plus_jres() -> crate::Result> { let version = extract_java_majorminor_version("1.18")?; let jres = jre::get_all_jre().await?; // Filter out JREs that are not 1.17 or higher Ok(jres .into_iter() .filter(|jre| { let jre_version = extract_java_majorminor_version(&jre.version); if let Ok(jre_version) = jre_version { jre_version >= version } else { false } }) .collect()) } // Searches for jres on the system that are 1.8 exactly pub async fn find_java8_jres() -> crate::Result> { let version = extract_java_majorminor_version("1.8")?; let jres = jre::get_all_jre().await?; // Filter out JREs that are not 1.8 Ok(jres .into_iter() .filter(|jre| { let jre_version = extract_java_majorminor_version(&jre.version); if let Ok(jre_version) = jre_version { jre_version == version } else { false } }) .collect()) } // Searches for jres on the system that are 1.17 exactly pub async fn find_java17_jres() -> crate::Result> { let version = extract_java_majorminor_version("1.17")?; let jres = jre::get_all_jre().await?; // Filter out JREs that are not 1.8 Ok(jres .into_iter() .filter(|jre| { let jre_version = extract_java_majorminor_version(&jre.version); if let Ok(jre_version) = jre_version { jre_version == version } else { false } }) .collect()) } pub async fn auto_install_java(java_version: u32) -> crate::Result { Box::pin( async move { let state = State::get().await?; let loading_bar = init_loading( LoadingBarType::JavaDownload { version: java_version, }, 100.0, "Downloading java version", ) .await?; #[derive(Deserialize)] struct Package { pub download_url: String, pub name: PathBuf, } emit_loading(&loading_bar, 0.0, Some("Fetching java version")).await?; let packages = fetch_json::>( Method::GET, &format!( "https://api.azul.com/metadata/v1/zulu/packages?arch={}&java_version={}&os={}&archive_type=zip&javafx_bundled=false&java_package_type=jre&page_size=1", std::env::consts::ARCH, java_version, std::env::consts::OS ), None, None, &state.fetch_semaphore, ).await?; emit_loading(&loading_bar, 10.0, Some("Downloading java version")).await?; if let Some(download) = packages.first() { let file = fetch_advanced( Method::GET, &download.download_url, None, None, None, Some((&loading_bar, 80.0)), &state.fetch_semaphore, ) .await?; let path = state.directories.java_versions_dir(); if path.exists() { tokio::fs::remove_dir_all(&path).await?; } let mut archive = zip::ZipArchive::new(std::io::Cursor::new(file)) .map_err(|_| { crate::Error::from(crate::ErrorKind::InputError( "Failed to read java zip".to_string(), )) })?; emit_loading(&loading_bar, 0.0, Some("Extracting java")).await?; archive.extract(&path).map_err(|_| { crate::Error::from(crate::ErrorKind::InputError( "Failed to extract java zip".to_string(), )) })?; emit_loading(&loading_bar, 100.0, Some("Done extracting java")).await?; Ok(path .join( download .name .file_stem() .unwrap_or_default() .to_string_lossy() .to_string(), ) .join(format!("zulu-{}.jre/Contents/Home/bin/java", java_version))) } else { Err(crate::ErrorKind::LauncherError(format!( "No Java Version found for Java version {}, OS {}, and Architecture {}", java_version, std::env::consts::OS, std::env::consts::ARCH, )).into()) } } ).await } // Get all JREs that exist on the system pub async fn get_all_jre() -> crate::Result> { Ok(jre::get_all_jre().await?) } pub async fn validate_globals() -> crate::Result { let state = State::get().await?; let settings = state.settings.read().await; Ok(settings.java_globals.is_all_valid().await) } // Validates JRE at a given at a given path pub async fn check_jre(path: PathBuf) -> crate::Result> { Ok(jre::check_java_at_filepath(&path).await) } // Gets maximum memory in KiB. pub async fn get_max_memory() -> crate::Result { Ok(sys_info::mem_info() .map_err(|_| { crate::Error::from(crate::ErrorKind::LauncherError( "Unable to get computer memory".to_string(), )) })? .total) }