🐛 fix: standardize rust constants bcs i was bored

This commit is contained in:
Pauline 2024-07-27 20:19:33 +02:00
parent c853a66969
commit 246b5a3d6a
No known key found for this signature in database
GPG key ID: 722BB181973296AE
26 changed files with 739 additions and 487 deletions

View file

@ -110,7 +110,7 @@ pub fn plugin<R: Runtime>() -> TauriPlugin<R> {
})
.js_init_script(format!(
r#"window.__ONELAUNCHER_VERSION__ = "{}";"#,
env!("CARGO_PKG_VERSION")
onelauncher::constants::VERSION,
))
.build()
}

View file

@ -24,13 +24,13 @@
"@rspc/tauri": "^0.2.0",
"@solid-primitives/refs": "^1.0.8",
"@solidjs/router": "^0.14.1",
"@tanstack/solid-query": "^5.51.9",
"@tanstack/solid-query": "^5.51.15",
"@tauri-apps/api": "^2.0.0-beta.13",
"@tauri-apps/plugin-clipboard-manager": "github:tauri-apps/tauri-plugin-clipboard-manager#v2",
"@tauri-apps/plugin-shell": "github:tauri-apps/tauri-plugin-shell#v2",
"@thisbeyond/solid-dnd": "^0.7.5",
"@thisbeyond/solid-select": "^0.15.0",
"@unocss/reset": "^0.61.5",
"@unocss/reset": "^0.61.6",
"@untitled-theme/icons-solid": "^0.10.5",
"overlayscrollbars": "^2.9.2",
"overlayscrollbars-solid": "^0.5.5",
@ -45,7 +45,7 @@
"@types/uuid": "^10.0.0",
"jsdom": "^24.1.1",
"sass": "^1.77.8",
"unocss": "^0.61.5",
"unocss": "^0.61.6",
"vite-plugin-solid": "^2.10.2",
"vite-plugin-solid-svg": "^0.8.1",
"vite-tsconfig-paths": "^4.3.2"

View file

@ -39,7 +39,7 @@
"@types/node": "^20.14.12",
"@vitest/ui": "^2.0.4",
"bumpp": "^9.4.1",
"eslint": "^9.7.0",
"eslint": "^9.8.0",
"eslint-plugin-solid": "^0.14.1",
"ts-node": "^10.9.2",
"tsx": "^4.16.2",

View file

@ -19,7 +19,7 @@
"@rspc/solid-query": "^0.2.3",
"@rspc/tauri": "^0.2.0",
"@solid-primitives/deep": "^0.2.9",
"@tanstack/solid-query": "^5.51.9",
"@tanstack/solid-query": "^5.51.15",
"fast-equals": "^5.0.1",
"plausible-tracker": "^0.3.9",
"solid-js": "^1.8.19",

View file

