diff --git a/Cargo.lock b/Cargo.lock index 19cb4927..04198c53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1214,12 +1214,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1616,6 +1616,18 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + [[package]] name = "gimli" version = "0.31.0" @@ -2297,9 +2309,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libloading" @@ -2340,9 +2352,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "lock_api" @@ -2957,6 +2969,7 @@ dependencies = [ "sysinfo", "tauri", "tauri-specta", + "tempfile", "thiserror 1.0.64", "tokio", "tokio-stream", @@ -3573,6 +3586,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -3918,15 +3937,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5287,12 +5306,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", "once_cell", "rustix", "windows-sys 0.59.0", @@ -5896,6 +5915,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasite" version = "0.1.0" @@ -6516,6 +6544,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "wry" version = "0.46.2" diff --git a/Cargo.toml b/Cargo.toml index 259b82d6..3c704849 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,7 @@ tokio = { version = "1.40", features = [ "full" ] } tokio-stream = { version = "0.1.16", features = [ "fs" ] } notify = { version = "6.1", default-features = false } notify-debouncer-mini = { version = "0.4", default-features = false } -tempfile = { version = "3.12" } +tempfile = { version = "3.19" } dunce = { version = "1.0.5" } zip = { version = "2.2.0" } dirs = { version = "5.0" } diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index 1262bbf1..b21c29bc 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -21,7 +21,7 @@ tauri = [ "specta", "gui" ] -specta = [ "dep:specta" ] +specta = [ "dep:specta", "onelauncher_entity/specta" ] cli = [ "dep:indicatif" ] gui = [] @@ -82,6 +82,7 @@ bytes = { workspace = true } base64 = { workspace = true } async-compression = { workspace = true } dunce = { workspace = true } +tempfile = { workspace = true } # features[tauri] tauri = { workspace = true, optional = true } diff --git a/packages/core/assets/java/JavaInfo.class b/packages/core/assets/java/JavaInfo.class new file mode 100644 index 00000000..0b9e4e9d Binary files /dev/null and b/packages/core/assets/java/JavaInfo.class differ diff --git a/packages/core/assets/java/JavaInfo.java b/packages/core/assets/java/JavaInfo.java new file mode 100644 index 00000000..0d8571cf --- /dev/null +++ b/packages/core/assets/java/JavaInfo.java @@ -0,0 +1,19 @@ +public final class JavaInfo { + private static final String[] CHECKED_PROPERTIES = new String[] {"os.arch", "java.version", "java.vendor"}; + + public static void main(String[] args) { + int returnCode = 0; + + for (String key : CHECKED_PROPERTIES) { + String property = System.getProperty(key); + + if (property != null) { + System.out.println(key + "=" + property); + } else { + returnCode = 1; + } + } + + System.exit(returnCode); + } +} diff --git a/packages/core/assets/java/README.md b/packages/core/assets/java/README.md new file mode 100644 index 00000000..2c311285 --- /dev/null +++ b/packages/core/assets/java/README.md @@ -0,0 +1,6 @@ +[`JavaInfo`](./JavaInfo.java) compiled by [`LynithDev`](https://github.com/LynithDev) using +``` +os.arch=amd64 +java.version=1.8.0_382 +java.vendor=Azul Systems, Inc. +``` diff --git a/packages/core/src/api/java.rs b/packages/core/src/api/java.rs new file mode 100644 index 00000000..e69de29b diff --git a/packages/core/src/api/mod.rs b/packages/core/src/api/mod.rs index 649515a3..69bcae7c 100644 --- a/packages/core/src/api/mod.rs +++ b/packages/core/src/api/mod.rs @@ -1,2 +1,3 @@ pub mod ingress; -pub mod proxy; \ No newline at end of file +pub mod proxy; +pub mod java; \ No newline at end of file diff --git a/packages/core/src/store/ingress.rs b/packages/core/src/store/ingress.rs index 12ec7339..aeea9891 100644 --- a/packages/core/src/store/ingress.rs +++ b/packages/core/src/store/ingress.rs @@ -108,7 +108,8 @@ pub struct IngressPayload { pub enum IngressType { Download { file_name: String, - } + }, + JavaCheck } impl Drop for IngressId { diff --git a/packages/core/src/store/java.rs b/packages/core/src/store/java.rs index 2861e553..4d86039d 100644 --- a/packages/core/src/store/java.rs +++ b/packages/core/src/store/java.rs @@ -1,14 +1,108 @@ -use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, path::PathBuf}; -use crate::LauncherResult; +use onelauncher_entity::java_versions; +use sea_orm::{ActiveValue::Set, ActiveModelTrait, ColumnTrait, EntityTrait, Order, QueryFilter, QueryOrder}; +use serde::Serialize; -// pub async fn get_java_versions() -> LauncherResult> { -// // let java_versions = sqlx::query_as!( -// // JavaVersion, -// // r#" -// // SELECT id, major_version, display_name, absolute_path, full_version FROM java_versions -// // "# -// // ); +use crate::{api::ingress::{init_ingress, send_ingress}, store::{ingress::IngressType, State}, utils::io::{self, IOError}, LauncherResult}; + +pub async fn get_java_all() -> LauncherResult> { + let db = &State::get().await?.db; + + Ok(java_versions::Entity::find() + .order_by(java_versions::Column::MajorVersion, Order::Desc) + .all(db) + .await?) +} + +pub async fn get_java_by_id(id: i32) -> LauncherResult> { + let db = &State::get().await?.db; + + Ok(java_versions::Entity::find() + .filter(java_versions::Column::Id.eq(id)) + .one(db) + .await?) +} + +pub async fn get_java_by_major(major: i32) -> LauncherResult> { + let db = &State::get().await?.db; + + Ok(java_versions::Entity::find() + .filter(java_versions::Column::MajorVersion.eq(major)) + .order_by(java_versions::Column::FullVersion, Order::Desc) + .all(db) + .await?) +} + +pub async fn insert_java(absolute_path: PathBuf) -> LauncherResult { + let db = &State::get().await?.db; + + let java_info = check_java_runtime(&absolute_path).await?; + + let major_version = if java_info.java_version[0..2].eq("1.") { + java_info.java_version[2..3].parse::().unwrap_or(0) + } else { + let split = java_info.java_version.split_once('.').unwrap_or_default(); + split.0.parse::().unwrap_or(0) + }; + + let model = java_versions::ActiveModel { + absolute_path: Set(absolute_path.to_string_lossy().to_string()), + major_version: Set(major_version), + full_version: Set(java_info.java_version.clone()), + vendor_name: Set(java_info.java_vendor.clone()), + ..Default::default() + }; + + Ok(model.insert(db).await?) +} + +#[onelauncher_macro::specta] +#[derive(Debug, Clone, Serialize)] +pub struct JavaInfo { + pub os_arch: String, + pub java_version: String, + pub java_vendor: String, +} + +const JAVA_INFO_CLASS: &[u8] = include_bytes!("../../assets/java/JavaInfo.class"); + +pub async fn check_java_runtime(absolute_path: &PathBuf) -> LauncherResult { + let id = init_ingress(IngressType::JavaCheck, "Checking JRE information", 100.0).await?; + + let dir = io::tempdir()?; + let file = dir.path().join("JavaInfo.class"); + send_ingress(&id, 25.0).await?; + + io::write(&file, JAVA_INFO_CLASS).await?; + send_ingress(&id, 25.0).await?; + + let java_info = tokio::process::Command::new(absolute_path) + .arg("-cp") + .arg(dir.path()) + .arg("JavaInfo") + .env_remove("_JAVA_OPTIONS") + .output() + .await + .map_err(IOError::from)?; + + let java_info = String::from_utf8_lossy(&java_info.stdout); + send_ingress(&id, 50.0).await?; + + let info = java_info.lines() + .map(|line| { + let mut parts = line.splitn(2, '='); + let key = parts.next().unwrap_or("unknown"); + let value = parts.next().unwrap_or("unknown"); + + (key.to_string(), value.to_string()) + }) + .collect::>(); + + Ok(JavaInfo { + os_arch: info.get("os.arch").cloned().unwrap_or_else(|| String::from("unknown")), + java_version: info.get("java.version").cloned().unwrap_or_else(|| String::from("unknown")), + java_vendor: info.get("java.vendor").cloned().unwrap_or_else(|| String::from("unknown")), + }) +} -// Ok(vec![]) -// } diff --git a/packages/core/src/utils/io.rs b/packages/core/src/utils/io.rs index 721662d9..2a8bf79b 100644 --- a/packages/core/src/utils/io.rs +++ b/packages/core/src/utils/io.rs @@ -1,4 +1,5 @@ use async_compression::tokio::bufread::GzipDecoder; +use tempfile::TempDir; use tokio::io::AsyncReadExt; /// A wrapper around generic and unhelpful [`std::io::Error`] messages. @@ -182,4 +183,14 @@ pub async fn remove_file(path: impl AsRef) -> Result<(), IOErro source: e, path: path.to_string_lossy().to_string(), }) -} \ No newline at end of file +} + +/// Creates a temporary directory. +pub fn tempdir() -> Result { + Ok(tempfile::tempdir()?) +} + +/// Creates a temporary file. +pub fn tempfile() -> Result { + Ok(tempfile::tempfile()?) +} diff --git a/packages/core_old/wrapper/java/JavaInfo.class b/packages/core_old/wrapper/java/JavaInfo.class deleted file mode 100644 index 69ffc97b..00000000 Binary files a/packages/core_old/wrapper/java/JavaInfo.class and /dev/null differ diff --git a/packages/core_old/wrapper/java/LICENSE b/packages/core_old/wrapper/java/LICENSE deleted file mode 100644 index fdddb29a..00000000 --- a/packages/core_old/wrapper/java/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/packages/entity/src/entities/java_versions.rs b/packages/entity/src/entities/java_versions.rs index aa793ca5..0e114730 100644 --- a/packages/entity/src/entities/java_versions.rs +++ b/packages/entity/src/entities/java_versions.rs @@ -11,7 +11,7 @@ pub struct Model { pub id: i32, pub major_version: i32, #[sea_orm(column_type = "Text")] - pub display_name: String, + pub vendor_name: String, #[sea_orm(column_type = "Text")] pub absolute_path: String, #[sea_orm(column_type = "Text")] diff --git a/packages/migration/src/init.sql b/packages/migration/src/init.sql index 8b84d638..4538a7f2 100644 --- a/packages/migration/src/init.sql +++ b/packages/migration/src/init.sql @@ -7,7 +7,7 @@ create table cluster_groups ( create table java_versions ( id integer not null, major_version integer not null, - display_name text not null, + vendor_name text not null, absolute_path text not null, full_version text not null, constraint java_versions_pk primary key (id autoincrement)