Inherit dependencies from workspace manifest, and optimize some out (#3655)

* chore: inherit dependencies from workspace, optimize some deps out

* Update bitflags from 2.9.0 to 2.9.1

* Fix temp directory leak in check_java_at_filepath

* Fix build

* Fix lint

* chore(app-lib): refactor overkill `futures` executor usage to Tokio MPSC

* chore: fix Clippy lint

* tweak: optimize out dependency on OpenSSL source build

Contrary to what I expected before, this was caused due to the Tauri
updater plugin using a different TLS stack than everything else.

* chore(labrinth): drop now unused dependency

* Update zip because 2.6.1 got yanked

* Downgrade weezl to 0.1.8

* Mention that p256 is also a blocker for rand 0.9

* chore: sidestep GitHub review requirements

* chore: sidestep GitHub review requirements (2)

* chore: sidestep GitHub review requirements (3)

---------

Co-authored-by: Josiah Glosson <soujournme@gmail.com>
This commit is contained in:
Alejandro González
2025-05-15 22:47:29 +02:00
committed by GitHub
parent 37cc81a36d
commit f19643095e
35 changed files with 876 additions and 1020 deletions

View File

@@ -5,75 +5,72 @@ authors = ["Jai A <jaiagr+gpg@pm.me>"]
edition = "2024"
[dependencies]
bytes = "1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_ini = "0.2.0"
sha1_smol = { version = "1.0.0", features = ["std"] }
sha2 = "0.10.9"
url = { version = "2.2", features = ["serde"] }
uuid = { version = "1.1", features = ["serde", "v4"] }
zip = "2.6.1"
async_zip = { version = "0.0.17", features = ["chrono", "tokio-fs", "deflate", "bzip2", "zstd", "deflate64"] }
flate2 = "1.1.1"
tempfile = "3.5.0"
dashmap = { version = "6.1.0", features = ["serde"] }
quick-xml = { version = "0.37", features = ["async-tokio"] }
enumset = "1.1"
bytes.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
serde_ini.workspace = true
sha1_smol.workspace = true
sha2.workspace = true
url = { workspace = true, features = ["serde"] }
uuid = { workspace = true, features = ["serde", "v4"] }
zip.workspace = true
async_zip = { workspace = true, features = ["chrono", "tokio-fs", "deflate", "bzip2", "zstd", "deflate64"] }
flate2.workspace = true
tempfile.workspace = true
dashmap = { workspace = true, features = ["serde"] }
quick-xml = { workspace = true, features = ["async-tokio"] }
enumset.workspace = true
chrono = { version = "0.4.19", features = ["serde"] }
daedalus = { path = "../../packages/daedalus" }
dirs = "6.0.0"
chrono = { workspace = true, features = ["serde"] }
daedalus.workspace = true
dirs.workspace = true
regex = "1.5"
sys-info = "0.9.0"
sysinfo = "0.35.0"
thiserror = "2.0.12"
either = "1.13"
regex.workspace = true
sysinfo = { workspace = true, features = ["system", "disk"] }
thiserror.workspace = true
either.workspace = true
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.18", features = ["chrono", "env-filter"] }
tracing-error = "0.2.0"
tracing.workspace = true
tracing-subscriber = { workspace = true, features = ["chrono", "env-filter"] }
tracing-error.workspace = true
paste = { version = "1.0" }
paste.workspace = true
tauri = { version = "2.5.1", optional = true }
indicatif = { version = "0.17.3", optional = true }
tauri = { workspace = true, optional = true }
indicatif = { workspace = true, optional = true }
async-tungstenite = { version = "0.29.1", features = ["tokio-runtime", "tokio-rustls-webpki-roots"] }
futures = "0.3"
reqwest = { version = "0.12.15", features = ["json", "stream", "deflate", "gzip", "brotli", "rustls-tls", "charset", "http2", "macos-system-configuration"], default-features = false }
tokio = { version = "1", features = ["full"] }
tokio-util = "0.7"
async-recursion = "1.0.4"
fs4 = { version = "0.13", features = ["tokio"] }
async-walkdir = "2.1"
async-compression = { version = "0.4", default-features = false, features = ["tokio", "gzip"] }
async-tungstenite = { workspace = true, features = ["tokio-runtime", "tokio-rustls-webpki-roots"] }
futures = { workspace = true, features = ["async-await", "alloc"] }
reqwest = { workspace = true, features = ["json", "stream", "deflate", "gzip", "brotli", "rustls-tls-webpki-roots", "charset", "http2", "macos-system-configuration"] }
tokio = { workspace = true, features = ["time", "io-util", "net", "sync", "fs", "macros", "process"] }
tokio-util = { workspace = true, features = ["compat"] }
async-recursion.workspace = true
fs4 = { workspace = true, features = ["tokio"] }
async-walkdir.workspace = true
async-compression = { workspace = true, features = ["tokio", "gzip"] }
notify = { version = "8.0.0", default-features = false }
notify-debouncer-mini = { version = "0.6.0", default-features = false }
notify.workspace = true
notify-debouncer-mini.workspace = true
lazy_static = "1.4.0"
dunce = "1.0.3"
dunce.workspace = true
whoami = "1.4.0"
whoami.workspace = true
discord-rich-presence = "0.2.4"
discord-rich-presence.workspace = true
p256 = { version = "0.13.2", features = ["ecdsa"] }
rand = "0.8"
byteorder = "1.5.0"
base64 = "0.22.1"
p256 = { workspace = true, features = ["ecdsa"] }
rand.workspace = true
base64.workspace = true
sqlx = { version = "0.8.2", features = [ "runtime-tokio", "sqlite", "macros" ] }
sqlx = { workspace = true, features = ["runtime-tokio", "sqlite", "macros", "migrate", "json"] }
quartz_nbt = { version = "0.2", features = ["serde"] }
hickory-resolver = "0.25"
quartz_nbt = { workspace = true, features = ["serde"] }
hickory-resolver.workspace = true
ariadne = { path = "../ariadne" }
ariadne.workspace = true
[target.'cfg(windows)'.dependencies]
winreg = "0.55.0"
winreg.workspace = true
[features]
tauri = ["dep:tauri"]

View File

@@ -6,6 +6,7 @@ use dashmap::DashMap;
use reqwest::Method;
use serde::Deserialize;
use std::path::PathBuf;
use sysinfo::{MemoryRefreshKind, RefreshKind};
use crate::util::io;
use crate::util::jre::extract_java_majorminor_version;
@@ -175,11 +176,10 @@ pub async fn test_jre(
// Gets maximum memory in KiB.
pub async fn get_max_memory() -> crate::Result<u64> {
Ok(sys_info::mem_info()
.map_err(|_| {
crate::Error::from(crate::ErrorKind::LauncherError(
"Unable to get computer memory".to_string(),
))
})?
.total)
Ok(sysinfo::System::new_with_specifics(
RefreshKind::nothing()
.with_memory(MemoryRefreshKind::nothing().with_ram()),
)
.total_memory()
/ 1024)
}

View File

@@ -17,7 +17,6 @@ use either::Either;
use enumset::{EnumSet, EnumSetType};
use fs4::tokio::AsyncFileExt;
use futures::StreamExt;
use lazy_static::lazy_static;
use quartz_nbt::{NbtCompound, NbtTag};
use regex::{Regex, RegexBuilder};
use serde::{Deserialize, Serialize};
@@ -25,6 +24,7 @@ use std::cmp::Reverse;
use std::io::Cursor;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use tokio::io::AsyncWriteExt;
use tokio_util::compat::FuturesAsyncWriteCompatExt;
use url::Url;
@@ -548,17 +548,19 @@ pub async fn backup_world(instance: &Path, world: &str) -> Result<u64> {
}
fn find_available_name(dir: &Path, file_name: &str, extension: &str) -> String {
lazy_static! {
static ref RESERVED_WINDOWS_FILENAMES: Regex = RegexBuilder::new(r#"^.*\.|(?:COM|CLOCK\$|CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\..*)?$"#)
static RESERVED_WINDOWS_FILENAMES: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(r#"^.*\.|(?:COM|CLOCK\$|CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\..*)?$"#)
.case_insensitive(true)
.build()
.unwrap();
static ref COPY_COUNTER_PATTERN: Regex = RegexBuilder::new(r#"^(?<name>.*) \((?<count>\d*)\)$"#)
.unwrap()
});
static COPY_COUNTER_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(r#"^(?<name>.*) \((?<count>\d*)\)$"#)
.case_insensitive(true)
.unicode(true)
.build()
.unwrap();
}
.unwrap()
});
let mut file_name = file_name.replace(
[

View File

@@ -5,30 +5,27 @@ use crate::state::{
DirectoryInfo, ProfileInstallStage, ProjectType, attached_world_data,
};
use crate::worlds::WorldType;
use futures::{SinkExt, StreamExt, channel::mpsc::channel};
use notify::{RecommendedWatcher, RecursiveMode};
use notify_debouncer_mini::{DebounceEventResult, Debouncer, new_debouncer};
use std::time::Duration;
use tokio::sync::RwLock;
use tokio::sync::{RwLock, mpsc::channel};
pub type FileWatcher = RwLock<Debouncer<RecommendedWatcher>>;
pub async fn init_watcher() -> crate::Result<FileWatcher> {
let (mut tx, mut rx) = channel(1);
let (tx, mut rx) = channel(1);
let file_watcher = new_debouncer(
Duration::from_secs_f32(1.0),
move |res: DebounceEventResult| {
futures::executor::block_on(async {
tx.send(res).await.unwrap();
})
tx.blocking_send(res).ok();
},
)?;
tokio::task::spawn(async move {
let span = tracing::span!(tracing::Level::INFO, "init_watcher");
tracing::info!(parent: &span, "Initting watcher");
while let Some(res) = rx.next().await {
while let Some(res) = rx.recv().await {
let _span = span.enter();
match res {

View File

@@ -2,7 +2,6 @@ use crate::ErrorKind;
use crate::util::fetch::REQWEST_CLIENT;
use base64::Engine;
use base64::prelude::{BASE64_STANDARD, BASE64_URL_SAFE_NO_PAD};
use byteorder::BigEndian;
use chrono::{DateTime, Duration, TimeZone, Utc};
use dashmap::DashMap;
use futures::TryStreamExt;
@@ -62,12 +61,6 @@ pub enum MinecraftAuthenticationError {
#[source]
source: reqwest::Error,
},
#[error("Error creating signed request buffer {step:?}: {source}")]
ConstructingSignedRequest {
step: MinecraftAuthStep,
#[source]
source: std::io::Error,
},
#[error("Error reading XBOX Session ID header")]
NoSessionId,
#[error("Error reading user hash")]
@@ -1087,56 +1080,25 @@ async fn send_signed_request<T: DeserializeOwned>(
let time: u128 =
{ ((current_date.timestamp() as u128) + 11644473600) * 10000000 };
use byteorder::WriteBytesExt;
let mut buffer = Vec::new();
buffer.write_u32::<BigEndian>(1).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
buffer.write_u8(0).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
buffer
.write_u64::<BigEndian>(time as u64)
.map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest {
source,
step,
}
})?;
buffer.write_u8(0).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
buffer.extend_from_slice(&1_u32.to_be_bytes()[..]);
buffer.push(0_u8);
buffer.extend_from_slice(&(time as u64).to_be_bytes()[..]);
buffer.push(0_u8);
buffer.extend_from_slice("POST".as_bytes());
buffer.write_u8(0).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
buffer.push(0_u8);
buffer.extend_from_slice(url_path.as_bytes());
buffer.write_u8(0).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
buffer.push(0_u8);
buffer.extend_from_slice(&auth);
buffer.write_u8(0).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
buffer.push(0_u8);
buffer.extend_from_slice(&body);
buffer.write_u8(0).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
buffer.push(0_u8);
let ecdsa_sig: Signature = key.key.sign(&buffer);
let mut sig_buffer = Vec::new();
sig_buffer.write_i32::<BigEndian>(1).map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest { source, step }
})?;
sig_buffer
.write_u64::<BigEndian>(time as u64)
.map_err(|source| {
MinecraftAuthenticationError::ConstructingSignedRequest {
source,
step,
}
})?;
sig_buffer.extend_from_slice(&1_i32.to_be_bytes()[..]);
sig_buffer.extend_from_slice(&(time as u64).to_be_bytes()[..]);
sig_buffer.extend_from_slice(&ecdsa_sig.r().to_bytes());
sig_buffer.extend_from_slice(&ecdsa_sig.s().to_bytes());

View File

@@ -9,7 +9,6 @@ use crate::util::fetch::{FetchSemaphore, IoSemaphore, write_cached_icon};
use crate::util::io::{self};
use chrono::{DateTime, TimeDelta, TimeZone, Utc};
use dashmap::DashMap;
use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize, Serialize};
use sqlx::SqlitePool;
@@ -17,6 +16,7 @@ use std::collections::HashSet;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::path::Path;
use std::sync::LazyLock;
use tokio::fs::DirEntry;
use tokio::io::{AsyncBufReadExt, AsyncRead};
use tokio::task::JoinSet;
@@ -837,9 +837,9 @@ impl Profile {
state: &crate::State,
join_entry: &mut JoinLogEntry,
) -> crate::Result<()> {
lazy_static! {
static ref LOG_LINE_REGEX: Regex = Regex::new(r"^\[[0-9]{2}(?::[0-9]{2}){2}] \[.+?/[A-Z]+?]: Connecting to (.+?), ([1-9][0-9]{0,4})$").unwrap();
}
static LOG_LINE_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"^\[[0-9]{2}(?::[0-9]{2}){2}] \[.+?/[A-Z]+?]: Connecting to (.+?), ([1-9][0-9]{0,4})$").unwrap()
});
let reader = tokio::io::BufReader::new(reader);
let mut lines = reader.lines();
while let Some(log_line) = lines.next_line().await? {

View File

@@ -1,14 +1,14 @@
//! Functions for fetching infromation from the Internet
//! Functions for fetching information from the Internet
use super::io::{self, IOError};
use crate::config::{MODRINTH_API_URL, MODRINTH_API_URL_V3};
use crate::event::LoadingBarId;
use crate::event::emit::emit_loading;
use bytes::Bytes;
use lazy_static::lazy_static;
use reqwest::Method;
use serde::de::DeserializeOwned;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use std::time::{self};
use tokio::sync::Semaphore;
use tokio::{fs::File, io::AsyncWriteExt};
@@ -18,22 +18,20 @@ pub struct IoSemaphore(pub Semaphore);
#[derive(Debug)]
pub struct FetchSemaphore(pub Semaphore);
lazy_static! {
pub static ref REQWEST_CLIENT: reqwest::Client = {
let mut headers = reqwest::header::HeaderMap::new();
let header = reqwest::header::HeaderValue::from_str(&format!(
"modrinth/theseus/{} (support@modrinth.com)",
env!("CARGO_PKG_VERSION")
))
.unwrap();
headers.insert(reqwest::header::USER_AGENT, header);
reqwest::Client::builder()
.tcp_keepalive(Some(time::Duration::from_secs(10)))
.default_headers(headers)
.build()
.expect("Reqwest Client Building Failed")
};
}
pub static REQWEST_CLIENT: LazyLock<reqwest::Client> = LazyLock::new(|| {
let mut headers = reqwest::header::HeaderMap::new();
let header = reqwest::header::HeaderValue::from_str(&format!(
"modrinth/theseus/{} (support@modrinth.com)",
env!("CARGO_PKG_VERSION")
))
.unwrap();
headers.insert(reqwest::header::USER_AGENT, header);
reqwest::Client::builder()
.tcp_keepalive(Some(time::Duration::from_secs(10)))
.default_headers(headers)
.build()
.expect("Reqwest Client Building Failed")
});
const FETCH_ATTEMPTS: usize = 3;
#[tracing::instrument(skip(semaphore))]

View File

@@ -276,11 +276,10 @@ pub async fn check_java_at_filepath(path: &Path) -> Option<JavaVersion> {
};
let bytes = include_bytes!("../../library/JavaInfo.class");
let tempdir: PathBuf = tempfile::tempdir().ok()?.into_path();
if !tempdir.exists() {
let Ok(tempdir) = tempfile::tempdir() else {
return None;
}
let file_path = tempdir.join("JavaInfo.class");
};
let file_path = tempdir.path().join("JavaInfo.class");
io::write(&file_path, bytes).await.ok()?;
let output = Command::new(&java)

View File

@@ -1,6 +1,5 @@
//! Platform-related code
use daedalus::minecraft::{Os, OsRule};
use regex::Regex;
// OS detection
pub trait OsExt {
@@ -92,12 +91,16 @@ pub fn os_rule(
}
}
if let Some(version) = &rule.version {
if let Ok(regex) = Regex::new(version.as_str()) {
rule_match &=
regex.is_match(&sys_info::os_release().unwrap_or_default());
}
}
// `rule.version` is ignored because it's not usually seen on real recent
// Minecraft version manifests, its alleged regex syntax is undefined and is
// likely to not match `Regex`'s, and the way to get the value to match it
// against is allegedly calling `System.getProperty("os.version")`, which
// on Windows the OpenJDK implements by fetching the kernel32.dll version,
// an approach that no public Rust library implements. Moreover, launchers
// such as PrismLauncher also ignore this field. Code references:
// - https://github.com/openjdk/jdk/blob/948ade8e7003a41683600428c8e3155c7ed798db/src/java.base/windows/native/libjava/java_props_md.c#L556
// - https://github.com/PrismLauncher/PrismLauncher/blob/1c20faccf88999474af70db098a4c10e7a03af33/launcher/minecraft/Rule.h#L77
// - https://github.com/FillZpp/sys-info-rs/blob/60ecf1470a5b7c90242f429934a3bacb6023ec4d/c/windows.c#L23-L38
rule_match
}

View File

@@ -4,13 +4,12 @@ version = "0.1.0"
edition = "2024"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "2.0.12"
uuid = { version = "1.2.2", features = ["v4", "fast-rng", "serde"] }
serde_bytes = "0.11"
rand = "0.8.5"
either = "1.13"
chrono = { version = "0.4.26", features = ["serde"] }
serde_cbor = "0.11"
lazy_static = "1.5"
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror.workspace = true
uuid = { workspace = true, features = ["v4", "fast-rng", "serde"] }
serde_bytes.workspace = true
rand.workspace = true
either.workspace = true
chrono = { workspace = true, features = ["serde"] }
serde_cbor.workspace = true

View File

@@ -1,8 +1,7 @@
use lazy_static::lazy_static;
use std::collections::HashMap;
use std::{collections::HashMap, sync::LazyLock};
lazy_static! {
static ref SPECIAL_PARENTS: HashMap<&'static str, &'static str> = {
static SPECIAL_PARENTS: LazyLock<HashMap<&'static str, &'static str>> =
LazyLock::new(|| {
let mut m = HashMap::new();
m.insert("15w14a", "1.8.3");
m.insert("1.RV-Pre1", "1.9.2");
@@ -12,8 +11,7 @@ lazy_static! {
m.insert("23w13a_or_b", "23w13a");
m.insert("24w14potato", "24w12a");
m
};
}
});
pub fn is_feature_supported_in(
version: &str,

View File

@@ -14,7 +14,7 @@ readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
thiserror = "2.0"
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
chrono = { workspace = true, features = ["serde"] }
thiserror.workspace = true