@ -1,5 +1,4 @@
use crate::data::{ManagedPackage, ManagedVersion, PackageType};
use crate::package::from::MODRINTH_API_URL;
use crate::store::{ManagedVersionFile, PackageFile, PackageSide};
use crate::utils::http::fetch;
use crate::{Result, State};
@ -127,7 +126,7 @@ pub struct Gallery {
macro_rules! format_url {
($($arg:tt)*) => {{
format!("{}{}", MODRINTH_API_URL, format!($($arg)*))
format!("{}{}", crate::constants::MODRINTH_API_URL, format!($($arg)*))
}};
}

View file

@ -13,9 +13,6 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
pub const MODRINTH_API_URL: &str = "https://api.modrinth.com/v2";
pub const CURSEFORGE_API_URL: &str = "https://api.cursefor";
#[derive(Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PackFormat {
@ -216,7 +213,11 @@ pub async fn generate_pack_from_version_id(
send_ingress(&ingress, 0.0, Some("fetching version")).await?;
let version: ManagedVersion = fetch_json(
Method::GET,
&format!("{}version/{}", MODRINTH_API_URL, version_id),
&format!(
"{}version/{}",
crate::constants::MODRINTH_API_URL,
version_id
),
None,
None,
&state.fetch_semaphore,
@ -250,7 +251,11 @@ pub async fn generate_pack_from_version_id(
let pkg: ManagedPackage = fetch_json(
Method::GET,
&format!("{}project/{}", MODRINTH_API_URL, version.package_id),
&format!(
"{}project/{}",
crate::constants::MODRINTH_API_URL,
version.package_id
),
None,
None,
&state.fetch_semaphore,

View file

@ -18,7 +18,7 @@ use std::path::{Component, PathBuf};
use super::from::{
generate_pack_from_file, generate_pack_from_version_id, CreatePack, CreatePackLocation,
PackFormat, MODRINTH_API_URL,
PackFormat,
};
/// Install a pack
@ -280,7 +280,7 @@ pub async fn remove_all_related_files(
.filter_map(|f| Some(f.hashes.get(&PackFileHash::Sha512)?.clone()))
.collect::<Vec<_>>();
let files_url = format!("{}version_files", MODRINTH_API_URL);
let files_url = format!("{}version_files", crate::constants::MODRINTH_API_URL);
let hash_packages = fetch_json::<HashMap<String, ManagedVersion>>(
Method::POST,

View file

@ -2,6 +2,8 @@ use super::IngressId;
use crate::api::proxy::{
ClusterPayloadType, Ingress, IngressType, InternetPayload, ProcessPayloadType, ProxyError,
};
#[cfg(feature = "cli")]
use crate::constants::CLI_TOTAL_INGRESS;
use crate::store::{ClusterPath, IngressProcessType, IngressProcessor};
use uuid::Uuid;
@ -22,9 +24,6 @@ pub async fn init_ingress(
Ok(key)
}
#[cfg(feature = "cli")]
const CLI_TOTAL_INGRESS: u64 = 1000;
#[onelauncher_macros::memory]
pub async fn init_ingress_internal(
ingress_type: IngressType,

View file

@ -1,7 +1,7 @@
//! Settings Management
use crate::proxy::send::{init_ingress, send_ingress};
use crate::store::{self, Clusters, Directories, Settings};
use crate::store::{Clusters, Directories, Settings};
use crate::State;
use std::path::{Path, PathBuf};
use tokio::sync::RwLock;
@ -103,7 +103,9 @@ pub async fn set_directory(new: PathBuf) -> crate::Result<()> {
{
let epath = e.path();
if let Some(file_name) = epath.file_name() {
if file_name == store::CLUSTERS_FOLDER || file_name == store::METADATA_FOLDER {
if file_name == crate::constants::CLUSTERS_FOLDER
|| file_name == crate::constants::METADATA_FOLDER
{
if across_filesystems {
entries.extend(crate::package::import::sub(&epath).await?);
cleanable.push(epath.clone());

View file

@ -1,18 +1,26 @@
//! **OneLauncher Constants**
//!
//! Public constant variables and strings that are used throughout the launcher.
//! Can be shared publically, any encrypted secrets should be stored in [`crate::store::credentials`].
//! Can be shared publically, any secrets should be stored in [`crate::store::credentials`].
// =========== Core Metadata ===========
/// The name of the launcher.
pub const NAME: &str = "OneLauncher";
/// The version of the launcher
pub const VERSION: &str = "1.0.0-alpha.1"; // todo: env
/// The version of the launcher (from `../Cargo.toml` env).
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
// =========== Default Ingress ===========
/// The amount of attempts to fetch a file before a request fails.
pub const FETCH_ATTEMPTS: usize = 3;
/// The total ingress capacity of the CLI, provided to [`indicatif`].
#[cfg(feature = "cli")]
pub const CLI_TOTAL_INGRESS: u64 = 1000;
/// The newline which we replace in metadata files.
pub const DUMMY_REPLACE_NEWLINE: &str = "\n";
// =========== Authentication ===========
/// The Discord RPC client ID.
pub const DISCORD_RPC_CLIENT_ID: &str = "1234567890000000";
/// Our Discord RPC client ID.
pub const DISCORD_RPC_CLIENT_ID: &str = "1234567890000000"; // todo
/// Our Microsoft client ID.
pub const MICROSOFT_CLIENT_ID: &str = "9eac3a4e-8cdd-43ef-863e-49cd601b1f03";
/// Mojang/Microsoft client ID.
@ -22,6 +30,47 @@ pub const MINECRAFT_REDIRECT_URL: &str = "https://login.live.com/oauth20_desktop
/// Mojang/Microsoft login xboxlive scopes to get tokens.
pub const MINECRAFT_SCOPES: &str = "service::user.auth.xboxlive.com::MBI_SSL";
// =========== API ===========
/// The Modrinth API base url.
pub const MODRINTH_API_URL: &str = "https://api.modrinth.com/v2";
/// The Curseforge API base url.
pub const CURSEFORGE_API_URL: &str = "https://api.curseforge";
/// Our metadata API base url.
pub const METADATA_API_URL: &str = "https://meta.polyfrost.org";
// =========== Paths ===========
/// The public `settings.json` file used to store the global [`Settings`] state.
///
/// [`Settings`]: crate::store::Settings
pub const SETTINGS_FILE: &str = "settings.json";
/// The public `cluster.json` file used to store the global [`Clusters`] state.
///
/// [`Clusters`]: crate::store::Clusters
pub const CLUSTER_FILE: &str = "cluster.json";
/// The public `authentication.json` file used to store the global [`MinecraftAuth`] state.
///
/// [`MinecraftAuth`]: crate::store::MinecraftAuth
pub const AUTH_FILE: &str = "authentication.json";
/// The public `processor.json` file used to store the global [`Processor`] state.
///
/// [`Processor`]: crate::store::Processor
pub const PROCESSOR_FILE: &str = "processor.json";
/// The current [`Settings`] format version, bumped for breaking changes.
/// If updated, a config file migration logic **NEEDS** to be implemented.
///
/// [`Settings`]: crate::store::Settings
pub const CURRENT_SETTINGS_FORMAT_VERSION: u32 = 1;
/// The constant core caches folder.
pub const CACHES_FOLDER: &str = "caches";
/// The constant core crash reports folder.
pub const CRASH_PATH: &str = "crash-reports";
/// The constant core clusters folder.
pub const CLUSTERS_FOLDER: &str = "clusters";
/// The constant core metadata folder.
pub const METADATA_FOLDER: &str = "metadata";
// =========== Hacky Mojang-spec OS constants ===========
#[cfg(target_os = "windows")]
pub const TARGET_OS: &str = "windows";
@ -41,4 +90,19 @@ pub const NATIVE_ARCH: &str = "64";
#[cfg(all(not(target_arch = "x86_64"), not(target_arch = "x86")))]
pub const NATIVE_ARCH: &str = "64";
// TODO: Add more architectures
// =========== Java ===========
/// The default java executable on Windows.
#[cfg(target_os = "windows")]
pub const JAVA_BIN: &str = "javaw.exe";
/// The default java executable on macOS and Linux.
#[cfg(not(target_os = "windows"))]
pub const JAVA_BIN: &str = "java";
/// The bit width on x64 architectures.
#[cfg(target_pointer_width = "64")]
pub const ARCH_WIDTH: &str = "64";
/// The bit width on x32 architectures.
#[cfg(target_pointer_width = "32")]
pub const ARCH_WIDTH: &str = "32";

View file

@ -9,12 +9,11 @@ use interpulse::api::minecraft::{Argument, ArgumentValue, Library, VersionType};
use interpulse::api::modded::SidedDataEntry;
use interpulse::utils::get_path_from_artifact;
use crate::constants::DUMMY_REPLACE_NEWLINE;
use crate::store::{Memory, MinecraftCredentials, Resolution};
use crate::utils::io::IOError;
use crate::utils::platform::classpath_separator;
const DUMMY_REPLACE_NEWLINE: &str = "\n";
#[allow(clippy::too_many_arguments)]
pub fn java_arguments(
arguments: Option<&[Argument]>,
@ -285,8 +284,8 @@ fn parse_java_argument(
.to_string_lossy(),
)
.replace("${classpath_seperator}", classpath_separator(java_arch))
.replace("${launcher_name}", "onelauncher")
.replace("${launcher_version}", env!("CARGO_PKG_VERSION"))
.replace("${launcher_name}", crate::constants::NAME)
.replace("${launcher_version}", crate::constants::VERSION)
.replace("${version_name}", version)
.replace("${classpath}", classpaths))
}

View file

@ -290,7 +290,7 @@ pub async fn download_libraries(
lib.natives.as_ref()?.get(&Os::native_arch(java_arch))?,
lib.downloads.as_ref()?.classifiers.as_ref()?
))) {
let parsed = os_key.replace("${arch}", crate::utils::platform::ARCH_WIDTH);
let parsed = os_key.replace("${arch}", crate::constants::ARCH_WIDTH);
if let Some(native) = classifiers.get(&parsed) {
let data = fetch(&native.url, Some(&native.sha1), &st.fetch_semaphore).await?;
let reader = std::io::Cursor::new(&data);

View file

@ -10,6 +10,7 @@ use std::collections::HashMap;
use std::path::{Path, PathBuf};
use uuid::Uuid;
use crate::constants::CLUSTER_FILE;
use crate::proxy::send::{send_cluster, send_message};
use crate::proxy::ClusterPayloadType;
use crate::utils::http::{write_icon, IoSemaphore};
@ -19,9 +20,6 @@ use crate::State;
use super::{Directories, InitHooks, Memory, Package, PackageType, Resolution};
/// The public `cluster.json` file used to store the global [`Clusters`] state.
const CLUSTER_JSON: &str = "cluster.json";
/// Core Cluster state manager with a [`HashMap<ClusterPath, Cluster>`].
pub(crate) struct Clusters(pub HashMap<ClusterPath, Cluster>);
@ -712,7 +710,7 @@ impl Clusters {
.map(Ok::<_, crate::Error>)
.try_for_each_concurrent(None, |(_, cluster)| async move {
let json = serde_json::to_vec(&cluster)?;
let json_path = cluster.get_full_path().await?.join(CLUSTER_JSON);
let json_path = cluster.get_full_path().await?.join(CLUSTER_FILE);
io::write(&json_path, &json).await?;
Ok::<_, crate::Error>(())
})
@ -723,7 +721,7 @@ impl Clusters {
/// read a cluster from a directory
async fn from_dir(path: &Path, dirs: &Directories) -> crate::Result<Cluster> {
let json = io::read(&path.join(CLUSTER_JSON)).await?;
let json = io::read(&path.join(CLUSTER_FILE)).await?;
let mut cluster = serde_json::from_slice::<Cluster>(&json)?;
cluster.path = PathBuf::from(
path.strip_prefix(dirs.clusters_dir().await)

View file

@ -5,15 +5,6 @@ use tokio::sync::RwLock;
use super::Settings;
use crate::constants;
/// The public `settings.json` file used to store the [`Settings`] state.
pub const SETTINGS_FILE: &str = "settings.json";
/// The constant core caches folder.
pub const CACHES_FOLDER: &str = "caches";
/// The constant core clusters folder.
pub const CLUSTERS_FOLDER: &str = "clusters";
/// The constant core metadata folder.
pub const METADATA_FOLDER: &str = "metadata";
/// Directory management and utilities.
#[derive(Debug)]
pub struct Directories {
@ -59,7 +50,10 @@ impl Directories {
/// Get the `config_dir/metadata` folder within the core config directory.
#[inline]
pub async fn metadata_dir(&self) -> PathBuf {
self.config_dir.read().await.join(METADATA_FOLDER)
self.config_dir
.read()
.await
.join(constants::METADATA_FOLDER)
}
/// Get the `config_dir/metadata/libraries` folder for Minecraft libraries.
@ -89,7 +83,7 @@ impl Directories {
/// Get the `settings_dir/settings.json` file as a [`PathBuf`].
#[inline]
pub fn settings_file(&self) -> PathBuf {
self.settings_dir.join(SETTINGS_FILE)
self.settings_dir.join(constants::SETTINGS_FILE)
}
/// Get a [`PathBuf`] from a provided environment variable.

View file

@ -4,15 +4,13 @@ use interpulse::api::minecraft::VersionManifest as MinecraftManifest;
use interpulse::api::modded::Manifest as ModdedManifest;
use serde::{Deserialize, Serialize};
use crate::constants::METADATA_API_URL;
use crate::utils::http::{fetch, read_json, write, FetchSemaphore, IoSemaphore};
use crate::utils::io::copy;
use crate::State;
use super::Directories;
/// The metadata url.
const METADATA_URL: &str = "https://meta.polyfrost.org";
/// A structure of manifests and metadata fetching utilities.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Metadata {
@ -33,7 +31,7 @@ pub struct Metadata {
impl Metadata {
/// Get the formatted manifest for a specific [`Metadata`] type.
fn get_manifest(name: &str, version: usize) -> String {
format!("{METADATA_URL}/{name}/v{version}/manifest.json")
format!("{METADATA_API_URL}/{name}/v{version}/manifest.json")
}
/// Fetch all available metadata types that are currently [`None`] and get a new [`Metadata`] structure.

View file

@ -13,9 +13,7 @@ use std::collections::HashMap;
use std::fmt::Write;
use uuid::Uuid;
use crate::constants::{MINECRAFT_CLIENT_ID, MINECRAFT_REDIRECT_URL, MINECRAFT_SCOPES};
const AUTH_STORE: &str = "authentication.json";
use crate::constants::{AUTH_FILE, MINECRAFT_CLIENT_ID, MINECRAFT_REDIRECT_URL, MINECRAFT_SCOPES};
/// The core state of Microsoft authentication for the launcher
#[derive(Serialize, Deserialize, Debug)]
@ -35,7 +33,7 @@ impl MinecraftState {
dirs: &super::Directories,
io_semaphore: &crate::utils::http::IoSemaphore,
) -> crate::Result<Self> {
let path = dirs.caches_dir().await.join(AUTH_STORE);
let path = dirs.caches_dir().await.join(AUTH_FILE);
let store = crate::utils::http::read_json(&path, io_semaphore)
.await
.ok();
@ -55,7 +53,7 @@ impl MinecraftState {
#[tracing::instrument(skip(self))]
pub async fn save(&self) -> crate::Result<()> {
let state = crate::State::get().await?;
let path = state.directories.caches_dir().await.join(AUTH_STORE);
let path = state.directories.caches_dir().await.join(AUTH_FILE);
crate::utils::http::write(&path, &serde_json::to_vec(&self)?, &state.io_semaphore).await?;
Ok(())
}

View file

@ -10,6 +10,7 @@ use tokio::task::JoinHandle;
use uuid::Uuid;
use crate::api::cluster;
use crate::constants::PROCESSOR_FILE;
use crate::proxy::send::send_process;
use crate::proxy::ProcessPayloadType;
use crate::utils::http::read_json;
@ -18,9 +19,6 @@ use crate::State;
use super::{Cluster, ClusterPath};
/// Global processor cache file.
const PROCESSOR_JSON: &str = "processor.json";
/// Wrapper over a HashMap of PIDs to ProcessorChildren and unified apis
pub struct Processor(HashMap<Uuid, Arc<RwLock<ProcessorChild>>>);
@ -168,7 +166,7 @@ impl ChildType {
post,
};
let path = state.directories.caches_dir().await.join(PROCESSOR_JSON);
let path = state.directories.caches_dir().await.join(PROCESSOR_FILE);
let mut caches = if let Ok(proc_json) =
read_json::<HashMap<Uuid, ProcessorCache>>(&path, &state.io_semaphore).await
{
@ -187,8 +185,7 @@ impl ChildType {
/// Remove a child from the global store of processes.
pub async fn remove(&self, uuid: Uuid) -> crate::Result<()> {
let state = crate::State::get().await?;
let path = state.directories.caches_dir().await.join(PROCESSOR_JSON);
let path = state.directories.caches_dir().await.join(PROCESSOR_FILE);
let mut caches = if let Ok(proc_json) =
read_json::<HashMap<Uuid, ProcessorCache>>(&path, &state.io_semaphore).await
{
@ -378,8 +375,7 @@ impl Processor {
/// restore processes from the cache.
pub async fn restore(&mut self) -> crate::Result<()> {
let state = crate::State::get().await?;
let processor_path = state.directories.caches_dir().await.join(PROCESSOR_JSON);
let processor_path = state.directories.caches_dir().await.join(PROCESSOR_FILE);
let mut processor_caches = if let Ok(processes_json) =
read_json::<HashMap<uuid::Uuid, ProcessorCache>>(&processor_path, &state.io_semaphore)
.await

View file

@ -1,14 +1,11 @@
//! Handles user-inputted settings and global values
use super::{Directories, JavaVersions};
use crate::constants::CURRENT_SETTINGS_FORMAT_VERSION;
use crate::utils::io;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
/// The current [`Settings`] format version, changed for breaking changes.
/// If updated, a config file migration logic **NEEDS** to be implemented.
const CURRENT_FORMAT_VERSION: u32 = 1;
/// A global settings state for the launcher.
#[cfg_attr(feature = "tauri", derive(specta::Type))]
#[derive(Debug, Serialize, Deserialize, Clone)]
@ -106,7 +103,7 @@ impl Settings {
custom_java_args: Vec::new(),
max_async_fetches: 10,
max_async_io_operations: 10,
version: CURRENT_FORMAT_VERSION,
version: CURRENT_SETTINGS_FORMAT_VERSION,
disable_analytics: false,
disable_discord: false,
debug_mode: false,

View file

@ -13,6 +13,7 @@ use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use tokio::sync::{RwLock, Semaphore};
use crate::constants::FETCH_ATTEMPTS;
use crate::proxy::send::send_ingress;
use crate::proxy::IngressId;
use crate::utils::io;
@ -31,8 +32,9 @@ lazy_static::lazy_static! {
pub static ref REQWEST_CLIENT: reqwest::Client = {
let mut headers = reqwest::header::HeaderMap::new();
let header = reqwest::header::HeaderValue::from_str(&format!(
"onelauncher/{} (polyfrost.org)",
env!("CARGO_PKG_VERSION")
"{}/{} (https://polyfrost.org)",
crate::constants::NAME,
crate::constants::VERSION,
)).unwrap();
headers.insert(reqwest::header::USER_AGENT, header);
reqwest::Client::builder()
@ -43,9 +45,6 @@ lazy_static::lazy_static! {
};
}
/// The amount of attempts to fetch a file before the request fails.
const FETCH_ATTEMPTS: usize = 3;
/// Basic HTTP fetch interface.
#[tracing::instrument(skip(semaphore))]
pub async fn fetch(

View file

@ -1,12 +1,8 @@
//! **IO Utilities**
//!
//! Wrapper around [`tokio::io`] for our error system.
//! Async wrapper around [`tokio::fs`] and [`std::io::Error`] for our error system.
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use anyhow::anyhow;
use tempfile::NamedTempFile;
use tokio::task::spawn_blocking;
@ -184,32 +180,3 @@ pub async fn remove_file(path: impl AsRef<std::path::Path>) -> Result<(), IOErro
path: path.to_string_lossy().to_string(),
})
}
/// Extract an archive based on its file extension, supporting ZIP files and GZ files.
pub fn extract_archive(archive: &PathBuf, dest: &PathBuf) -> crate::Result<()> {
let ext = match archive.extension() {
Some(ext) => ext.to_str().unwrap(),
None => return Err(anyhow!("unsupported operating system").into()),
};
match ext {
"zip" => Ok(extract_zip(archive, dest)?),
"gz" => Ok(extract_tar_gz(archive, dest)?),
_ => Err(anyhow!("unsupported file extension {:?}", ext).into()),
}
}
pub fn extract_zip(archive: &PathBuf, dest: &PathBuf) -> Result<(), IOError> {
let file = File::open(archive).map_err(|err| IOError::with_path(err, archive.as_path()))?;
let archive = zip::ZipArchive::new(file).map_err(IOError::from_zip);
archive?.extract(dest).map_err(IOError::from_zip)?;
Ok(())
}
pub fn extract_tar_gz(archive: &PathBuf, dest: &PathBuf) -> Result<(), IOError> {
let file = File::open(archive).map_err(IOError::from)?;
let tar_gz = flate2::read::GzDecoder::new(file);
let mut archive = tar::Archive::new(tar_gz);
archive.unpack(dest).map_err(IOError::from)?;
Ok(())
}

View file

@ -2,6 +2,7 @@
//!
//! Async utilities for managing and downloading Java versions.
use crate::constants::JAVA_BIN;
use crate::State;
use futures::prelude::*;
use serde::{Deserialize, Serialize};
@ -19,10 +20,12 @@ use winreg::{
use super::io;
/// A struct representing a single version of the Java Runtime Environment
/// Use [`locate_java`] to get an array of all located java instances on the machine
/// paths from https://github.com/PrismLauncher/PrismLauncher/blob/develop/launcher/java/JavaUtils.cpp under GPL 3.0
/// paths and java_check from https://github.com/modrinth/theseus/blob/master/theseus/src/util/jre.rs under MIT
/// A struct representing a single version of the Java Runtime Environment.
/// Use [`locate_java`] to get an array of all located java instances on the machine.
///
/// common java paths from https://github.com/PrismLauncher/PrismLauncher/blob/develop/launcher/java/JavaUtils.cpp under GPL 3.0
///
/// java check functionality from https://github.com/modrinth/theseus/blob/master/theseus/src/util/jre.rs under MIT
#[cfg_attr(feature = "tauri", derive(specta::Type))]
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)]
pub struct JavaVersion {
@ -31,7 +34,8 @@ pub struct JavaVersion {
pub path: String,
}
/// JVM Entrypoint (WINDOWS ONLY)
/// Java entrypoint: Returns all possibly existing java paths on a Linux machine and validates them,
/// returning a [`Vec<JavaVersion>`] with all valid java installations, their paths, and associated metadata.
#[cfg(target_os = "windows")]
#[tracing::instrument]
pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
@ -42,7 +46,6 @@ pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
paths.insert(PathBuf::from(java_home));
}
// i hate windows.com
let common_java_paths = [
r"C:/Program Files/Java",
r"C:\Program Files\Eclipse Adoptium",
@ -76,7 +79,7 @@ pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
r"SOFTWARE\\BellSoft\\Liberica",
];
for key in key_paths {
for key in common_key_paths {
if let Ok(java_key) = RegKey::predef(HKEY_LOCAL_MACHINE)
.open_subkey_with_flags(key, KEY_READ | KEY_WOW64_32KEY)
{
@ -91,9 +94,10 @@ pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
let java = check_java(paths).await.into_iter().collect();
Ok(java);
Ok(java)
}
/// Locates possibly existing java paths on Windows from Registry keys, returning as a [`HashSet<PathBuf>`]
#[cfg(target_os = "windows")]
#[tracing::instrument]
pub fn get_java_paths_from_windows(java_key: RegKey) -> HashSet<PathBuf> {
@ -113,7 +117,8 @@ pub fn get_java_paths_from_windows(java_key: RegKey) -> HashSet<PathBuf> {
paths
}
/// JVM Entrypoint (MacOS ONLY)
/// Java entrypoint: Returns all possibly existing java paths on a macOS machine and validates them,
/// returning a [`Vec<JavaVersion>`] with all valid java installations, their paths, and associated metadata.
#[cfg(target_os = "macos")]
#[tracing::instrument]
pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
@ -144,7 +149,8 @@ pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
Ok(java)
}
/// JVM Entrypoint (LINUX ONLY)
/// Java entrypoint: Returns all possibly existing java paths on a Linux machine and validates them,
/// returning a [`Vec<JavaVersion>`] with all valid java installations, their paths, and associated metadata.
#[cfg(target_os = "linux")]
#[tracing::instrument]
pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
@ -181,7 +187,7 @@ pub async fn locate_java() -> Result<Vec<JavaVersion>, JavaError> {
Ok(java)
}
/// Locate JRE's auto-installed by the launcher instance.
/// Locate Java paths automatically added by the launcher instance.
#[tracing::instrument]
#[onelauncher_macros::memory]
async fn locate_installed_java() -> Result<HashSet<PathBuf>, JavaError> {
@ -213,20 +219,16 @@ async fn locate_installed_java() -> Result<HashSet<PathBuf>, JavaError> {
.await
}
/// Locate all installed Java instances from the PATH env variable cross-device.
/// Locates all installed Java instances from the `PATH` env variable, returning a
/// [`HashSet<PathBuf>`] containing all paths in the `PATH` variable to be sorted into java versions.
#[tracing::instrument]
async fn locate_java_path() -> HashSet<PathBuf> {
let paths = env::var("PATH").map(|p| env::split_paths(&p).collect::<HashSet<_>>());
paths.unwrap_or_else(|_| HashSet::new())
}
#[cfg(target_os = "windows")]
pub const JAVA_BIN: &str = "javaw.exe";
#[cfg(not(target_os = "windows"))]
pub const JAVA_BIN: &str = "java";
/// Verifies that each Java instance is valid from a HashSet of PathBufs
/// Verifies that each Java instance is valid from a [`HashSet<PathBuf>`], returning a
/// [`HashSet<JavaVersion>`] for each validated path containing the installation's metadata.
#[tracing::instrument]
pub async fn check_java(paths: HashSet<PathBuf>) -> HashSet<JavaVersion> {
let java_instances = stream::iter(paths.into_iter())
@ -242,7 +244,8 @@ pub async fn check_java(paths: HashSet<PathBuf>) -> HashSet<JavaVersion> {
.collect()
}
/// Verifies that a java instance [`Path`] is valid.
/// Verifies that a java instance [`Path`] is valid, returning a [`JavaVersion`] if the java path
/// is valid, containing the installation's metadata.
/// java_check from https://github.com/modrinth/theseus/blob/master/theseus/library/JavaInfo.class under MIT
#[tracing::instrument]
#[onelauncher_macros::memory]
@ -311,7 +314,9 @@ pub async fn check_java_instance(path: &Path) -> Option<JavaVersion> {
None
}
/// Get a formatted java version.
/// Get a formatted java version as `(major: u32, minor: u32)`.
///
/// This means 1.8 becomes `(1, 8)`, and 21.0.3 becomes `(21, 0)`.
pub fn get_java_version(version: &str) -> Result<(u32, u32), JavaError> {
let mut split = version.split('.');
let major_opt = split.next();

View file

@ -2,12 +2,11 @@
pub mod http;
pub mod io;
pub mod java;
pub mod pkg;
pub mod platform;
pub mod watcher;
/// mutable reference gets epically owned by free thinking macro!!!! (not clickbait)
/// im going insane insane insane insane insane insane
/// mutable reference gets epically owned by free thinking macro!!!!! (not clickbait)
/// im going insane insane insane insane insane insane insane insane insane
macro_rules! ref_owned {
($id:ident = $init:expr => $transform:block) => {{
let mut it = $init;

View file

@ -1 +0,0 @@

View file

@ -5,11 +5,13 @@
use interpulse::api::minecraft::{Os, OsRule};
use regex::Regex;
// todo: add this to interpulse (maybe, generally we keep it unimplemented but these are pretty basic functions).
pub trait OsExt {
/// Get the OS of the current system
/// Get the [`Os`] of the current system
fn native() -> Self;
/// Gets the OS + Arch of the current system
/// Get the [`Os`] of the current system along with it's arch from the `java_arch`.
fn native_arch(java_arch: &str) -> Self;
}
@ -50,13 +52,6 @@ impl OsExt for Os {
}
}
// Bit width
#[cfg(target_pointer_width = "64")]
pub const ARCH_WIDTH: &str = "64";
#[cfg(target_pointer_width = "32")]
pub const ARCH_WIDTH: &str = "32";
// Platform rule handling
pub fn os_rule(rule: &OsRule, java_arch: &str, updated: bool) -> bool {
let mut rule_match = true;

View file

@ -11,9 +11,6 @@ use futures::{SinkExt, StreamExt};
use notify::RecommendedWatcher;
use notify_debouncer_mini::{new_debouncer, DebounceEventResult, Debouncer};
pub const CLUSTERS_PATH: &str = "clusters";
pub const CRASH_PATH: &str = "crash-reports";
pub async fn initialize_watcher() -> crate::Result<Debouncer<RecommendedWatcher>> {
let (mut sender, mut rscv) = channel(1);
let watcher = new_debouncer(
@ -56,7 +53,9 @@ pub async fn initialize_watcher() -> crate::Result<Debouncer<RecommendedWatcher>
formatted.file_name().unwrap_or_default(),
));
if a.path.components().any(|c| c.as_os_str() == CRASH_PATH)
if a.path
.components()
.any(|c| c.as_os_str() == crate::constants::CRASH_PATH)
&& a.path.extension().map(|e| e == "txt").unwrap_or(false)
{
Cluster::handle_crash(cluster_path);

920
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff