aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src-tauri/src/core/java/detection.rs59
-rw-r--r--src-tauri/src/core/java/mod.rs18
-rw-r--r--src-tauri/src/core/java/providers/adoptium.rs103
-rw-r--r--src-tauri/src/core/java/validation.rs14
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 || {