diff options
Diffstat (limited to 'src-tauri')
| -rw-r--r-- | src-tauri/src/core/java/detection.rs | 59 | ||||
| -rw-r--r-- | src-tauri/src/core/java/mod.rs | 18 | ||||
| -rw-r--r-- | src-tauri/src/core/java/providers/adoptium.rs | 103 | ||||
| -rw-r--r-- | src-tauri/src/core/java/validation.rs | 14 |
4 files changed, 110 insertions, 84 deletions
diff --git a/src-tauri/src/core/java/detection.rs b/src-tauri/src/core/java/detection.rs index 263580f..ee2111e 100644 --- a/src-tauri/src/core/java/detection.rs +++ b/src-tauri/src/core/java/detection.rs @@ -1,20 +1,15 @@ +use std::io::Read; use std::path::PathBuf; -use std::process::Command; +use std::process::{Command, Stdio}; +use std::thread::sleep; +use std::time::{Duration, Instant}; #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; -pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { - #[cfg(target_os = "windows")] - { - // Remove the UNC prefix (\\?\) from Windows paths - let s = path.to_string_lossy().to_string(); - if s.starts_with(r"\\?\") { - return PathBuf::from(&s[4..]); - } - } - path -} +use super::strip_unc_prefix; + +const WHICH_TIMEOUT: Duration = Duration::from_secs(2); pub fn find_sdkman_java() -> Option<PathBuf> { let home = std::env::var("HOME").ok()?; @@ -30,18 +25,40 @@ fn run_which_command_with_timeout() -> Option<String> { let mut cmd = Command::new(if cfg!(windows) { "where" } else { "which" }); cmd.arg("java"); #[cfg(target_os = "windows")] - // Hide the console window on Windows cmd.creation_flags(0x08000000); - - match cmd.output() { - Ok(output) => { - if output.status.success() { - Some(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - None + cmd.stdout(Stdio::piped()); + + let start = Instant::now(); + let mut child = cmd.spawn().ok()?; + + loop { + match child.try_wait() { + Ok(Some(status)) => { + if status.success() { + let mut output = String::new(); + if let Some(mut stdout) = child.stdout.take() { + let _ = stdout.read_to_string(&mut output); + } + return Some(output); + } else { + let _ = child.wait(); + return None; + } + } + Ok(None) => { + if start.elapsed() >= WHICH_TIMEOUT { + let _ = child.kill(); + let _ = child.wait(); + return None; + } + sleep(Duration::from_millis(50)); + } + Err(_) => { + let _ = child.kill(); + let _ = child.wait(); + return None; } } - Err(_) => None, } } diff --git a/src-tauri/src/core/java/mod.rs b/src-tauri/src/core/java/mod.rs index fd82390..05bf734 100644 --- a/src-tauri/src/core/java/mod.rs +++ b/src-tauri/src/core/java/mod.rs @@ -9,6 +9,18 @@ pub mod validation; pub mod provider; pub mod providers; +/// Remove the UNC prefix (\\?\) from Windows paths +pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { + #[cfg(target_os = "windows")] + { + let s = path.to_string_lossy().to_string(); + if s.starts_with(r"\\?\\") { + return PathBuf::from(&s[4..]); + } + } + path +} + use crate::core::downloader::{DownloadQueue, JavaDownloadProgress, PendingJavaDownload}; use crate::utils::zip; use provider::JavaProvider; @@ -267,7 +279,7 @@ pub async fn download_and_install_java( } let java_bin = std::fs::canonicalize(&java_bin).map_err(|e| e.to_string())?; - let java_bin = validation::strip_unc_prefix(java_bin); + let java_bin = strip_unc_prefix(java_bin); let installation = validation::check_java_installation(&java_bin) .await @@ -431,7 +443,7 @@ fn find_java_executable(dir: &PathBuf) -> Option<PathBuf> { let direct_bin = dir.join("bin").join(bin_name); if direct_bin.exists() { let resolved = std::fs::canonicalize(&direct_bin).unwrap_or(direct_bin); - return Some(validation::strip_unc_prefix(resolved)); + return Some(strip_unc_prefix(resolved)); } #[cfg(target_os = "macos")] @@ -449,7 +461,7 @@ fn find_java_executable(dir: &PathBuf) -> Option<PathBuf> { let nested_bin = path.join("bin").join(bin_name); if nested_bin.exists() { let resolved = std::fs::canonicalize(&nested_bin).unwrap_or(nested_bin); - return Some(validation::strip_unc_prefix(resolved)); + return Some(strip_unc_prefix(resolved)); } #[cfg(target_os = "macos")] diff --git a/src-tauri/src/core/java/providers/adoptium.rs b/src-tauri/src/core/java/providers/adoptium.rs index dfd4c0e..53d1519 100644 --- a/src-tauri/src/core/java/providers/adoptium.rs +++ b/src-tauri/src/core/java/providers/adoptium.rs @@ -91,77 +91,88 @@ impl JavaProvider for AdoptiumProvider { .await .map_err(|e| format!("Failed to parse available releases: {}", e))?; - let mut releases = Vec::new(); + // Parallelize HTTP requests for better performance + let mut fetch_tasks = Vec::new(); for major_version in &available.available_releases { for image_type in &["jre", "jdk"] { + let major_version = *major_version; + let image_type = image_type.to_string(); let url = format!( "{}/assets/latest/{}/hotspot?os={}&architecture={}&image_type={}", ADOPTIUM_API_BASE, major_version, os, arch, image_type ); - - match client - .get(&url) - .header("Accept", "application/json") - .send() - .await - { - Ok(response) => { - if response.status().is_success() { - if let Ok(assets) = response.json::<Vec<AdoptiumAsset>>().await { - if let Some(asset) = assets.into_iter().next() { - let release_date = asset.binary.updated_at.clone(); - let release_info = JavaReleaseInfo { - major_version: *major_version, - image_type: image_type.to_string(), - version: asset.version.semver.clone(), - release_name: asset.release_name.clone(), - release_date, - file_size: asset.binary.package.size, - checksum: asset.binary.package.checksum, - download_url: asset.binary.package.link, - is_lts: available - .available_lts_releases - .contains(major_version), - is_available: true, - architecture: asset.binary.architecture.clone(), - }; - releases.push(release_info); + let client = client.clone(); + let is_lts = available.available_lts_releases.contains(&major_version); + let arch = arch.to_string(); + + let task = tokio::spawn(async move { + match client + .get(&url) + .header("Accept", "application/json") + .send() + .await + { + Ok(response) => { + if response.status().is_success() { + if let Ok(assets) = response.json::<Vec<AdoptiumAsset>>().await { + if let Some(asset) = assets.into_iter().next() { + let release_date = asset.binary.updated_at.clone(); + return Some(JavaReleaseInfo { + major_version, + image_type, + version: asset.version.semver.clone(), + release_name: asset.release_name.clone(), + release_date, + file_size: asset.binary.package.size, + checksum: asset.binary.package.checksum, + download_url: asset.binary.package.link, + is_lts, + is_available: true, + architecture: asset.binary.architecture.clone(), + }); + } } } - } else { - let release_info = JavaReleaseInfo { - major_version: *major_version, - image_type: image_type.to_string(), + // Fallback for unsuccessful response + Some(JavaReleaseInfo { + major_version, + image_type, version: format!("{}.x", major_version), release_name: format!("jdk-{}", major_version), release_date: None, file_size: 0, checksum: None, download_url: String::new(), - is_lts: available.available_lts_releases.contains(major_version), + is_lts, is_available: false, - architecture: arch.to_string(), - }; - releases.push(release_info); + architecture: arch, + }) } - } - Err(_) => { - releases.push(JavaReleaseInfo { - major_version: *major_version, - image_type: image_type.to_string(), + Err(_) => Some(JavaReleaseInfo { + major_version, + image_type, version: format!("{}.x", major_version), release_name: format!("jdk-{}", major_version), release_date: None, file_size: 0, checksum: None, download_url: String::new(), - is_lts: available.available_lts_releases.contains(major_version), + is_lts, is_available: false, - architecture: arch.to_string(), - }); + architecture: arch, + }), } - } + }); + fetch_tasks.push(task); + } + } + + // Collect all results concurrently + let mut releases = Vec::new(); + for task in fetch_tasks { + if let Ok(Some(release)) = task.await { + releases.push(release); } } diff --git a/src-tauri/src/core/java/validation.rs b/src-tauri/src/core/java/validation.rs index ec7745d..8eca58a 100644 --- a/src-tauri/src/core/java/validation.rs +++ b/src-tauri/src/core/java/validation.rs @@ -1,25 +1,11 @@ use std::path::PathBuf; use std::process::Command; -use std::time::Duration; #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; use super::JavaInstallation; -const JAVA_CHECK_TIMEOUT: Duration = Duration::from_secs(5); - -pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { - #[cfg(target_os = "windows")] - { - let s = path.to_string_lossy().to_string(); - if s.starts_with(r"\\?\") { - return PathBuf::from(&s[4..]); - } - } - path -} - pub async fn check_java_installation(path: &PathBuf) -> Option<JavaInstallation> { let path = path.clone(); tokio::task::spawn_blocking(move || { |