Updating + Profile Repairs + Performance Improvements (#97)
* repairing * Main framework for updating * add jsconfig * more work * Improve performance * Finish updating * run lint
This commit is contained in:
parent
c53104c28e
commit
f0b8a708a3
75
Cargo.lock
generated
75
Cargo.lock
generated
@ -587,19 +587,6 @@ dependencies = [
|
|||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"memoffset",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.15"
|
version = "0.8.15"
|
||||||
@ -987,16 +974,6 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fs2"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futf"
|
name = "futf"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@ -2278,17 +2255,6 @@ version = "1.5.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2eaf2319cd71dd9ff38c72bebde61b9ea657134abcf26ae4205f54f772a32810"
|
checksum = "2eaf2319cd71dd9ff38c72bebde61b9ea657134abcf26ae4205f54f772a32810"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
|
||||||
dependencies = [
|
|
||||||
"instant",
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core 0.8.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@ -2296,21 +2262,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"parking_lot_core 0.9.7",
|
"parking_lot_core",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.8.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"instant",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"smallvec",
|
|
||||||
"winapi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3120,23 +3072,6 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sled"
|
|
||||||
version = "0.34.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
|
|
||||||
dependencies = [
|
|
||||||
"crc32fast",
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"fs2",
|
|
||||||
"fxhash",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"parking_lot 0.11.2",
|
|
||||||
"zstd",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
@ -3204,7 +3139,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot",
|
||||||
"phf_shared 0.10.0",
|
"phf_shared 0.10.0",
|
||||||
"precomputed-hash",
|
"precomputed-hash",
|
||||||
"serde",
|
"serde",
|
||||||
@ -3340,7 +3275,7 @@ dependencies = [
|
|||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
"objc",
|
"objc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot",
|
||||||
"paste",
|
"paste",
|
||||||
"png",
|
"png",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@ -3575,7 +3510,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-tungstenite",
|
"async-tungstenite",
|
||||||
"async_zip",
|
"async_zip",
|
||||||
"bincode",
|
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"daedalus",
|
"daedalus",
|
||||||
@ -3591,7 +3525,6 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"sha1 0.6.1",
|
"sha1 0.6.1",
|
||||||
"sha2 0.9.9",
|
"sha2 0.9.9",
|
||||||
"sled",
|
|
||||||
"sys-info",
|
"sys-info",
|
||||||
"tauri",
|
"tauri",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -3772,7 +3705,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
|
|||||||
@ -8,22 +8,20 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
bincode = { version = "2.0.0-rc.1", features = ["serde"] }
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
toml = "0.7.3"
|
toml = "0.7.3"
|
||||||
sha1 = { version = "0.6.1", features = ["std"]}
|
sha1 = { version = "0.6.1", features = ["std"]}
|
||||||
sha2 = "0.9.9"
|
sha2 = "0.9.9"
|
||||||
sled = { version = "0.34.7", features = ["compression"] }
|
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
uuid = { version = "1.1", features = ["serde", "v4"] }
|
uuid = { version = "1.1", features = ["serde", "v4"] }
|
||||||
zip = "0.5"
|
zip = "0.5"
|
||||||
async_zip = { version = "0.0.13", features = ["full"] }
|
async_zip = { version = "0.0.13", features = ["full"] }
|
||||||
|
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
daedalus = { version = "0.1.18", features = ["bincode"] }
|
daedalus = { version = "0.1.18" }
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
# TODO: possibly replace with tracing to have structured logging
|
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
sys-info = "0.9.0"
|
sys-info = "0.9.0"
|
||||||
|
|||||||
@ -47,7 +47,7 @@ pub async fn authenticate(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let credentials = flow.extract_credentials(&state.io_semaphore).await?;
|
let credentials = flow.extract_credentials(&state.io_semaphore).await?;
|
||||||
users.insert(&credentials)?;
|
users.insert(&credentials).await?;
|
||||||
|
|
||||||
if state.settings.read().await.default_user.is_none() {
|
if state.settings.read().await.default_user.is_none() {
|
||||||
let mut settings = state.settings.write().await;
|
let mut settings = state.settings.write().await;
|
||||||
@ -65,7 +65,7 @@ pub async fn refresh(user: uuid::Uuid) -> crate::Result<Credentials> {
|
|||||||
let mut users = state.users.write().await;
|
let mut users = state.users.write().await;
|
||||||
|
|
||||||
let io_sempahore = &state.io_semaphore;
|
let io_sempahore = &state.io_semaphore;
|
||||||
futures::future::ready(users.get(user)?.ok_or_else(|| {
|
futures::future::ready(users.get(user).ok_or_else(|| {
|
||||||
crate::ErrorKind::OtherError(format!(
|
crate::ErrorKind::OtherError(format!(
|
||||||
"Tried to refresh nonexistent user with ID {user}"
|
"Tried to refresh nonexistent user with ID {user}"
|
||||||
))
|
))
|
||||||
@ -75,7 +75,7 @@ pub async fn refresh(user: uuid::Uuid) -> crate::Result<Credentials> {
|
|||||||
if chrono::offset::Utc::now() > credentials.expires {
|
if chrono::offset::Utc::now() > credentials.expires {
|
||||||
inner::refresh_credentials(&mut credentials, io_sempahore).await?;
|
inner::refresh_credentials(&mut credentials, io_sempahore).await?;
|
||||||
}
|
}
|
||||||
users.insert(&credentials)?;
|
users.insert(&credentials).await?;
|
||||||
Ok(credentials)
|
Ok(credentials)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -89,14 +89,10 @@ pub async fn remove_user(user: uuid::Uuid) -> crate::Result<()> {
|
|||||||
|
|
||||||
if state.settings.read().await.default_user == Some(user) {
|
if state.settings.read().await.default_user == Some(user) {
|
||||||
let mut settings = state.settings.write().await;
|
let mut settings = state.settings.write().await;
|
||||||
settings.default_user = users
|
settings.default_user = users.0.values().next().map(|it| it.id);
|
||||||
.0
|
|
||||||
.first()?
|
|
||||||
.map(|it| uuid::Uuid::from_slice(&it.0))
|
|
||||||
.transpose()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
users.remove(user)?;
|
users.remove(user).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,15 +102,15 @@ pub async fn has_user(user: uuid::Uuid) -> crate::Result<bool> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let users = state.users.read().await;
|
let users = state.users.read().await;
|
||||||
|
|
||||||
users.contains(user)
|
Ok(users.contains(user))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a copy of the list of all user credentials
|
/// Get a copy of the list of all user credentials
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn users() -> crate::Result<Box<[Credentials]>> {
|
pub async fn users() -> crate::Result<Vec<Credentials>> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let users = state.users.read().await;
|
let users = state.users.read().await;
|
||||||
users.iter().collect()
|
Ok(users.0.values().cloned().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a specific user by user ID
|
/// Get a specific user by user ID
|
||||||
@ -123,7 +119,7 @@ pub async fn users() -> crate::Result<Box<[Credentials]>> {
|
|||||||
pub async fn get_user(user: uuid::Uuid) -> crate::Result<Credentials> {
|
pub async fn get_user(user: uuid::Uuid) -> crate::Result<Credentials> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let users = state.users.read().await;
|
let users = state.users.read().await;
|
||||||
let user = users.get(user)?.ok_or_else(|| {
|
let user = users.get(user).ok_or_else(|| {
|
||||||
crate::ErrorKind::OtherError(format!(
|
crate::ErrorKind::OtherError(format!(
|
||||||
"Tried to get nonexistent user with ID {user}"
|
"Tried to get nonexistent user with ID {user}"
|
||||||
))
|
))
|
||||||
|
|||||||
@ -40,10 +40,10 @@ pub async fn autodetect_java_globals() -> crate::Result<JavaGlobals> {
|
|||||||
// this can be overwritten by the user a profile-by-profile basis
|
// this can be overwritten by the user a profile-by-profile basis
|
||||||
pub async fn get_optimal_jre_key(profile: &Profile) -> crate::Result<String> {
|
pub async fn get_optimal_jre_key(profile: &Profile) -> crate::Result<String> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
let metadata = state.metadata.read().await;
|
||||||
|
|
||||||
// Fetch version info from stored profile game_version
|
// Fetch version info from stored profile game_version
|
||||||
let version = state
|
let version = metadata
|
||||||
.metadata
|
|
||||||
.minecraft
|
.minecraft
|
||||||
.versions
|
.versions
|
||||||
.iter()
|
.iter()
|
||||||
@ -60,6 +60,7 @@ pub async fn get_optimal_jre_key(profile: &Profile) -> crate::Result<String> {
|
|||||||
&state,
|
&state,
|
||||||
version,
|
version,
|
||||||
profile.metadata.loader_version.as_ref(),
|
profile.metadata.loader_version.as_ref(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let optimal_key = match version_info
|
let optimal_key = match version_info
|
||||||
|
|||||||
@ -5,7 +5,7 @@ pub use daedalus::modded::Manifest;
|
|||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_minecraft_versions() -> crate::Result<VersionManifest> {
|
pub async fn get_minecraft_versions() -> crate::Result<VersionManifest> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.metadata.minecraft.clone();
|
let tags = state.metadata.read().await.minecraft.clone();
|
||||||
|
|
||||||
Ok(tags)
|
Ok(tags)
|
||||||
}
|
}
|
||||||
@ -13,7 +13,7 @@ pub async fn get_minecraft_versions() -> crate::Result<VersionManifest> {
|
|||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_fabric_versions() -> crate::Result<Manifest> {
|
pub async fn get_fabric_versions() -> crate::Result<Manifest> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.metadata.fabric.clone();
|
let tags = state.metadata.read().await.fabric.clone();
|
||||||
|
|
||||||
Ok(tags)
|
Ok(tags)
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ pub async fn get_fabric_versions() -> crate::Result<Manifest> {
|
|||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_forge_versions() -> crate::Result<Manifest> {
|
pub async fn get_forge_versions() -> crate::Result<Manifest> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.metadata.forge.clone();
|
let tags = state.metadata.read().await.forge.clone();
|
||||||
|
|
||||||
Ok(tags)
|
Ok(tags)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
use crate::config::MODRINTH_API_URL;
|
use crate::config::MODRINTH_API_URL;
|
||||||
use crate::data::ModLoader;
|
use crate::data::ModLoader;
|
||||||
use crate::event::emit::{init_loading, loading_try_for_each_concurrent};
|
use crate::event::emit::{
|
||||||
|
emit_loading, init_loading, loading_try_for_each_concurrent,
|
||||||
|
};
|
||||||
use crate::event::LoadingBarType;
|
use crate::event::LoadingBarType;
|
||||||
use crate::state::{ModrinthProject, ModrinthVersion, SideType};
|
use crate::state::{LinkedData, ModrinthProject, ModrinthVersion, SideType};
|
||||||
use crate::util::fetch::{
|
use crate::util::fetch::{
|
||||||
fetch, fetch_json, fetch_mirrors, write, write_cached_icon,
|
fetch, fetch_json, fetch_mirrors, write, write_cached_icon,
|
||||||
};
|
};
|
||||||
@ -218,13 +220,18 @@ async fn install_pack(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let pack_name = pack.name.clone();
|
let pack_name = pack.name.clone();
|
||||||
|
|
||||||
let profile = crate::api::profile_create::profile_create(
|
let profile = crate::api::profile_create::profile_create(
|
||||||
pack.name,
|
pack.name,
|
||||||
game_version.clone(),
|
game_version.clone(),
|
||||||
mod_loader.unwrap_or(ModLoader::Vanilla),
|
mod_loader.unwrap_or(ModLoader::Vanilla),
|
||||||
loader_version,
|
loader_version,
|
||||||
icon,
|
icon,
|
||||||
project_id.clone(),
|
Some(LinkedData {
|
||||||
|
project_id: project_id.clone(),
|
||||||
|
version_id: version_id.clone(),
|
||||||
|
}),
|
||||||
|
Some(true),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -238,6 +245,7 @@ async fn install_pack(
|
|||||||
"Downloading modpack...",
|
"Downloading modpack...",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let num_files = pack.files.len();
|
let num_files = pack.files.len();
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
loading_try_for_each_concurrent(
|
loading_try_for_each_concurrent(
|
||||||
@ -245,7 +253,7 @@ async fn install_pack(
|
|||||||
.map(Ok::<PackFile, crate::Error>),
|
.map(Ok::<PackFile, crate::Error>),
|
||||||
None,
|
None,
|
||||||
Some(&loading_bar),
|
Some(&loading_bar),
|
||||||
100.0,
|
80.0,
|
||||||
num_files,
|
num_files,
|
||||||
None,
|
None,
|
||||||
|project| {
|
|project| {
|
||||||
@ -344,11 +352,22 @@ async fn install_pack(
|
|||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
|
|
||||||
|
emit_loading(&loading_bar, 0.05, Some("Extracting overrides")).await?;
|
||||||
extract_overrides("overrides".to_string()).await?;
|
extract_overrides("overrides".to_string()).await?;
|
||||||
extract_overrides("client_overrides".to_string()).await?;
|
extract_overrides("client_overrides".to_string()).await?;
|
||||||
|
emit_loading(&loading_bar, 0.1, Some("Done extacting overrides"))
|
||||||
|
.await?;
|
||||||
|
|
||||||
super::profile::sync(&profile).await?;
|
super::profile::sync(&profile).await?;
|
||||||
|
|
||||||
|
if let Some(profile) = crate::api::profile::get(&profile).await? {
|
||||||
|
crate::launcher::install_minecraft(&profile, Some(loading_bar))
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
emit_loading(&loading_bar, 0.1, Some("Done extacting overrides"))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(profile)
|
Ok(profile)
|
||||||
} else {
|
} else {
|
||||||
Err(crate::Error::from(crate::ErrorKind::InputError(
|
Err(crate::Error::from(crate::ErrorKind::InputError(
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
//! Theseus profile management interface
|
//! Theseus profile management interface
|
||||||
|
use crate::event::emit::{init_loading, loading_try_for_each_concurrent};
|
||||||
|
use crate::event::LoadingBarType;
|
||||||
|
use crate::state::ProjectMetadata;
|
||||||
use crate::{
|
use crate::{
|
||||||
auth::{self, refresh},
|
auth::{self, refresh},
|
||||||
event::{emit::emit_profile, ProfilePayloadType},
|
event::{emit::emit_profile, ProfilePayloadType},
|
||||||
@ -22,7 +25,7 @@ pub async fn remove(path: &Path) -> crate::Result<()> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let mut profiles = state.profiles.write().await;
|
let mut profiles = state.profiles.write().await;
|
||||||
|
|
||||||
if let Some(profile) = profiles.0.get(path) {
|
if let Some(profile) = profiles.remove(path).await? {
|
||||||
emit_profile(
|
emit_profile(
|
||||||
profile.uuid,
|
profile.uuid,
|
||||||
profile.path.clone(),
|
profile.path.clone(),
|
||||||
@ -32,8 +35,6 @@ pub async fn remove(path: &Path) -> crate::Result<()> {
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles.remove(path).await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,20 +109,151 @@ pub async fn sync(path: &Path) -> crate::Result<()> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a project from a version
|
/// Installs/Repairs a profile
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn add_project_from_version(
|
pub async fn install(path: &Path) -> crate::Result<()> {
|
||||||
profile: &Path,
|
let state = State::get().await?;
|
||||||
|
let result = {
|
||||||
|
let mut profiles: tokio::sync::RwLockWriteGuard<
|
||||||
|
crate::state::Profiles,
|
||||||
|
> = state.profiles.write().await;
|
||||||
|
|
||||||
|
if let Some(profile) = profiles.0.get_mut(path) {
|
||||||
|
crate::launcher::install_minecraft(profile, None).await?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(crate::ErrorKind::UnmanagedProfileError(
|
||||||
|
path.display().to_string(),
|
||||||
|
)
|
||||||
|
.as_error())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
State::sync().await?;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_all(profile_path: &Path) -> crate::Result<()> {
|
||||||
|
let state = State::get().await?;
|
||||||
|
let mut profiles = state.profiles.write().await;
|
||||||
|
|
||||||
|
if let Some(profile) = profiles.0.get_mut(profile_path) {
|
||||||
|
let loading_bar = init_loading(
|
||||||
|
LoadingBarType::ProfileUpdate {
|
||||||
|
profile_uuid: profile.uuid,
|
||||||
|
profile_name: profile.metadata.name.clone(),
|
||||||
|
},
|
||||||
|
100.0,
|
||||||
|
"Updating profile...",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
|
loading_try_for_each_concurrent(
|
||||||
|
futures::stream::iter(profile.projects.keys())
|
||||||
|
.map(Ok::<&PathBuf, crate::Error>),
|
||||||
|
None,
|
||||||
|
Some(&loading_bar),
|
||||||
|
100.0,
|
||||||
|
profile.projects.len(),
|
||||||
|
None,
|
||||||
|
|project| update_project(profile_path, project, Some(true)),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
profile.sync().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(crate::ErrorKind::UnmanagedProfileError(
|
||||||
|
profile_path.display().to_string(),
|
||||||
|
)
|
||||||
|
.as_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_project(
|
||||||
|
profile_path: &Path,
|
||||||
|
project_path: &Path,
|
||||||
|
should_not_sync: Option<bool>,
|
||||||
|
) -> crate::Result<()> {
|
||||||
|
let state = State::get().await?;
|
||||||
|
let mut profiles = state.profiles.write().await;
|
||||||
|
|
||||||
|
if let Some(profile) = profiles.0.get_mut(profile_path) {
|
||||||
|
if let Some(project) = profile.projects.get(project_path) {
|
||||||
|
if let ProjectMetadata::Modrinth {
|
||||||
|
update_version: Some(update_version),
|
||||||
|
..
|
||||||
|
} = &project.metadata
|
||||||
|
{
|
||||||
|
let path = profile
|
||||||
|
.add_project_version(update_version.id.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if path != project_path {
|
||||||
|
profile.remove_project(project_path).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !should_not_sync.unwrap_or(false) {
|
||||||
|
profile.sync().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(crate::ErrorKind::UnmanagedProfileError(
|
||||||
|
profile_path.display().to_string(),
|
||||||
|
)
|
||||||
|
.as_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces a project given a new version ID
|
||||||
|
pub async fn replace_project(
|
||||||
|
profile_path: &Path,
|
||||||
|
project: &Path,
|
||||||
version_id: String,
|
version_id: String,
|
||||||
) -> crate::Result<PathBuf> {
|
) -> crate::Result<PathBuf> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let mut profiles = state.profiles.write().await;
|
let mut profiles = state.profiles.write().await;
|
||||||
|
|
||||||
if let Some(profile) = profiles.0.get_mut(profile) {
|
if let Some(profile) = profiles.0.get_mut(profile_path) {
|
||||||
profile.add_project_version(version_id).await
|
let path = profile.add_project_version(version_id).await?;
|
||||||
|
|
||||||
|
if path != project {
|
||||||
|
profile.remove_project(project).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.sync().await?;
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
} else {
|
} else {
|
||||||
Err(crate::ErrorKind::UnmanagedProfileError(
|
Err(crate::ErrorKind::UnmanagedProfileError(
|
||||||
profile.display().to_string(),
|
profile_path.display().to_string(),
|
||||||
|
)
|
||||||
|
.as_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a project from a version
|
||||||
|
#[tracing::instrument]
|
||||||
|
pub async fn add_project_from_version(
|
||||||
|
profile_path: &Path,
|
||||||
|
version_id: String,
|
||||||
|
) -> crate::Result<PathBuf> {
|
||||||
|
let state = State::get().await?;
|
||||||
|
let mut profiles = state.profiles.write().await;
|
||||||
|
|
||||||
|
if let Some(profile) = profiles.0.get_mut(profile_path) {
|
||||||
|
let path = profile.add_project_version(version_id).await?;
|
||||||
|
|
||||||
|
profile.sync().await?;
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
} else {
|
||||||
|
Err(crate::ErrorKind::UnmanagedProfileError(
|
||||||
|
profile_path.display().to_string(),
|
||||||
)
|
)
|
||||||
.as_error())
|
.as_error())
|
||||||
}
|
}
|
||||||
@ -130,14 +262,14 @@ pub async fn add_project_from_version(
|
|||||||
/// Add a project from an FS path
|
/// Add a project from an FS path
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn add_project_from_path(
|
pub async fn add_project_from_path(
|
||||||
profile: &Path,
|
profile_path: &Path,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
project_type: Option<String>,
|
project_type: Option<String>,
|
||||||
) -> crate::Result<PathBuf> {
|
) -> crate::Result<PathBuf> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let mut profiles = state.profiles.write().await;
|
let mut profiles = state.profiles.write().await;
|
||||||
|
|
||||||
if let Some(profile) = profiles.0.get_mut(profile) {
|
if let Some(profile) = profiles.0.get_mut(profile_path) {
|
||||||
let file = fs::read(path).await?;
|
let file = fs::read(path).await?;
|
||||||
let file_name = path
|
let file_name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
@ -145,16 +277,20 @@ pub async fn add_project_from_path(
|
|||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
profile
|
let path = profile
|
||||||
.add_project_bytes(
|
.add_project_bytes(
|
||||||
&file_name,
|
&file_name,
|
||||||
bytes::Bytes::from(file),
|
bytes::Bytes::from(file),
|
||||||
project_type.and_then(|x| serde_json::from_str(&x).ok()),
|
project_type.and_then(|x| serde_json::from_str(&x).ok()),
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
|
|
||||||
|
profile.sync().await?;
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
} else {
|
} else {
|
||||||
Err(crate::ErrorKind::UnmanagedProfileError(
|
Err(crate::ErrorKind::UnmanagedProfileError(
|
||||||
profile.display().to_string(),
|
profile_path.display().to_string(),
|
||||||
)
|
)
|
||||||
.as_error())
|
.as_error())
|
||||||
}
|
}
|
||||||
@ -214,7 +350,7 @@ pub async fn run(path: &Path) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
|||||||
} else {
|
} else {
|
||||||
// If no default account, try to use a logged in account
|
// If no default account, try to use a logged in account
|
||||||
let users = auth::users().await?;
|
let users = auth::users().await?;
|
||||||
let last_account = users.iter().next();
|
let last_account = users.first();
|
||||||
if let Some(last_account) = last_account {
|
if let Some(last_account) = last_account {
|
||||||
refresh(last_account.id).await?
|
refresh(last_account.id).await?
|
||||||
} else {
|
} else {
|
||||||
@ -233,6 +369,7 @@ pub async fn run_credentials(
|
|||||||
) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let settings = state.settings.read().await;
|
let settings = state.settings.read().await;
|
||||||
|
let metadata = state.metadata.read().await;
|
||||||
let profile = get(path).await?.ok_or_else(|| {
|
let profile = get(path).await?.ok_or_else(|| {
|
||||||
crate::ErrorKind::OtherError(format!(
|
crate::ErrorKind::OtherError(format!(
|
||||||
"Tried to run a nonexistent or unloaded profile at path {}!",
|
"Tried to run a nonexistent or unloaded profile at path {}!",
|
||||||
@ -240,8 +377,7 @@ pub async fn run_credentials(
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let version = state
|
let version = metadata
|
||||||
.metadata
|
|
||||||
.minecraft
|
.minecraft
|
||||||
.versions
|
.versions
|
||||||
.iter()
|
.iter()
|
||||||
@ -256,6 +392,7 @@ pub async fn run_credentials(
|
|||||||
&state,
|
&state,
|
||||||
version,
|
version,
|
||||||
profile.metadata.loader_version.as_ref(),
|
profile.metadata.loader_version.as_ref(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let pre_launch_hooks =
|
let pre_launch_hooks =
|
||||||
@ -358,9 +495,6 @@ pub async fn run_credentials(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mc_process = crate::launcher::launch_minecraft(
|
let mc_process = crate::launcher::launch_minecraft(
|
||||||
&profile.metadata.game_version,
|
|
||||||
&profile.metadata.loader_version,
|
|
||||||
&profile.path,
|
|
||||||
java_install,
|
java_install,
|
||||||
java_args,
|
java_args,
|
||||||
env_args,
|
env_args,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
//! Theseus profile management interface
|
//! Theseus profile management interface
|
||||||
|
use crate::state::LinkedData;
|
||||||
use crate::{
|
use crate::{
|
||||||
event::{emit::emit_profile, ProfilePayloadType},
|
event::{emit::emit_profile, ProfilePayloadType},
|
||||||
jre,
|
jre,
|
||||||
@ -29,6 +30,7 @@ pub async fn profile_create_empty() -> crate::Result<PathBuf> {
|
|||||||
None, // the modloader version to use, set to "latest", "stable", or the ID of your chosen loader
|
None, // the modloader version to use, set to "latest", "stable", or the ID of your chosen loader
|
||||||
None, // the icon for the profile
|
None, // the icon for the profile
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@ -42,9 +44,11 @@ pub async fn profile_create(
|
|||||||
modloader: ModLoader, // the modloader to use
|
modloader: ModLoader, // the modloader to use
|
||||||
loader_version: Option<String>, // the modloader version to use, set to "latest", "stable", or the ID of your chosen loader. defaults to latest
|
loader_version: Option<String>, // the modloader version to use, set to "latest", "stable", or the ID of your chosen loader. defaults to latest
|
||||||
icon: Option<PathBuf>, // the icon for the profile
|
icon: Option<PathBuf>, // the icon for the profile
|
||||||
linked_project_id: Option<String>, // the linked project ID (mainly for modpacks)- used for updating
|
linked_data: Option<LinkedData>, // the linked project ID (mainly for modpacks)- used for updating
|
||||||
|
skip_install_profile: Option<bool>,
|
||||||
) -> crate::Result<PathBuf> {
|
) -> crate::Result<PathBuf> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
let metadata = state.metadata.read().await;
|
||||||
|
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
let path = state.directories.profiles_dir().join(uuid.to_string());
|
let path = state.directories.profiles_dir().join(uuid.to_string());
|
||||||
@ -86,8 +90,8 @@ pub async fn profile_create(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let loader_data = match loader {
|
let loader_data = match loader {
|
||||||
ModLoader::Forge => &state.metadata.forge,
|
ModLoader::Forge => &metadata.forge,
|
||||||
ModLoader::Fabric => &state.metadata.fabric,
|
ModLoader::Fabric => &metadata.fabric,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ProfileCreationError::NoManifest(
|
return Err(ProfileCreationError::NoManifest(
|
||||||
loader.to_string(),
|
loader.to_string(),
|
||||||
@ -157,7 +161,7 @@ pub async fn profile_create(
|
|||||||
profile.metadata.loader_version = Some(loader_version);
|
profile.metadata.loader_version = Some(loader_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
profile.metadata.linked_project_id = linked_project_id;
|
profile.metadata.linked_data = linked_data;
|
||||||
|
|
||||||
// Attempts to find optimal JRE for the profile from the JavaGlobals
|
// Attempts to find optimal JRE for the profile from the JavaGlobals
|
||||||
// Finds optimal key, and see if key has been set in JavaGlobals
|
// Finds optimal key, and see if key has been set in JavaGlobals
|
||||||
@ -179,11 +183,15 @@ pub async fn profile_create(
|
|||||||
ProfilePayloadType::Created,
|
ProfilePayloadType::Created,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut profiles = state.profiles.write().await;
|
let mut profiles = state.profiles.write().await;
|
||||||
profiles.insert(profile).await?;
|
profiles.insert(profile.clone()).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !skip_install_profile.unwrap_or(false) {
|
||||||
|
crate::launcher::install_minecraft(&profile, None).await?;
|
||||||
|
}
|
||||||
State::sync().await?;
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(path)
|
Ok(path)
|
||||||
|
|||||||
@ -1,18 +1,16 @@
|
|||||||
//! Theseus tag management interface
|
//! Theseus tag management interface
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
state::{
|
state::{Category, DonationPlatform, GameVersion, Loader, Tags},
|
||||||
Category, DonationPlatform, GameVersion, License, Loader, TagBundle,
|
|
||||||
},
|
|
||||||
State,
|
State,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get bundled set of tags
|
// Get bundled set of tags
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_tag_bundle() -> crate::Result<TagBundle> {
|
pub async fn get_tag_bundle() -> crate::Result<Tags> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.tags.read().await;
|
let tags = state.tags.read().await;
|
||||||
|
|
||||||
tags.get_tag_bundle()
|
Ok(tags.get_tag_bundle())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get category tags
|
/// Get category tags
|
||||||
@ -21,7 +19,7 @@ pub async fn get_category_tags() -> crate::Result<Vec<Category>> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.tags.read().await;
|
let tags = state.tags.read().await;
|
||||||
|
|
||||||
tags.get_categories()
|
Ok(tags.get_categories())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get report type tags
|
/// Get report type tags
|
||||||
@ -30,7 +28,7 @@ pub async fn get_report_type_tags() -> crate::Result<Vec<String>> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.tags.read().await;
|
let tags = state.tags.read().await;
|
||||||
|
|
||||||
tags.get_report_types()
|
Ok(tags.get_report_types())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get loader tags
|
/// Get loader tags
|
||||||
@ -39,7 +37,7 @@ pub async fn get_loader_tags() -> crate::Result<Vec<Loader>> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.tags.read().await;
|
let tags = state.tags.read().await;
|
||||||
|
|
||||||
tags.get_loaders()
|
Ok(tags.get_loaders())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get game version tags
|
/// Get game version tags
|
||||||
@ -48,16 +46,7 @@ pub async fn get_game_version_tags() -> crate::Result<Vec<GameVersion>> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.tags.read().await;
|
let tags = state.tags.read().await;
|
||||||
|
|
||||||
tags.get_game_versions()
|
Ok(tags.get_game_versions())
|
||||||
}
|
|
||||||
|
|
||||||
/// Get license tags
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub async fn get_license_tags() -> crate::Result<Vec<License>> {
|
|
||||||
let state = State::get().await?;
|
|
||||||
let tags = state.tags.read().await;
|
|
||||||
|
|
||||||
tags.get_licenses()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get donation platform tags
|
/// Get donation platform tags
|
||||||
@ -67,5 +56,5 @@ pub async fn get_donation_platform_tags() -> crate::Result<Vec<DonationPlatform>
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let tags = state.tags.read().await;
|
let tags = state.tags.read().await;
|
||||||
|
|
||||||
tags.get_donation_platforms()
|
Ok(tags.get_donation_platforms())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,3 @@
|
|||||||
//! Configuration structs
|
//! Configuration structs
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref BINCODE_CONFIG: bincode::config::Configuration =
|
|
||||||
bincode::config::standard()
|
|
||||||
.with_little_endian()
|
|
||||||
.with_no_limit();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const MODRINTH_API_URL: &str = "https://api.modrinth.com/v2/";
|
pub const MODRINTH_API_URL: &str = "https://api.modrinth.com/v2/";
|
||||||
|
|
||||||
pub fn sled_config() -> sled::Config {
|
|
||||||
sled::Config::default().use_compression(true)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,18 +13,9 @@ pub enum ErrorKind {
|
|||||||
#[error("Error parsing UUID: {0}")]
|
#[error("Error parsing UUID: {0}")]
|
||||||
UUIDError(#[from] uuid::Error),
|
UUIDError(#[from] uuid::Error),
|
||||||
|
|
||||||
#[error("Serialization error (Bincode): {0}")]
|
|
||||||
EncodeError(#[from] bincode::error::EncodeError),
|
|
||||||
|
|
||||||
#[error("Deserialization error (Bincode): {0}")]
|
|
||||||
DecodeError(#[from] bincode::error::DecodeError),
|
|
||||||
|
|
||||||
#[error("Error parsing URL: {0}")]
|
#[error("Error parsing URL: {0}")]
|
||||||
URLError(#[from] url::ParseError),
|
URLError(#[from] url::ParseError),
|
||||||
|
|
||||||
#[error("Database error: {0}")]
|
|
||||||
DBError(#[from] sled::Error),
|
|
||||||
|
|
||||||
#[error("Unable to read {0} from any source")]
|
#[error("Unable to read {0} from any source")]
|
||||||
NoValueFor(String),
|
NoValueFor(String),
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::event::{
|
use crate::event::{
|
||||||
EventError, LoadingBar, LoadingBarId, LoadingBarType, ProcessPayloadType,
|
EventError, LoadingBar, LoadingBarType, ProcessPayloadType,
|
||||||
ProfilePayloadType,
|
ProfilePayloadType,
|
||||||
};
|
};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
@ -11,6 +11,7 @@ use crate::event::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "tauri")]
|
#[cfg(feature = "tauri")]
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Events are a way we can communciate with the Tauri frontend from the Rust backend.
|
Events are a way we can communciate with the Tauri frontend from the Rust backend.
|
||||||
@ -39,22 +40,23 @@ use tauri::Manager;
|
|||||||
// Initialize a loading bar for use in emit_loading
|
// Initialize a loading bar for use in emit_loading
|
||||||
// This will generate a LoadingBarId, which is used to refer to the loading bar uniquely.
|
// This will generate a LoadingBarId, which is used to refer to the loading bar uniquely.
|
||||||
// total is the total amount of work to be done- all emissions will be considered a fraction of this value (should be 1 or 100 for simplicity)
|
// total is the total amount of work to be done- all emissions will be considered a fraction of this value (should be 1 or 100 for simplicity)
|
||||||
// default_message is the message to display on the loading bar if no message is passed to emit_loading
|
// title is the title of the loading bar
|
||||||
pub async fn init_loading(
|
pub async fn init_loading(
|
||||||
bar_type: LoadingBarType,
|
bar_type: LoadingBarType,
|
||||||
total: f64,
|
total: f64,
|
||||||
default_message: &str,
|
title: &str,
|
||||||
) -> crate::Result<LoadingBarId> {
|
) -> crate::Result<Uuid> {
|
||||||
let event_state = crate::EventState::get().await?;
|
let event_state = crate::EventState::get().await?;
|
||||||
let key = LoadingBarId::new(bar_type);
|
let key = Uuid::new_v4();
|
||||||
|
|
||||||
event_state.loading_bars.write().await.insert(
|
event_state.loading_bars.write().await.insert(
|
||||||
key.clone(),
|
key,
|
||||||
LoadingBar {
|
LoadingBar {
|
||||||
loading_bar_id: key.clone(),
|
loading_bar_id: key,
|
||||||
message: default_message.to_string(),
|
message: title.to_string(),
|
||||||
total,
|
total,
|
||||||
current: 0.0,
|
current: 0.0,
|
||||||
|
bar_type,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// attempt an initial loading_emit event to the frontend
|
// attempt an initial loading_emit event to the frontend
|
||||||
@ -62,6 +64,40 @@ pub async fn init_loading(
|
|||||||
Ok(key)
|
Ok(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn init_or_edit_loading(
|
||||||
|
id: Option<Uuid>,
|
||||||
|
bar_type: LoadingBarType,
|
||||||
|
total: f64,
|
||||||
|
title: &str,
|
||||||
|
) -> crate::Result<Uuid> {
|
||||||
|
if let Some(id) = id {
|
||||||
|
edit_loading(id, bar_type, total, title).await?;
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
} else {
|
||||||
|
init_loading(bar_type, total, title).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edits a loading bar's type
|
||||||
|
pub async fn edit_loading(
|
||||||
|
id: Uuid,
|
||||||
|
bar_type: LoadingBarType,
|
||||||
|
total: f64,
|
||||||
|
title: &str,
|
||||||
|
) -> crate::Result<()> {
|
||||||
|
let event_state = crate::EventState::get().await?;
|
||||||
|
|
||||||
|
if let Some(bar) = event_state.loading_bars.write().await.get_mut(&id) {
|
||||||
|
bar.bar_type = bar_type;
|
||||||
|
bar.total = total;
|
||||||
|
bar.message = title.to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
emit_loading(&id, 0.0, None).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// emit_loading emits a loading event to the frontend
|
// emit_loading emits a loading event to the frontend
|
||||||
// key refers to the loading bar to update
|
// key refers to the loading bar to update
|
||||||
// increment refers to by what relative increment to the loading struct's total to update
|
// increment refers to by what relative increment to the loading struct's total to update
|
||||||
@ -69,7 +105,7 @@ pub async fn init_loading(
|
|||||||
// By convention, fraction is the fraction of the progress bar that is filled
|
// By convention, fraction is the fraction of the progress bar that is filled
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub async fn emit_loading(
|
pub async fn emit_loading(
|
||||||
key: &LoadingBarId,
|
key: &Uuid,
|
||||||
increment_frac: f64,
|
increment_frac: f64,
|
||||||
message: Option<&str>,
|
message: Option<&str>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
@ -79,14 +115,14 @@ pub async fn emit_loading(
|
|||||||
let loading_bar = match loading_bar.get_mut(key) {
|
let loading_bar = match loading_bar.get_mut(key) {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => {
|
None => {
|
||||||
return Err(EventError::NoLoadingBar(key.clone()).into());
|
return Err(EventError::NoLoadingBar(*key).into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tick up loading bar
|
// Tick up loading bar
|
||||||
loading_bar.current += increment_frac;
|
loading_bar.current += increment_frac;
|
||||||
let display_frac = loading_bar.current / loading_bar.total;
|
let display_frac = loading_bar.current / loading_bar.total;
|
||||||
let display_frac = if display_frac > 1.0 {
|
let display_frac = if display_frac >= 1.0 {
|
||||||
None // by convention, when its done, we submit None
|
None // by convention, when its done, we submit None
|
||||||
// any further updates will be ignored (also sending None)
|
// any further updates will be ignored (also sending None)
|
||||||
} else {
|
} else {
|
||||||
@ -101,8 +137,8 @@ pub async fn emit_loading(
|
|||||||
LoadingPayload {
|
LoadingPayload {
|
||||||
fraction: display_frac,
|
fraction: display_frac,
|
||||||
message: message.unwrap_or(&loading_bar.message).to_string(),
|
message: message.unwrap_or(&loading_bar.message).to_string(),
|
||||||
event: key.key.clone(),
|
event: loading_bar.bar_type.clone(),
|
||||||
loader_uuid: key.uuid,
|
loader_uuid: loading_bar.loading_bar_id,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.map_err(EventError::from)?;
|
.map_err(EventError::from)?;
|
||||||
@ -132,7 +168,7 @@ pub async fn emit_warning(message: &str) -> crate::Result<()> {
|
|||||||
// emit_process(uuid, pid, event, message)
|
// emit_process(uuid, pid, event, message)
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub async fn emit_process(
|
pub async fn emit_process(
|
||||||
uuid: uuid::Uuid,
|
uuid: Uuid,
|
||||||
pid: u32,
|
pid: u32,
|
||||||
event: ProcessPayloadType,
|
event: ProcessPayloadType,
|
||||||
message: &str,
|
message: &str,
|
||||||
@ -159,7 +195,7 @@ pub async fn emit_process(
|
|||||||
// emit_profile(path, event)
|
// emit_profile(path, event)
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub async fn emit_profile(
|
pub async fn emit_profile(
|
||||||
uuid: uuid::Uuid,
|
uuid: Uuid,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
name: &str,
|
name: &str,
|
||||||
event: ProfilePayloadType,
|
event: ProfilePayloadType,
|
||||||
@ -253,7 +289,7 @@ macro_rules! loading_join {
|
|||||||
pub async fn loading_try_for_each_concurrent<I, F, Fut, T>(
|
pub async fn loading_try_for_each_concurrent<I, F, Fut, T>(
|
||||||
stream: I,
|
stream: I,
|
||||||
limit: Option<usize>,
|
limit: Option<usize>,
|
||||||
key: Option<&LoadingBarId>,
|
key: Option<&Uuid>,
|
||||||
total: f64,
|
total: f64,
|
||||||
num_futs: usize, // num is in here as we allow Iterator to be passed in, which doesn't have a size
|
num_futs: usize, // num is in here as we allow Iterator to be passed in, which doesn't have a size
|
||||||
message: Option<&str>,
|
message: Option<&str>,
|
||||||
@ -285,7 +321,7 @@ where
|
|||||||
pub async fn loading_try_for_each_concurrent<I, F, Fut, T>(
|
pub async fn loading_try_for_each_concurrent<I, F, Fut, T>(
|
||||||
stream: I,
|
stream: I,
|
||||||
limit: Option<usize>,
|
limit: Option<usize>,
|
||||||
_key: Option<&LoadingBarId>,
|
_key: Option<&Uuid>,
|
||||||
_total: f64,
|
_total: f64,
|
||||||
_num_futs: usize, // num is in here as we allow Iterator to be passed in, which doesn't have a size
|
_num_futs: usize, // num is in here as we allow Iterator to be passed in, which doesn't have a size
|
||||||
_message: Option<&str>,
|
_message: Option<&str>,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! Theseus state management system
|
//! Theseus state management system
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fmt, path::PathBuf, sync::Arc};
|
use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -14,7 +14,7 @@ pub struct EventState {
|
|||||||
/// Tauri app
|
/// Tauri app
|
||||||
#[cfg(feature = "tauri")]
|
#[cfg(feature = "tauri")]
|
||||||
pub app: tauri::AppHandle,
|
pub app: tauri::AppHandle,
|
||||||
pub loading_bars: RwLock<HashMap<LoadingBarId, LoadingBar>>,
|
pub loading_bars: RwLock<HashMap<Uuid, LoadingBar>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventState {
|
impl EventState {
|
||||||
@ -48,6 +48,13 @@ impl EventState {
|
|||||||
Ok(EVENT_STATE.get().ok_or(EventError::NotInitialized)?.clone())
|
Ok(EVENT_STATE.get().ok_or(EventError::NotInitialized)?.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_progress_bars() -> crate::Result<HashMap<Uuid, LoadingBar>>
|
||||||
|
{
|
||||||
|
let value = Self::get().await?;
|
||||||
|
let read = value.loading_bars.read().await;
|
||||||
|
Ok(read.clone())
|
||||||
|
}
|
||||||
|
|
||||||
// Initialization requires no app handle in non-tauri mode, so we can just use the same function
|
// Initialization requires no app handle in non-tauri mode, so we can just use the same function
|
||||||
#[cfg(not(feature = "tauri"))]
|
#[cfg(not(feature = "tauri"))]
|
||||||
pub async fn get() -> crate::Result<Arc<Self>> {
|
pub async fn get() -> crate::Result<Arc<Self>> {
|
||||||
@ -55,35 +62,13 @@ impl EventState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Serialize, Debug, Clone)]
|
||||||
pub struct LoadingBar {
|
pub struct LoadingBar {
|
||||||
pub loading_bar_id: LoadingBarId,
|
pub loading_bar_id: Uuid,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub total: f64,
|
pub total: f64,
|
||||||
pub current: f64,
|
pub current: f64,
|
||||||
}
|
pub bar_type: LoadingBarType,
|
||||||
|
|
||||||
// Loading Bar Id lets us uniquely identify loading bars stored in the state
|
|
||||||
// the uuid lets us identify loading bars across threads
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct LoadingBarId {
|
|
||||||
pub key: LoadingBarType,
|
|
||||||
pub uuid: Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LoadingBarId {
|
|
||||||
pub fn new(key: LoadingBarType) -> Self {
|
|
||||||
Self {
|
|
||||||
key,
|
|
||||||
uuid: Uuid::new_v4(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for LoadingBarId {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{:?}-{}", self.key, self.uuid)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
@ -98,7 +83,10 @@ pub enum LoadingBarType {
|
|||||||
profile_uuid: Uuid,
|
profile_uuid: Uuid,
|
||||||
profile_name: String,
|
profile_name: String,
|
||||||
},
|
},
|
||||||
ProfileSync,
|
ProfileUpdate {
|
||||||
|
profile_uuid: Uuid,
|
||||||
|
profile_name: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Clone)]
|
#[derive(Serialize, Clone)]
|
||||||
@ -139,6 +127,7 @@ pub struct ProfilePayload {
|
|||||||
pub enum ProfilePayloadType {
|
pub enum ProfilePayloadType {
|
||||||
Created,
|
Created,
|
||||||
Added, // also triggered when Created
|
Added, // also triggered when Created
|
||||||
|
Synced,
|
||||||
Edited,
|
Edited,
|
||||||
Removed,
|
Removed,
|
||||||
}
|
}
|
||||||
@ -149,7 +138,7 @@ pub enum EventError {
|
|||||||
NotInitialized,
|
NotInitialized,
|
||||||
|
|
||||||
#[error("Non-existent loading bar of key: {0}")]
|
#[error("Non-existent loading bar of key: {0}")]
|
||||||
NoLoadingBar(LoadingBarId),
|
NoLoadingBar(Uuid),
|
||||||
|
|
||||||
#[cfg(feature = "tauri")]
|
#[cfg(feature = "tauri")]
|
||||||
#[error("Tauri error: {0}")]
|
#[error("Tauri error: {0}")]
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
//! Authentication flow based on Hydra
|
//! Authentication flow based on Hydra
|
||||||
use crate::util::fetch::{fetch_advanced, fetch_json};
|
use crate::util::fetch::{fetch_advanced, fetch_json};
|
||||||
use async_tungstenite as ws;
|
use async_tungstenite as ws;
|
||||||
use bincode::{Decode, Encode};
|
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -50,14 +49,12 @@ struct ProfileInfoJSON {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login information
|
// Login information
|
||||||
#[derive(Encode, Decode, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Credentials {
|
pub struct Credentials {
|
||||||
#[bincode(with_serde)]
|
|
||||||
pub id: uuid::Uuid,
|
pub id: uuid::Uuid,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub access_token: String,
|
pub access_token: String,
|
||||||
pub refresh_token: String,
|
pub refresh_token: String,
|
||||||
#[bincode(with_serde)]
|
|
||||||
pub expires: DateTime<Utc>,
|
pub expires: DateTime<Utc>,
|
||||||
_ctor_scope: std::marker::PhantomData<()>,
|
_ctor_scope: std::marker::PhantomData<()>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
//! Downloader for Minecraft data
|
//! Downloader for Minecraft data
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
event::{
|
event::emit::{emit_loading, loading_try_for_each_concurrent},
|
||||||
emit::{emit_loading, init_loading, loading_try_for_each_concurrent},
|
|
||||||
LoadingBarId, LoadingBarType,
|
|
||||||
},
|
|
||||||
process::Profile,
|
|
||||||
state::State,
|
state::State,
|
||||||
util::{fetch::*, platform::OsExt},
|
util::{fetch::*, platform::OsExt},
|
||||||
};
|
};
|
||||||
@ -19,26 +15,17 @@ use daedalus::{
|
|||||||
};
|
};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use tokio::{fs, sync::OnceCell};
|
use tokio::{fs, sync::OnceCell};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn download_minecraft(
|
pub async fn download_minecraft(
|
||||||
st: &State,
|
st: &State,
|
||||||
version: &GameVersionInfo,
|
version: &GameVersionInfo,
|
||||||
profile: &Profile,
|
loading_bar: Uuid,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
log::info!("Downloading Minecraft version {}", version.id);
|
log::info!("Downloading Minecraft version {}", version.id);
|
||||||
let assets_index = download_assets_index(st, version).await?;
|
let assets_index = download_assets_index(st, version).await?;
|
||||||
|
|
||||||
let loading_bar = init_loading(
|
|
||||||
LoadingBarType::MinecraftDownload {
|
|
||||||
// If we are downloading minecraft for a profile, provide its name and uuid
|
|
||||||
profile_name: profile.metadata.name.clone(),
|
|
||||||
profile_uuid: profile.uuid,
|
|
||||||
},
|
|
||||||
100.0,
|
|
||||||
"Downloading Minecraft...",
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
tokio::try_join! {
|
tokio::try_join! {
|
||||||
download_client(st, version, Some(&loading_bar)),
|
download_client(st, version, Some(&loading_bar)),
|
||||||
download_assets(st, version.assets == "legacy", &assets_index, Some(&loading_bar)),
|
download_assets(st, version.assets == "legacy", &assets_index, Some(&loading_bar)),
|
||||||
@ -54,6 +41,7 @@ pub async fn download_version_info(
|
|||||||
st: &State,
|
st: &State,
|
||||||
version: &GameVersion,
|
version: &GameVersion,
|
||||||
loader: Option<&LoaderVersion>,
|
loader: Option<&LoaderVersion>,
|
||||||
|
force: Option<bool>,
|
||||||
) -> crate::Result<GameVersionInfo> {
|
) -> crate::Result<GameVersionInfo> {
|
||||||
let version_id = loader
|
let version_id = loader
|
||||||
.map_or(version.id.clone(), |it| format!("{}-{}", version.id, it.id));
|
.map_or(version.id.clone(), |it| format!("{}-{}", version.id, it.id));
|
||||||
@ -63,7 +51,7 @@ pub async fn download_version_info(
|
|||||||
.version_dir(&version_id)
|
.version_dir(&version_id)
|
||||||
.join(format!("{version_id}.json"));
|
.join(format!("{version_id}.json"));
|
||||||
|
|
||||||
let res = if path.exists() {
|
let res = if path.exists() && !force.unwrap_or(false) {
|
||||||
fs::read(path)
|
fs::read(path)
|
||||||
.err_into::<crate::Error>()
|
.err_into::<crate::Error>()
|
||||||
.await
|
.await
|
||||||
@ -90,7 +78,7 @@ pub async fn download_version_info(
|
|||||||
pub async fn download_client(
|
pub async fn download_client(
|
||||||
st: &State,
|
st: &State,
|
||||||
version_info: &GameVersionInfo,
|
version_info: &GameVersionInfo,
|
||||||
loading_bar: Option<&LoadingBarId>,
|
loading_bar: Option<&Uuid>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let version = &version_info.id;
|
let version = &version_info.id;
|
||||||
log::debug!("Locating client for version {version}");
|
log::debug!("Locating client for version {version}");
|
||||||
@ -158,7 +146,7 @@ pub async fn download_assets(
|
|||||||
st: &State,
|
st: &State,
|
||||||
with_legacy: bool,
|
with_legacy: bool,
|
||||||
index: &AssetsIndex,
|
index: &AssetsIndex,
|
||||||
loading_bar: Option<&LoadingBarId>,
|
loading_bar: Option<&Uuid>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
log::debug!("Loading assets");
|
log::debug!("Loading assets");
|
||||||
let num_futs = index.objects.len();
|
let num_futs = index.objects.len();
|
||||||
@ -219,7 +207,7 @@ pub async fn download_libraries(
|
|||||||
st: &State,
|
st: &State,
|
||||||
libraries: &[Library],
|
libraries: &[Library],
|
||||||
version: &str,
|
version: &str,
|
||||||
loading_bar: Option<&LoadingBarId>,
|
loading_bar: Option<&Uuid>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
log::debug!("Loading libraries");
|
log::debug!("Loading libraries");
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
//! Logic for launching Minecraft
|
//! Logic for launching Minecraft
|
||||||
|
use crate::event::emit::{emit_loading, init_or_edit_loading};
|
||||||
|
use crate::event::LoadingBarType;
|
||||||
use crate::{
|
use crate::{
|
||||||
process,
|
process,
|
||||||
state::{self as st, MinecraftChild},
|
state::{self as st, MinecraftChild},
|
||||||
@ -8,6 +10,7 @@ use dunce::canonicalize;
|
|||||||
use st::Profile;
|
use st::Profile;
|
||||||
use std::{path::Path, process::Stdio, sync::Arc};
|
use std::{path::Path, process::Stdio, sync::Arc};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
|
|
||||||
@ -48,55 +51,60 @@ macro_rules! processor_rules {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
pub async fn install_minecraft(
|
||||||
#[tracing::instrument(skip_all, fields(path = ?instance_path))]
|
profile: &Profile,
|
||||||
pub async fn launch_minecraft(
|
existing_loading_bar: Option<Uuid>,
|
||||||
game_version: &str,
|
) -> crate::Result<()> {
|
||||||
loader_version: &Option<d::modded::LoaderVersion>,
|
|
||||||
instance_path: &Path,
|
|
||||||
java_install: &Path,
|
|
||||||
java_args: &[String],
|
|
||||||
env_args: &[(String, String)],
|
|
||||||
wrapper: &Option<String>,
|
|
||||||
memory: &st::MemorySettings,
|
|
||||||
resolution: &st::WindowSize,
|
|
||||||
credentials: &auth::Credentials,
|
|
||||||
post_exit_hook: Option<Command>,
|
|
||||||
profile: &Profile, // optional ref to Profile for event tracking
|
|
||||||
) -> crate::Result<Arc<tokio::sync::RwLock<MinecraftChild>>> {
|
|
||||||
let state = st::State::get().await?;
|
let state = st::State::get().await?;
|
||||||
let instance_path = &canonicalize(instance_path)?;
|
let instance_path = &canonicalize(&profile.path)?;
|
||||||
|
let metadata = state.metadata.read().await;
|
||||||
|
|
||||||
let version = state
|
let version = metadata
|
||||||
.metadata
|
|
||||||
.minecraft
|
.minecraft
|
||||||
.versions
|
.versions
|
||||||
.iter()
|
.iter()
|
||||||
.find(|it| it.id == game_version)
|
.find(|it| it.id == profile.metadata.game_version)
|
||||||
.ok_or(crate::ErrorKind::LauncherError(format!(
|
.ok_or(crate::ErrorKind::LauncherError(format!(
|
||||||
"Invalid game version: {game_version}"
|
"Invalid game version: {}",
|
||||||
|
profile.metadata.game_version
|
||||||
)))?;
|
)))?;
|
||||||
|
|
||||||
let version_jar =
|
let version_jar = profile
|
||||||
loader_version.as_ref().map_or(version.id.clone(), |it| {
|
.metadata
|
||||||
|
.loader_version
|
||||||
|
.as_ref()
|
||||||
|
.map_or(version.id.clone(), |it| {
|
||||||
format!("{}-{}", version.id.clone(), it.id.clone())
|
format!("{}-{}", version.id.clone(), it.id.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut version_info = download::download_version_info(
|
let mut version_info = download::download_version_info(
|
||||||
&state,
|
&state,
|
||||||
version,
|
version,
|
||||||
loader_version.as_ref(),
|
profile.metadata.loader_version.as_ref(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let loading_bar = init_or_edit_loading(
|
||||||
|
existing_loading_bar,
|
||||||
|
LoadingBarType::MinecraftDownload {
|
||||||
|
// If we are downloading minecraft for a profile, provide its name and uuid
|
||||||
|
profile_name: profile.metadata.name.clone(),
|
||||||
|
profile_uuid: profile.uuid,
|
||||||
|
},
|
||||||
|
100.0,
|
||||||
|
"Downloading Minecraft...",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
download::download_minecraft(&state, &version_info, loading_bar).await?;
|
||||||
|
st::State::sync().await?;
|
||||||
|
|
||||||
let client_path = state
|
let client_path = state
|
||||||
.directories
|
.directories
|
||||||
.version_dir(&version_jar)
|
.version_dir(&version_jar)
|
||||||
.join(format!("{version_jar}.jar"));
|
.join(format!("{version_jar}.jar"));
|
||||||
|
|
||||||
download::download_minecraft(&state, &version_info, profile).await?;
|
|
||||||
st::State::sync().await?;
|
|
||||||
|
|
||||||
if let Some(processors) = &version_info.processors {
|
if let Some(processors) = &version_info.processors {
|
||||||
if let Some(ref mut data) = version_info.data {
|
if let Some(ref mut data) = version_info.data {
|
||||||
processor_rules! {
|
processor_rules! {
|
||||||
@ -108,7 +116,7 @@ pub async fn launch_minecraft(
|
|||||||
client => client_path.to_string_lossy(),
|
client => client_path.to_string_lossy(),
|
||||||
server => "";
|
server => "";
|
||||||
"MINECRAFT_VERSION":
|
"MINECRAFT_VERSION":
|
||||||
client => game_version,
|
client => profile.metadata.game_version.clone(),
|
||||||
server => "";
|
server => "";
|
||||||
"ROOT":
|
"ROOT":
|
||||||
client => instance_path.to_string_lossy(),
|
client => instance_path.to_string_lossy(),
|
||||||
@ -118,7 +126,21 @@ pub async fn launch_minecraft(
|
|||||||
server => "";
|
server => "";
|
||||||
}
|
}
|
||||||
|
|
||||||
for processor in processors {
|
emit_loading(&loading_bar, 0.0, Some("Running forge processors"))
|
||||||
|
.await?;
|
||||||
|
let total_length = processors.len();
|
||||||
|
|
||||||
|
for (index, processor) in processors.iter().enumerate() {
|
||||||
|
emit_loading(
|
||||||
|
&loading_bar,
|
||||||
|
index as f64 / total_length as f64,
|
||||||
|
Some(&format!(
|
||||||
|
"Running forge processor {}/{}",
|
||||||
|
index, total_length
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if let Some(sides) = &processor.sides {
|
if let Some(sides) = &processor.sides {
|
||||||
if !sides.contains(&String::from("client")) {
|
if !sides.contains(&String::from("client")) {
|
||||||
continue;
|
continue;
|
||||||
@ -173,6 +195,68 @@ pub async fn launch_minecraft(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate::api::profile::edit(&profile.path, |prof| {
|
||||||
|
prof.installed = true;
|
||||||
|
|
||||||
|
async { Ok(()) }
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
crate::api::profile::sync(&profile.path).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub async fn launch_minecraft(
|
||||||
|
java_install: &Path,
|
||||||
|
java_args: &[String],
|
||||||
|
env_args: &[(String, String)],
|
||||||
|
wrapper: &Option<String>,
|
||||||
|
memory: &st::MemorySettings,
|
||||||
|
resolution: &st::WindowSize,
|
||||||
|
credentials: &auth::Credentials,
|
||||||
|
post_exit_hook: Option<Command>,
|
||||||
|
profile: &Profile,
|
||||||
|
) -> crate::Result<Arc<tokio::sync::RwLock<MinecraftChild>>> {
|
||||||
|
if !profile.installed {
|
||||||
|
install_minecraft(profile, None).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = st::State::get().await?;
|
||||||
|
let metadata = state.metadata.read().await;
|
||||||
|
let instance_path = &canonicalize(&profile.path)?;
|
||||||
|
|
||||||
|
let version = metadata
|
||||||
|
.minecraft
|
||||||
|
.versions
|
||||||
|
.iter()
|
||||||
|
.find(|it| it.id == profile.metadata.game_version)
|
||||||
|
.ok_or(crate::ErrorKind::LauncherError(format!(
|
||||||
|
"Invalid game version: {}",
|
||||||
|
profile.metadata.game_version
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
let version_jar = profile
|
||||||
|
.metadata
|
||||||
|
.loader_version
|
||||||
|
.as_ref()
|
||||||
|
.map_or(version.id.clone(), |it| {
|
||||||
|
format!("{}-{}", version.id.clone(), it.id.clone())
|
||||||
|
});
|
||||||
|
|
||||||
|
let version_info = download::download_version_info(
|
||||||
|
&state,
|
||||||
|
version,
|
||||||
|
profile.metadata.loader_version.as_ref(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let client_path = state
|
||||||
|
.directories
|
||||||
|
.version_dir(&version_jar)
|
||||||
|
.join(format!("{version_jar}.jar"));
|
||||||
|
|
||||||
let args = version_info.arguments.clone().unwrap_or_default();
|
let args = version_info.arguments.clone().unwrap_or_default();
|
||||||
let mut command = match wrapper {
|
let mut command = match wrapper {
|
||||||
Some(hook) => {
|
Some(hook) => {
|
||||||
|
|||||||
@ -19,5 +19,5 @@ mod state;
|
|||||||
|
|
||||||
pub use api::*;
|
pub use api::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use event::EventState;
|
pub use event::{EventState, LoadingBar, LoadingBarType};
|
||||||
pub use state::State;
|
pub use state::State;
|
||||||
|
|||||||
@ -134,6 +134,11 @@ impl DirectoryInfo {
|
|||||||
self.config_dir.join("caches")
|
self.config_dir.join("caches")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn caches_meta_dir(&self) -> PathBuf {
|
||||||
|
self.config_dir.join("caches").join("metadata")
|
||||||
|
}
|
||||||
|
|
||||||
/// Get path from environment variable
|
/// Get path from environment variable
|
||||||
#[inline]
|
#[inline]
|
||||||
fn env_path(name: &str) -> Option<PathBuf> {
|
fn env_path(name: &str) -> Option<PathBuf> {
|
||||||
|
|||||||
@ -1,21 +1,18 @@
|
|||||||
//! Theseus metadata
|
//! Theseus metadata
|
||||||
use crate::config::BINCODE_CONFIG;
|
use crate::data::DirectoryInfo;
|
||||||
use bincode::{Decode, Encode};
|
use crate::util::fetch::{read_json, write};
|
||||||
use daedalus::{
|
use daedalus::{
|
||||||
minecraft::{fetch_version_manifest, VersionManifest as MinecraftManifest},
|
minecraft::{fetch_version_manifest, VersionManifest as MinecraftManifest},
|
||||||
modded::{
|
modded::{
|
||||||
fetch_manifest as fetch_loader_manifest, Manifest as LoaderManifest,
|
fetch_manifest as fetch_loader_manifest, Manifest as LoaderManifest,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use futures::prelude::*;
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::LinkedList;
|
use tokio::sync::{RwLock, Semaphore};
|
||||||
|
|
||||||
const METADATA_URL: &str = "https://meta.modrinth.com";
|
const METADATA_URL: &str = "https://meta.modrinth.com";
|
||||||
const METADATA_DB_FIELD: &[u8] = b"metadata";
|
|
||||||
const RETRY_ATTEMPTS: i32 = 3;
|
|
||||||
|
|
||||||
// TODO: store as subtree in database
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Encode, Decode, Debug)]
|
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
pub minecraft: MinecraftManifest,
|
pub minecraft: MinecraftManifest,
|
||||||
pub forge: LoaderManifest,
|
pub forge: LoaderManifest,
|
||||||
@ -27,7 +24,7 @@ impl Metadata {
|
|||||||
format!("{METADATA_URL}/{name}/v0/manifest.json")
|
format!("{METADATA_URL}/{name}/v0/manifest.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch() -> crate::Result<Self> {
|
pub async fn fetch() -> crate::Result<Self> {
|
||||||
let (minecraft, forge, fabric) = tokio::try_join! {
|
let (minecraft, forge, fabric) = tokio::try_join! {
|
||||||
async {
|
async {
|
||||||
let url = Self::get_manifest("minecraft");
|
let url = Self::get_manifest("minecraft");
|
||||||
@ -51,41 +48,42 @@ impl Metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to fetch metadata and store in sled DB
|
// Attempt to fetch metadata and store in sled DB
|
||||||
#[tracing::instrument(skip_all)]
|
pub async fn init(
|
||||||
pub async fn init(db: &sled::Db) -> crate::Result<Self> {
|
dirs: &DirectoryInfo,
|
||||||
|
io_semaphore: &RwLock<Semaphore>,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
let mut metadata = None;
|
let mut metadata = None;
|
||||||
|
let metadata_path = dirs.caches_meta_dir().join("metadata.json");
|
||||||
|
|
||||||
if let Some(ref meta_bin) = db.get(METADATA_DB_FIELD)? {
|
if let Ok(metadata_json) =
|
||||||
match bincode::decode_from_slice::<Self, _>(
|
read_json::<Metadata>(&metadata_path, io_semaphore).await
|
||||||
meta_bin,
|
{
|
||||||
*BINCODE_CONFIG,
|
metadata = Some(metadata_json);
|
||||||
) {
|
} else {
|
||||||
Ok((meta, _)) => metadata = Some(meta),
|
let res = async {
|
||||||
|
let metadata_fetch = Self::fetch().await?;
|
||||||
|
|
||||||
|
write(
|
||||||
|
&metadata_path,
|
||||||
|
&serde_json::to_vec(&metadata_fetch).unwrap_or_default(),
|
||||||
|
io_semaphore,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
metadata = Some(metadata_fetch);
|
||||||
|
Ok::<(), crate::Error>(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Could not read launcher metadata: {err}")
|
log::warn!("Unable to fetch launcher metadata: {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut fetch_futures = LinkedList::new();
|
|
||||||
for _ in 0..RETRY_ATTEMPTS {
|
|
||||||
fetch_futures.push_back(Self::fetch().boxed());
|
|
||||||
}
|
|
||||||
|
|
||||||
match future::select_ok(fetch_futures).await {
|
|
||||||
Ok(meta) => metadata = Some(meta.0),
|
|
||||||
Err(err) => log::warn!("Unable to fetch launcher metadata: {err}"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(meta) = metadata {
|
if let Some(meta) = metadata {
|
||||||
db.insert(
|
|
||||||
METADATA_DB_FIELD,
|
|
||||||
sled::IVec::from(bincode::encode_to_vec(
|
|
||||||
&meta,
|
|
||||||
*BINCODE_CONFIG,
|
|
||||||
)?),
|
|
||||||
)?;
|
|
||||||
db.flush_async().await?;
|
|
||||||
Ok(meta)
|
Ok(meta)
|
||||||
} else {
|
} else {
|
||||||
Err(
|
Err(
|
||||||
@ -94,4 +92,35 @@ impl Metadata {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update() {
|
||||||
|
let res = async {
|
||||||
|
let metadata_fetch = Metadata::fetch().await?;
|
||||||
|
let state = crate::State::get().await?;
|
||||||
|
|
||||||
|
let metadata_path =
|
||||||
|
state.directories.caches_meta_dir().join("metadata.json");
|
||||||
|
|
||||||
|
write(
|
||||||
|
&metadata_path,
|
||||||
|
&serde_json::to_vec(&metadata_fetch)?,
|
||||||
|
&state.io_semaphore,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut old_metadata = state.metadata.write().await;
|
||||||
|
*old_metadata = metadata_fetch;
|
||||||
|
|
||||||
|
Ok::<(), crate::Error>(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("Unable to update launcher metadata: {err}")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
//! Theseus state management system
|
//! Theseus state management system
|
||||||
use crate::config::sled_config;
|
|
||||||
use crate::event::emit::emit_loading;
|
use crate::event::emit::emit_loading;
|
||||||
|
|
||||||
use crate::event::emit::init_loading;
|
use crate::event::emit::init_loading;
|
||||||
use crate::event::LoadingBarType;
|
use crate::event::LoadingBarType;
|
||||||
use crate::jre;
|
|
||||||
use crate::loading_join;
|
use crate::loading_join;
|
||||||
|
|
||||||
|
use crate::state::users::Users;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{OnceCell, RwLock, Semaphore};
|
use tokio::sync::{OnceCell, RwLock, Semaphore};
|
||||||
|
|
||||||
@ -27,7 +26,6 @@ mod projects;
|
|||||||
pub use self::projects::*;
|
pub use self::projects::*;
|
||||||
|
|
||||||
mod users;
|
mod users;
|
||||||
pub use self::users::*;
|
|
||||||
|
|
||||||
mod children;
|
mod children;
|
||||||
pub use self::children::*;
|
pub use self::children::*;
|
||||||
@ -51,8 +49,7 @@ pub struct State {
|
|||||||
/// Stored maximum number of sempahores of current io_semaphore
|
/// Stored maximum number of sempahores of current io_semaphore
|
||||||
pub io_semaphore_max: RwLock<u32>,
|
pub io_semaphore_max: RwLock<u32>,
|
||||||
/// Launcher metadata
|
/// Launcher metadata
|
||||||
pub metadata: Metadata,
|
pub metadata: RwLock<Metadata>,
|
||||||
// TODO: settings API
|
|
||||||
/// Launcher configuration
|
/// Launcher configuration
|
||||||
pub settings: RwLock<Settings>,
|
pub settings: RwLock<Settings>,
|
||||||
/// Reference to minecraft process children
|
/// Reference to minecraft process children
|
||||||
@ -68,76 +65,55 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
#[tracing::instrument]
|
|
||||||
/// Get the current launcher state, initializing it if needed
|
/// Get the current launcher state, initializing it if needed
|
||||||
pub async fn get() -> crate::Result<Arc<Self>> {
|
pub async fn get() -> crate::Result<Arc<Self>> {
|
||||||
LAUNCHER_STATE
|
LAUNCHER_STATE
|
||||||
.get_or_try_init(|| {
|
.get_or_try_init(|| {
|
||||||
async {
|
async {
|
||||||
|
let loading_bar = init_loading(
|
||||||
|
LoadingBarType::StateInit,
|
||||||
|
100.0,
|
||||||
|
"Initializing launcher...",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let loading_bar = init_loading(LoadingBarType::StateInit, 100.0, "Initializing launcher...").await?;
|
|
||||||
// Directories
|
|
||||||
let directories = DirectoryInfo::init().await?;
|
let directories = DirectoryInfo::init().await?;
|
||||||
|
|
||||||
// Database
|
|
||||||
// TODO: make database versioned
|
|
||||||
let database = sled_config()
|
|
||||||
.path(directories.database_file())
|
|
||||||
.open()?;
|
|
||||||
|
|
||||||
emit_loading(&loading_bar, 10.0, None).await?;
|
emit_loading(&loading_bar, 10.0, None).await?;
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
let mut settings =
|
let settings =
|
||||||
Settings::init(&directories.settings_file()).await?;
|
Settings::init(&directories.settings_file()).await?;
|
||||||
|
let io_semaphore = RwLock::new(Semaphore::new(
|
||||||
|
settings.max_concurrent_downloads,
|
||||||
|
));
|
||||||
|
emit_loading(&loading_bar, 10.0, None).await?;
|
||||||
|
|
||||||
// Loose initializations
|
let metadata_fut =
|
||||||
let io_semaphore_max = settings.max_concurrent_downloads;
|
Metadata::init(&directories, &io_semaphore);
|
||||||
|
|
||||||
let io_semaphore =
|
|
||||||
RwLock::new(Semaphore::new(io_semaphore_max));
|
|
||||||
|
|
||||||
let metadata_fut = Metadata::init(&database);
|
|
||||||
let profiles_fut =
|
let profiles_fut =
|
||||||
Profiles::init(&directories, &io_semaphore);
|
Profiles::init(&directories, &io_semaphore);
|
||||||
|
let tags_fut = Tags::init(&directories, &io_semaphore);
|
||||||
|
let users_fut = Users::init(&directories, &io_semaphore);
|
||||||
// Launcher data
|
// Launcher data
|
||||||
let (metadata, profiles) = loading_join! {
|
let (metadata, profiles, tags, users) = loading_join! {
|
||||||
Some(&loading_bar), 20.0, Some("Initializing metadata and profiles...");
|
Some(&loading_bar), 70.0, Some("Initializing...");
|
||||||
metadata_fut, profiles_fut
|
metadata_fut,
|
||||||
|
profiles_fut,
|
||||||
|
tags_fut,
|
||||||
|
users_fut,
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
emit_loading(&loading_bar, 10.0, None).await?;
|
|
||||||
let users = Users::init(&database)?;
|
|
||||||
|
|
||||||
let children = Children::new();
|
let children = Children::new();
|
||||||
|
|
||||||
let auth_flow = AuthTask::new();
|
let auth_flow = AuthTask::new();
|
||||||
|
|
||||||
// On launcher initialization, attempt a tag fetch after tags init
|
|
||||||
let mut tags = Tags::init(&database)?;
|
|
||||||
if let Err(tag_fetch_err) =
|
|
||||||
tags.fetch_update(&io_semaphore,Some(&loading_bar)).await
|
|
||||||
{
|
|
||||||
tracing::error!(
|
|
||||||
"Failed to fetch tags on launcher init: {}",
|
|
||||||
tag_fetch_err
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
emit_loading(&loading_bar, 10.0, None).await?;
|
emit_loading(&loading_bar, 10.0, None).await?;
|
||||||
|
|
||||||
// On launcher initialization, if global java variables are unset, try to find and set them
|
|
||||||
// (they are required for the game to launch)
|
|
||||||
if settings.java_globals.count() == 0 {
|
|
||||||
settings.java_globals = jre::autodetect_java_globals().await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
directories,
|
directories,
|
||||||
io_semaphore,
|
io_semaphore,
|
||||||
io_semaphore_max: RwLock::new(io_semaphore_max as u32),
|
io_semaphore_max: RwLock::new(
|
||||||
metadata,
|
settings.max_concurrent_downloads as u32,
|
||||||
|
),
|
||||||
|
metadata: RwLock::new(metadata),
|
||||||
settings: RwLock::new(settings),
|
settings: RwLock::new(settings),
|
||||||
profiles: RwLock::new(profiles),
|
profiles: RwLock::new(profiles),
|
||||||
users: RwLock::new(users),
|
users: RwLock::new(users),
|
||||||
@ -151,6 +127,14 @@ impl State {
|
|||||||
.map(Arc::clone)
|
.map(Arc::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates state with data from the web
|
||||||
|
pub fn update() {
|
||||||
|
tokio::task::spawn(Metadata::update());
|
||||||
|
tokio::task::spawn(Tags::update());
|
||||||
|
tokio::task::spawn(Profiles::update_projects());
|
||||||
|
tokio::task::spawn(Settings::update_java());
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
/// Synchronize in-memory state with persistent state
|
/// Synchronize in-memory state with persistent state
|
||||||
pub async fn sync() -> crate::Result<()> {
|
pub async fn sync() -> crate::Result<()> {
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
use super::settings::{Hooks, MemorySettings, WindowSize};
|
use super::settings::{Hooks, MemorySettings, WindowSize};
|
||||||
use crate::config::MODRINTH_API_URL;
|
use crate::config::MODRINTH_API_URL;
|
||||||
use crate::data::DirectoryInfo;
|
use crate::data::DirectoryInfo;
|
||||||
use crate::event::emit::{
|
use crate::event::emit::emit_profile;
|
||||||
emit_profile, init_loading, loading_try_for_each_concurrent,
|
use crate::event::ProfilePayloadType;
|
||||||
};
|
|
||||||
use crate::event::{LoadingBarType, ProfilePayloadType};
|
|
||||||
use crate::state::projects::Project;
|
use crate::state::projects::Project;
|
||||||
use crate::state::{ModrinthVersion, ProjectType};
|
use crate::state::{ModrinthVersion, ProjectType};
|
||||||
use crate::util::fetch::{fetch, fetch_json, write, write_cached_icon};
|
use crate::util::fetch::{fetch, fetch_json, write, write_cached_icon};
|
||||||
@ -34,6 +32,8 @@ pub const CURRENT_FORMAT_VERSION: u32 = 1;
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Profile {
|
pub struct Profile {
|
||||||
pub uuid: Uuid, // todo: will be used in restructure to refer to profiles
|
pub uuid: Uuid, // todo: will be used in restructure to refer to profiles
|
||||||
|
#[serde(default)]
|
||||||
|
pub installed: bool,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub metadata: ProfileMetadata,
|
pub metadata: ProfileMetadata,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -58,10 +58,15 @@ pub struct ProfileMetadata {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub loader_version: Option<LoaderVersion>,
|
pub loader_version: Option<LoaderVersion>,
|
||||||
pub format_version: u32,
|
pub format_version: u32,
|
||||||
pub linked_project_id: Option<String>,
|
pub linked_data: Option<LinkedData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct LinkedData {
|
||||||
|
pub project_id: Option<String>,
|
||||||
|
pub version_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Quilt?
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize, Default,
|
Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize, Default,
|
||||||
)]
|
)]
|
||||||
@ -85,6 +90,17 @@ impl std::fmt::Display for ModLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModLoader {
|
||||||
|
pub(crate) fn as_api_str(&self) -> &'static str {
|
||||||
|
match *self {
|
||||||
|
Self::Vanilla => "vanilla",
|
||||||
|
Self::Forge => "forge",
|
||||||
|
Self::Fabric => "fabric",
|
||||||
|
Self::Quilt => "quilt",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct JavaSettings {
|
pub struct JavaSettings {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -110,6 +126,7 @@ impl Profile {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
uuid,
|
uuid,
|
||||||
|
installed: false,
|
||||||
path: canonicalize(path)?,
|
path: canonicalize(path)?,
|
||||||
metadata: ProfileMetadata {
|
metadata: ProfileMetadata {
|
||||||
name,
|
name,
|
||||||
@ -118,7 +135,7 @@ impl Profile {
|
|||||||
loader: ModLoader::Vanilla,
|
loader: ModLoader::Vanilla,
|
||||||
loader_version: None,
|
loader_version: None,
|
||||||
format_version: CURRENT_FORMAT_VERSION,
|
format_version: CURRENT_FORMAT_VERSION,
|
||||||
linked_project_id: None,
|
linked_data: None,
|
||||||
},
|
},
|
||||||
projects: HashMap::new(),
|
projects: HashMap::new(),
|
||||||
java: None,
|
java: None,
|
||||||
@ -147,7 +164,7 @@ impl Profile {
|
|||||||
|
|
||||||
let paths = self.get_profile_project_paths()?;
|
let paths = self.get_profile_project_paths()?;
|
||||||
let projects = crate::state::infer_data_from_files(
|
let projects = crate::state::infer_data_from_files(
|
||||||
paths,
|
&[(self.clone(), paths)],
|
||||||
state.directories.caches_dir(),
|
state.directories.caches_dir(),
|
||||||
&state.io_semaphore,
|
&state.io_semaphore,
|
||||||
)
|
)
|
||||||
@ -155,6 +172,14 @@ impl Profile {
|
|||||||
|
|
||||||
self.projects = projects;
|
self.projects = projects;
|
||||||
|
|
||||||
|
emit_profile(
|
||||||
|
self.uuid,
|
||||||
|
self.path.clone(),
|
||||||
|
&self.metadata.name,
|
||||||
|
ProfilePayloadType::Synced,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,8 +291,6 @@ impl Profile {
|
|||||||
let path = self.path.join(project_type.get_folder()).join(file_name);
|
let path = self.path.join(project_type.get_folder()).join(file_name);
|
||||||
write(&path, &bytes, &state.io_semaphore).await?;
|
write(&path, &bytes, &state.io_semaphore).await?;
|
||||||
|
|
||||||
self.sync().await?;
|
|
||||||
|
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,34 +368,60 @@ impl Profiles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// project path, parent profile path
|
Ok(Self(profiles))
|
||||||
let mut files: HashMap<PathBuf, PathBuf> = HashMap::new();
|
}
|
||||||
|
|
||||||
|
pub async fn update_projects() {
|
||||||
|
let res = async {
|
||||||
|
let state = State::get().await?;
|
||||||
|
|
||||||
|
// profile, child paths
|
||||||
|
let mut files: Vec<(Profile, Vec<PathBuf>)> = Vec::new();
|
||||||
{
|
{
|
||||||
for (profile_path, profile) in profiles.iter() {
|
let profiles = state.profiles.read().await;
|
||||||
|
for (_profile_path, profile) in profiles.0.iter() {
|
||||||
let paths = profile.get_profile_project_paths()?;
|
let paths = profile.get_profile_project_paths()?;
|
||||||
|
|
||||||
for path in paths {
|
files.push((profile.clone(), paths));
|
||||||
files.insert(path, profile_path.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !files.is_empty() {
|
||||||
let inferred = super::projects::infer_data_from_files(
|
let inferred = super::projects::infer_data_from_files(
|
||||||
files.keys().cloned().collect(),
|
&files,
|
||||||
dirs.caches_dir(),
|
state.directories.caches_dir(),
|
||||||
io_sempahore,
|
&state.io_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
let mut wipe_profiles = Vec::new();
|
||||||
for (key, value) in inferred {
|
for (key, value) in inferred {
|
||||||
if let Some(profile_path) = files.get(&key) {
|
if let Some((profile, _)) =
|
||||||
if let Some(profile) = profiles.get_mut(profile_path) {
|
files.iter().find(|(_, files)| files.contains(&key))
|
||||||
|
{
|
||||||
|
let mut new_profiles = state.profiles.write().await;
|
||||||
|
if let Some(profile) =
|
||||||
|
new_profiles.0.get_mut(&profile.path)
|
||||||
|
{
|
||||||
|
if !wipe_profiles.contains(&profile.path) {
|
||||||
|
profile.projects = HashMap::new();
|
||||||
|
wipe_profiles.push(profile.path.clone());
|
||||||
|
}
|
||||||
profile.projects.insert(key, value);
|
profile.projects.insert(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self(profiles))
|
Ok::<(), crate::Error>(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("Unable to fetch profile projects: {err}")
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
@ -406,35 +455,26 @@ impl Profiles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn remove(&mut self, path: &Path) -> crate::Result<&Self> {
|
pub async fn remove(
|
||||||
|
&mut self,
|
||||||
|
path: &Path,
|
||||||
|
) -> crate::Result<Option<Profile>> {
|
||||||
let path =
|
let path =
|
||||||
PathBuf::from(&canonicalize(path)?.to_string_lossy().to_string());
|
PathBuf::from(&canonicalize(path)?.to_string_lossy().to_string());
|
||||||
self.0.remove(&path);
|
let profile = self.0.remove(&path);
|
||||||
|
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
fs::remove_dir_all(path).await?;
|
fs::remove_dir_all(path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self)
|
Ok(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn sync(&self) -> crate::Result<&Self> {
|
pub async fn sync(&self) -> crate::Result<&Self> {
|
||||||
let loading_bar = init_loading(
|
stream::iter(self.0.iter())
|
||||||
LoadingBarType::ProfileSync,
|
.map(Ok::<_, crate::Error>)
|
||||||
100.0,
|
.try_for_each_concurrent(None, |(path, profile)| async move {
|
||||||
"Syncing profiles...",
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let num_futs = self.0.len();
|
|
||||||
loading_try_for_each_concurrent(
|
|
||||||
stream::iter(self.0.iter()).map(Ok::<_, crate::Error>),
|
|
||||||
None,
|
|
||||||
Some(&loading_bar),
|
|
||||||
100.0,
|
|
||||||
num_futs,
|
|
||||||
None,
|
|
||||||
|(path, profile)| async move {
|
|
||||||
let json = serde_json::to_vec(&profile)?;
|
let json = serde_json::to_vec(&profile)?;
|
||||||
|
|
||||||
let json_path = Path::new(&path.to_string_lossy().to_string())
|
let json_path = Path::new(&path.to_string_lossy().to_string())
|
||||||
@ -442,8 +482,7 @@ impl Profiles {
|
|||||||
|
|
||||||
fs::write(json_path, json).await?;
|
fs::write(json_path, json).await?;
|
||||||
Ok::<_, crate::Error>(())
|
Ok::<_, crate::Error>(())
|
||||||
},
|
})
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
//! Project management + inference
|
//! Project management + inference
|
||||||
|
|
||||||
use crate::config::MODRINTH_API_URL;
|
use crate::config::MODRINTH_API_URL;
|
||||||
|
use crate::data::ModLoader;
|
||||||
|
use crate::state::Profile;
|
||||||
use crate::util::fetch::{fetch_json, write_cached_icon};
|
use crate::util::fetch::{fetch_json, write_cached_icon};
|
||||||
use async_zip::tokio::read::fs::ZipFileReader;
|
use async_zip::tokio::read::fs::ZipFileReader;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
@ -185,6 +187,8 @@ pub enum ProjectMetadata {
|
|||||||
project: Box<ModrinthProject>,
|
project: Box<ModrinthProject>,
|
||||||
version: Box<ModrinthVersion>,
|
version: Box<ModrinthVersion>,
|
||||||
members: Vec<ModrinthTeamMember>,
|
members: Vec<ModrinthTeamMember>,
|
||||||
|
update_version: Option<Box<ModrinthVersion>>,
|
||||||
|
incompatible: bool,
|
||||||
},
|
},
|
||||||
Inferred {
|
Inferred {
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
@ -246,14 +250,15 @@ async fn read_icon_from_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn infer_data_from_files(
|
pub async fn infer_data_from_files(
|
||||||
paths: Vec<PathBuf>,
|
paths: &[(Profile, Vec<PathBuf>)],
|
||||||
cache_dir: PathBuf,
|
cache_dir: PathBuf,
|
||||||
io_semaphore: &RwLock<Semaphore>,
|
io_semaphore: &RwLock<Semaphore>,
|
||||||
) -> crate::Result<HashMap<PathBuf, Project>> {
|
) -> crate::Result<HashMap<PathBuf, Project>> {
|
||||||
let mut file_path_hashes = HashMap::new();
|
let mut file_path_hashes = HashMap::new();
|
||||||
|
|
||||||
// TODO: Make this concurrent and use progressive hashing to avoid loading each JAR in memory
|
// TODO: Make this concurrent and use progressive hashing to avoid loading each JAR in memory
|
||||||
for path in paths.clone() {
|
for set in paths {
|
||||||
|
for path in &set.1 {
|
||||||
let mut file = tokio::fs::File::open(path.clone()).await?;
|
let mut file = tokio::fs::File::open(path.clone()).await?;
|
||||||
|
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
@ -262,6 +267,7 @@ pub async fn infer_data_from_files(
|
|||||||
let hash = format!("{:x}", sha2::Sha512::digest(&buffer));
|
let hash = format!("{:x}", sha2::Sha512::digest(&buffer));
|
||||||
file_path_hashes.insert(hash, path.clone());
|
file_path_hashes.insert(hash, path.clone());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let files: HashMap<String, ModrinthVersion> = fetch_json(
|
let files: HashMap<String, ModrinthVersion> = fetch_json(
|
||||||
Method::POST,
|
Method::POST,
|
||||||
@ -291,7 +297,6 @@ pub async fn infer_data_from_files(
|
|||||||
io_semaphore,
|
io_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let teams: Vec<ModrinthTeamMember> = fetch_json::<
|
let teams: Vec<ModrinthTeamMember> = fetch_json::<
|
||||||
Vec<Vec<ModrinthTeamMember>>,
|
Vec<Vec<ModrinthTeamMember>>,
|
||||||
>(
|
>(
|
||||||
@ -312,6 +317,26 @@ pub async fn infer_data_from_files(
|
|||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let mut update_versions: Vec<ModrinthVersion> = fetch_json(
|
||||||
|
Method::GET,
|
||||||
|
&format!(
|
||||||
|
"{}versions?ids={}",
|
||||||
|
MODRINTH_API_URL,
|
||||||
|
serde_json::to_string(
|
||||||
|
&projects
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.versions.clone())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
)?
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
io_semaphore,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
update_versions.sort_by(|a, b| b.date_published.cmp(&a.date_published));
|
||||||
|
|
||||||
let mut return_projects = HashMap::new();
|
let mut return_projects = HashMap::new();
|
||||||
let mut further_analyze_projects: Vec<(String, PathBuf)> = Vec::new();
|
let mut further_analyze_projects: Vec<(String, PathBuf)> = Vec::new();
|
||||||
|
|
||||||
@ -320,18 +345,14 @@ pub async fn infer_data_from_files(
|
|||||||
if let Some(project) =
|
if let Some(project) =
|
||||||
projects.iter().find(|x| version.project_id == x.id)
|
projects.iter().find(|x| version.project_id == x.id)
|
||||||
{
|
{
|
||||||
|
let profile = paths.iter().find(|x| x.1.contains(&path));
|
||||||
|
|
||||||
let file_name = path
|
let file_name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let team_members = teams
|
|
||||||
.iter()
|
|
||||||
.filter(|x| x.team_id == project.team)
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
return_projects.insert(
|
return_projects.insert(
|
||||||
path,
|
path,
|
||||||
Project {
|
Project {
|
||||||
@ -340,7 +361,52 @@ pub async fn infer_data_from_files(
|
|||||||
metadata: ProjectMetadata::Modrinth {
|
metadata: ProjectMetadata::Modrinth {
|
||||||
project: Box::new(project.clone()),
|
project: Box::new(project.clone()),
|
||||||
version: Box::new(version.clone()),
|
version: Box::new(version.clone()),
|
||||||
members: team_members,
|
members: teams
|
||||||
|
.iter()
|
||||||
|
.filter(|x| x.team_id == project.team)
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
update_version: if let Some((profile, _)) = &profile
|
||||||
|
{
|
||||||
|
update_versions
|
||||||
|
.iter()
|
||||||
|
.find(|x| {
|
||||||
|
x.project_id == project.id
|
||||||
|
&& x.game_versions.contains(
|
||||||
|
&profile.metadata.game_version,
|
||||||
|
)
|
||||||
|
&& if profile.metadata.loader
|
||||||
|
== ModLoader::Vanilla
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
x.loaders.contains(
|
||||||
|
&profile
|
||||||
|
.metadata
|
||||||
|
.loader
|
||||||
|
.as_api_str()
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.map(Box::new)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
incompatible: if let Some((profile, _)) = &profile {
|
||||||
|
!version.loaders.contains(
|
||||||
|
&profile
|
||||||
|
.metadata
|
||||||
|
.loader
|
||||||
|
.as_api_str()
|
||||||
|
.to_string(),
|
||||||
|
) || version
|
||||||
|
.game_versions
|
||||||
|
.contains(&profile.metadata.game_version)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
file_name,
|
file_name,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
//! Theseus settings file
|
//! Theseus settings file
|
||||||
|
use crate::{jre, State};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
@ -63,6 +64,29 @@ impl Settings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update_java() {
|
||||||
|
let res = async {
|
||||||
|
let state = State::get().await?;
|
||||||
|
let settings_read = state.settings.write().await;
|
||||||
|
|
||||||
|
if settings_read.java_globals.count() == 0 {
|
||||||
|
drop(settings_read);
|
||||||
|
let java_globals = jre::autodetect_java_globals().await?;
|
||||||
|
state.settings.write().await.java_globals = java_globals;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok::<(), crate::Error>(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("Unable to update launcher java: {err}")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn sync(&self, to: &Path) -> crate::Result<()> {
|
pub async fn sync(&self, to: &Path) -> crate::Result<()> {
|
||||||
fs::write(to, serde_json::to_vec(self)?)
|
fs::write(to, serde_json::to_vec(self)?)
|
||||||
|
|||||||
@ -1,152 +1,125 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use bincode::{Decode, Encode};
|
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{RwLock, Semaphore};
|
use tokio::sync::{RwLock, Semaphore};
|
||||||
|
|
||||||
use crate::config::{BINCODE_CONFIG, MODRINTH_API_URL};
|
use crate::config::MODRINTH_API_URL;
|
||||||
use crate::event::LoadingBarId;
|
use crate::data::DirectoryInfo;
|
||||||
use crate::loading_join;
|
use crate::util::fetch::{fetch_json, read_json, write};
|
||||||
use crate::util::fetch::fetch_json;
|
|
||||||
|
|
||||||
const CATEGORIES_DB_TREE: &[u8] = b"categories";
|
// Serializeable struct for all tags to be fetched together by the frontend
|
||||||
const LOADERS_DB_TREE: &[u8] = b"loaders";
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
const GAME_VERSIONS_DB_TREE: &[u8] = b"game_versions";
|
pub struct Tags {
|
||||||
const LICENSES_DB_TREE: &[u8] = b"licenses";
|
pub categories: Vec<Category>,
|
||||||
const DONATION_PLATFORMS_DB_TREE: &[u8] = b"donation_platforms";
|
pub loaders: Vec<Loader>,
|
||||||
const REPORT_TYPES_DB_TREE: &[u8] = b"report_types";
|
pub game_versions: Vec<GameVersion>,
|
||||||
|
pub donation_platforms: Vec<DonationPlatform>,
|
||||||
#[derive(Clone)]
|
pub report_types: Vec<String>,
|
||||||
pub(crate) struct Tags(pub(crate) TagsInner);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct TagsInner {
|
|
||||||
pub categories: sled::Tree,
|
|
||||||
pub loaders: sled::Tree,
|
|
||||||
pub game_versions: sled::Tree,
|
|
||||||
pub licenses: sled::Tree,
|
|
||||||
pub donation_platforms: sled::Tree,
|
|
||||||
pub report_types: sled::Tree,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tags {
|
impl Tags {
|
||||||
#[tracing::instrument(skip(db))]
|
pub async fn init(
|
||||||
pub fn init(db: &sled::Db) -> crate::Result<Self> {
|
dirs: &DirectoryInfo,
|
||||||
Ok(Tags(TagsInner {
|
io_semaphore: &RwLock<Semaphore>,
|
||||||
categories: db.open_tree(CATEGORIES_DB_TREE)?,
|
) -> crate::Result<Self> {
|
||||||
loaders: db.open_tree(LOADERS_DB_TREE)?,
|
let mut tags = None;
|
||||||
game_versions: db.open_tree(GAME_VERSIONS_DB_TREE)?,
|
let tags_path = dirs.caches_meta_dir().join("tags.json");
|
||||||
licenses: db.open_tree(LICENSES_DB_TREE)?,
|
|
||||||
donation_platforms: db.open_tree(DONATION_PLATFORMS_DB_TREE)?,
|
if let Ok(tags_json) = read_json::<Self>(&tags_path, io_semaphore).await
|
||||||
report_types: db.open_tree(REPORT_TYPES_DB_TREE)?,
|
{
|
||||||
}))
|
tags = Some(tags_json);
|
||||||
|
} else {
|
||||||
|
match Self::fetch(io_semaphore).await {
|
||||||
|
Ok(tags_fetch) => tags = Some(tags_fetch),
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("Unable to fetch launcher tags: {err}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tags_data) = tags {
|
||||||
|
write(&tags_path, &serde_json::to_vec(&tags_data)?, io_semaphore)
|
||||||
|
.await?;
|
||||||
|
Ok(tags_data)
|
||||||
|
} else {
|
||||||
|
Err(crate::ErrorKind::NoValueFor(String::from("launcher tags"))
|
||||||
|
.as_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update() {
|
||||||
|
let res = async {
|
||||||
|
let state = crate::State::get().await?;
|
||||||
|
let tags_fetch = Tags::fetch(&state.io_semaphore).await?;
|
||||||
|
|
||||||
|
let tags_path =
|
||||||
|
state.directories.caches_meta_dir().join("tags.json");
|
||||||
|
|
||||||
|
write(
|
||||||
|
&tags_path,
|
||||||
|
&serde_json::to_vec(&tags_fetch)?,
|
||||||
|
&state.io_semaphore,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut old_tags = state.tags.write().await;
|
||||||
|
*old_tags = tags_fetch;
|
||||||
|
|
||||||
|
Ok::<(), crate::Error>(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("Unable to update launcher tags: {err}")
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks the database for categories tag, returns a Vec::new() if it doesnt exist, otherwise returns the categories
|
// Checks the database for categories tag, returns a Vec::new() if it doesnt exist, otherwise returns the categories
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn get_categories(&self) -> crate::Result<Vec<Category>> {
|
pub fn get_categories(&self) -> Vec<Category> {
|
||||||
self.0.categories.get("categories")?.map_or(
|
self.categories.clone()
|
||||||
Ok(Vec::new()),
|
|
||||||
|categories| {
|
|
||||||
bincode::decode_from_slice(&categories, *BINCODE_CONFIG)
|
|
||||||
.map_err(crate::Error::from)
|
|
||||||
.map(|it| it.0)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks the database for loaders tag, returns a Vec::new() if it doesnt exist, otherwise returns the loaders
|
// Checks the database for loaders tag, returns a Vec::new() if it doesnt exist, otherwise returns the loaders
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn get_loaders(&self) -> crate::Result<Vec<Loader>> {
|
pub fn get_loaders(&self) -> Vec<Loader> {
|
||||||
self.0
|
self.loaders.clone()
|
||||||
.loaders
|
|
||||||
.get("loaders")?
|
|
||||||
.map_or(Ok(Vec::new()), |loaders| {
|
|
||||||
bincode::decode_from_slice(&loaders, *BINCODE_CONFIG)
|
|
||||||
.map_err(crate::Error::from)
|
|
||||||
.map(|it| it.0)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks the database for game_versions tag, returns a Vec::new() if it doesnt exist, otherwise returns the game_versions
|
// Checks the database for game_versions tag, returns a Vec::new() if it doesnt exist, otherwise returns the game_versions
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn get_game_versions(&self) -> crate::Result<Vec<GameVersion>> {
|
pub fn get_game_versions(&self) -> Vec<GameVersion> {
|
||||||
self.0.game_versions.get("game_versions")?.map_or(
|
self.game_versions.clone()
|
||||||
Ok(Vec::new()),
|
|
||||||
|game_versions| {
|
|
||||||
bincode::decode_from_slice(&game_versions, *BINCODE_CONFIG)
|
|
||||||
.map_err(crate::Error::from)
|
|
||||||
.map(|it| it.0)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks the database for licenses tag, returns a Vec::new() if it doesnt exist, otherwise returns the licenses
|
|
||||||
#[tracing::instrument(skip(self))]
|
|
||||||
pub fn get_licenses(&self) -> crate::Result<Vec<License>> {
|
|
||||||
self.0
|
|
||||||
.licenses
|
|
||||||
.get("licenses")?
|
|
||||||
.map_or(Ok(Vec::new()), |licenses| {
|
|
||||||
bincode::decode_from_slice(&licenses, *BINCODE_CONFIG)
|
|
||||||
.map_err(crate::Error::from)
|
|
||||||
.map(|it| it.0)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks the database for donation_platforms tag, returns a Vec::new() if it doesnt exist, otherwise returns the donation_platforms
|
// Checks the database for donation_platforms tag, returns a Vec::new() if it doesnt exist, otherwise returns the donation_platforms
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn get_donation_platforms(
|
pub fn get_donation_platforms(&self) -> Vec<DonationPlatform> {
|
||||||
&self,
|
self.donation_platforms.clone()
|
||||||
) -> crate::Result<Vec<DonationPlatform>> {
|
|
||||||
self.0.donation_platforms.get("donation_platforms")?.map_or(
|
|
||||||
Ok(Vec::new()),
|
|
||||||
|donation_platforms| {
|
|
||||||
bincode::decode_from_slice(&donation_platforms, *BINCODE_CONFIG)
|
|
||||||
.map_err(crate::Error::from)
|
|
||||||
.map(|it| it.0)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks the database for report_types tag, returns a Vec::new() if it doesnt exist, otherwise returns the report_types
|
// Checks the database for report_types tag, returns a Vec::new() if it doesnt exist, otherwise returns the report_types
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn get_report_types(&self) -> crate::Result<Vec<String>> {
|
pub fn get_report_types(&self) -> Vec<String> {
|
||||||
self.0.report_types.get("report_types")?.map_or(
|
self.report_types.clone()
|
||||||
Ok(Vec::new()),
|
|
||||||
|report_types| {
|
|
||||||
bincode::decode_from_slice(&report_types, *BINCODE_CONFIG)
|
|
||||||
.map_err(crate::Error::from)
|
|
||||||
.map(|it| it.0)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets all tags together as a serializable bundle
|
// Gets all tags together as a serializable bundle
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn get_tag_bundle(&self) -> crate::Result<TagBundle> {
|
pub fn get_tag_bundle(&self) -> Tags {
|
||||||
Ok(TagBundle {
|
self.clone()
|
||||||
categories: self.get_categories()?,
|
|
||||||
loaders: self.get_loaders()?,
|
|
||||||
game_versions: self.get_game_versions()?,
|
|
||||||
licenses: self.get_licenses()?,
|
|
||||||
donation_platforms: self.get_donation_platforms()?,
|
|
||||||
report_types: self.get_report_types()?,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetches the tags from the Modrinth API and stores them in the database
|
// Fetches the tags from the Modrinth API and stores them in the database
|
||||||
#[tracing::instrument(skip(self))]
|
pub async fn fetch(semaphore: &RwLock<Semaphore>) -> crate::Result<Self> {
|
||||||
pub async fn fetch_update(
|
|
||||||
&mut self,
|
|
||||||
semaphore: &RwLock<Semaphore>,
|
|
||||||
loading_bar: Option<&LoadingBarId>,
|
|
||||||
) -> crate::Result<()> {
|
|
||||||
let categories = format!("{MODRINTH_API_URL}tag/category");
|
let categories = format!("{MODRINTH_API_URL}tag/category");
|
||||||
let loaders = format!("{MODRINTH_API_URL}tag/loader");
|
let loaders = format!("{MODRINTH_API_URL}tag/loader");
|
||||||
let game_versions = format!("{MODRINTH_API_URL}tag/game_version");
|
let game_versions = format!("{MODRINTH_API_URL}tag/game_version");
|
||||||
let licenses = format!("{MODRINTH_API_URL}tag/license");
|
|
||||||
let donation_platforms =
|
let donation_platforms =
|
||||||
format!("{MODRINTH_API_URL}tag/donation_platform");
|
format!("{MODRINTH_API_URL}tag/donation_platform");
|
||||||
let report_types = format!("{MODRINTH_API_URL}tag/report_type");
|
let report_types = format!("{MODRINTH_API_URL}tag/report_type");
|
||||||
@ -172,13 +145,6 @@ impl Tags {
|
|||||||
None,
|
None,
|
||||||
semaphore,
|
semaphore,
|
||||||
);
|
);
|
||||||
let licenses_fut = fetch_json::<Vec<License>>(
|
|
||||||
Method::GET,
|
|
||||||
&licenses,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
semaphore,
|
|
||||||
);
|
|
||||||
let donation_platforms_fut = fetch_json::<Vec<DonationPlatform>>(
|
let donation_platforms_fut = fetch_json::<Vec<DonationPlatform>>(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
&donation_platforms,
|
&donation_platforms,
|
||||||
@ -198,60 +164,27 @@ impl Tags {
|
|||||||
categories,
|
categories,
|
||||||
loaders,
|
loaders,
|
||||||
game_versions,
|
game_versions,
|
||||||
licenses,
|
|
||||||
donation_platforms,
|
donation_platforms,
|
||||||
report_types,
|
report_types,
|
||||||
) = loading_join!(loading_bar, 0.5, None;
|
) = tokio::try_join!(
|
||||||
categories_fut,
|
categories_fut,
|
||||||
loaders_fut,
|
loaders_fut,
|
||||||
game_versions_fut,
|
game_versions_fut,
|
||||||
licenses_fut,
|
|
||||||
donation_platforms_fut,
|
donation_platforms_fut,
|
||||||
report_types_fut
|
report_types_fut
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Store the tags in the database
|
Ok(Self {
|
||||||
self.0.categories.insert(
|
categories,
|
||||||
"categories",
|
loaders,
|
||||||
bincode::encode_to_vec(categories, *BINCODE_CONFIG)?,
|
game_versions,
|
||||||
)?;
|
donation_platforms,
|
||||||
self.0.loaders.insert(
|
report_types,
|
||||||
"loaders",
|
})
|
||||||
bincode::encode_to_vec(loaders, *BINCODE_CONFIG)?,
|
|
||||||
)?;
|
|
||||||
self.0.game_versions.insert(
|
|
||||||
"game_versions",
|
|
||||||
bincode::encode_to_vec(game_versions, *BINCODE_CONFIG)?,
|
|
||||||
)?;
|
|
||||||
self.0.licenses.insert(
|
|
||||||
"licenses",
|
|
||||||
bincode::encode_to_vec(licenses, *BINCODE_CONFIG)?,
|
|
||||||
)?;
|
|
||||||
self.0.donation_platforms.insert(
|
|
||||||
"donation_platforms",
|
|
||||||
bincode::encode_to_vec(donation_platforms, *BINCODE_CONFIG)?,
|
|
||||||
)?;
|
|
||||||
self.0.report_types.insert(
|
|
||||||
"report_types",
|
|
||||||
bincode::encode_to_vec(report_types, *BINCODE_CONFIG)?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serializeable struct for all tags to be fetched together by the frontend
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct TagBundle {
|
|
||||||
pub categories: Vec<Category>,
|
|
||||||
pub loaders: Vec<Loader>,
|
|
||||||
pub game_versions: Vec<GameVersion>,
|
|
||||||
pub licenses: Vec<License>,
|
|
||||||
pub donation_platforms: Vec<DonationPlatform>,
|
|
||||||
pub report_types: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Decode, Encode, Serialize, Deserialize)]
|
|
||||||
pub struct Category {
|
pub struct Category {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub project_type: String,
|
pub project_type: String,
|
||||||
@ -259,26 +192,20 @@ pub struct Category {
|
|||||||
pub icon: PathBuf,
|
pub icon: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Decode, Encode, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Loader {
|
pub struct Loader {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub icon: PathBuf,
|
pub icon: PathBuf,
|
||||||
pub supported_project_types: Vec<String>,
|
pub supported_project_types: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Decode, Encode, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct License {
|
|
||||||
pub short: String,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Decode, Encode, Serialize, Deserialize)]
|
|
||||||
pub struct DonationPlatform {
|
pub struct DonationPlatform {
|
||||||
pub short: String,
|
pub short: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Decode, Encode, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct GameVersion {
|
pub struct GameVersion {
|
||||||
pub version: String,
|
pub version: String,
|
||||||
pub version_type: String,
|
pub version_type: String,
|
||||||
|
|||||||
@ -1,79 +1,70 @@
|
|||||||
//! User login info
|
//! User login info
|
||||||
use crate::{auth::Credentials, config::BINCODE_CONFIG};
|
use crate::auth::Credentials;
|
||||||
|
use crate::data::DirectoryInfo;
|
||||||
|
use crate::util::fetch::{read_json, write};
|
||||||
|
use crate::State;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use tokio::sync::{RwLock, Semaphore};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
const USER_DB_TREE: &[u8] = b"users";
|
const USERS_JSON: &str = "users.json";
|
||||||
|
|
||||||
/// The set of users stored in the launcher
|
/// The set of users stored in the launcher
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Users(pub(crate) sled::Tree);
|
pub(crate) struct Users(pub(crate) HashMap<Uuid, Credentials>);
|
||||||
|
|
||||||
impl Users {
|
impl Users {
|
||||||
#[tracing::instrument(skip(db))]
|
pub async fn init(
|
||||||
pub fn init(db: &sled::Db) -> crate::Result<Self> {
|
dirs: &DirectoryInfo,
|
||||||
Ok(Self(db.open_tree(USER_DB_TREE)?))
|
io_semaphore: &RwLock<Semaphore>,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
|
let users_path = dirs.caches_meta_dir().join(USERS_JSON);
|
||||||
|
let users = read_json(&users_path, io_semaphore).await.ok();
|
||||||
|
|
||||||
|
if let Some(users) = users {
|
||||||
|
Ok(Self(users))
|
||||||
|
} else {
|
||||||
|
Ok(Self(HashMap::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn save(&self) -> crate::Result<()> {
|
||||||
|
let state = State::get().await?;
|
||||||
|
let users_path = state.directories.caches_meta_dir().join(USERS_JSON);
|
||||||
|
write(
|
||||||
|
&users_path,
|
||||||
|
&serde_json::to_vec(&self.0)?,
|
||||||
|
&state.io_semaphore,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub fn insert(
|
pub async fn insert(
|
||||||
&mut self,
|
&mut self,
|
||||||
credentials: &Credentials,
|
credentials: &Credentials,
|
||||||
) -> crate::Result<&Self> {
|
) -> crate::Result<&Self> {
|
||||||
let id = credentials.id.as_bytes();
|
self.0.insert(credentials.id, credentials.clone());
|
||||||
self.0.insert(
|
self.save().await?;
|
||||||
id,
|
|
||||||
bincode::encode_to_vec(credentials, *BINCODE_CONFIG)?,
|
|
||||||
)?;
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn contains(&self, id: uuid::Uuid) -> crate::Result<bool> {
|
pub fn contains(&self, id: Uuid) -> bool {
|
||||||
Ok(self.0.contains_key(id.as_bytes())?)
|
self.0.contains_key(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn get(&self, id: uuid::Uuid) -> crate::Result<Option<Credentials>> {
|
pub fn get(&self, id: Uuid) -> Option<Credentials> {
|
||||||
self.0.get(id.as_bytes())?.map_or(Ok(None), |prof| {
|
self.0.get(&id).cloned()
|
||||||
bincode::decode_from_slice(&prof, *BINCODE_CONFIG)
|
|
||||||
.map_err(crate::Error::from)
|
|
||||||
.map(|it| Some(it.0))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn remove(&mut self, id: uuid::Uuid) -> crate::Result<&Self> {
|
pub async fn remove(&mut self, id: Uuid) -> crate::Result<&Self> {
|
||||||
self.0.remove(id.as_bytes())?;
|
self.0.remove(&id);
|
||||||
|
self.save().await?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> UserIter<impl UserInnerIter> {
|
|
||||||
UserIter(self.0.iter().values(), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
alias_trait! {
|
|
||||||
pub UserInnerIter: Iterator<Item = sled::Result<sled::IVec>>, Send, Sync
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator over the set of users
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UserIter<I: UserInnerIter>(I, bool);
|
|
||||||
|
|
||||||
impl<I: UserInnerIter> Iterator for UserIter<I> {
|
|
||||||
type Item = crate::Result<Credentials>;
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.1 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let it = self.0.next()?;
|
|
||||||
let res = it.map_err(crate::Error::from).and_then(|it| {
|
|
||||||
Ok(bincode::decode_from_slice(&it, *BINCODE_CONFIG)?.0)
|
|
||||||
});
|
|
||||||
|
|
||||||
self.1 = res.is_err();
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -144,6 +144,22 @@ pub async fn fetch_mirrors(
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn read_json<T>(
|
||||||
|
path: &Path,
|
||||||
|
semaphore: &RwLock<Semaphore>,
|
||||||
|
) -> crate::Result<T>
|
||||||
|
where
|
||||||
|
T: DeserializeOwned,
|
||||||
|
{
|
||||||
|
let io_semaphore = semaphore.read().await;
|
||||||
|
let _permit = io_semaphore.acquire().await?;
|
||||||
|
|
||||||
|
let json = fs::read(path).await?;
|
||||||
|
let json = serde_json::from_slice::<T>(&json)?;
|
||||||
|
|
||||||
|
Ok(json)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(bytes, semaphore))]
|
#[tracing::instrument(skip(bytes, semaphore))]
|
||||||
pub async fn write<'a>(
|
pub async fn write<'a>(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
|
|||||||
@ -14,11 +14,3 @@ macro_rules! wrap_ref_builder {
|
|||||||
it
|
it
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alias a trait, used to avoid needing nightly features
|
|
||||||
macro_rules! alias_trait {
|
|
||||||
($scope:vis $name:ident : $bound:path $(, $bounds:path)*) => {
|
|
||||||
$scope trait $name: $bound $(+ $bounds)* {}
|
|
||||||
impl<T: $bound $(+ $bounds)*> $name for T {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -64,6 +64,7 @@ impl ProfileInit {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// TODO: validate inputs from args early
|
// TODO: validate inputs from args early
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
let metadata = state.metadata.read().await;
|
||||||
|
|
||||||
if self.path.exists() {
|
if self.path.exists() {
|
||||||
ensure!(
|
ensure!(
|
||||||
@ -114,7 +115,7 @@ impl ProfileInit {
|
|||||||
let game_version = match &self.game_version {
|
let game_version = match &self.game_version {
|
||||||
Some(version) => version.clone(),
|
Some(version) => version.clone(),
|
||||||
None => {
|
None => {
|
||||||
let default = &state.metadata.minecraft.latest.release;
|
let default = &metadata.minecraft.latest.release;
|
||||||
|
|
||||||
prompt_async(
|
prompt_async(
|
||||||
String::from("Game version"),
|
String::from("Game version"),
|
||||||
@ -163,8 +164,8 @@ impl ProfileInit {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let loader_data = match loader {
|
let loader_data = match loader {
|
||||||
ModLoader::Forge => &state.metadata.forge,
|
ModLoader::Forge => &metadata.forge,
|
||||||
ModLoader::Fabric => &state.metadata.fabric,
|
ModLoader::Fabric => &metadata.fabric,
|
||||||
_ => eyre::bail!("Could not get manifest for loader {loader}. This is a bug in the CLI!"),
|
_ => eyre::bail!("Could not get manifest for loader {loader}. This is a bug in the CLI!"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,6 +194,7 @@ impl ProfileInit {
|
|||||||
loader.map(|x| x.0.id),
|
loader.map(|x| x.0.id),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@ -151,7 +151,6 @@ impl UserDefault {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
info!("Setting user {} as default", self.user.as_hyphenated());
|
info!("Setting user {} as default", self.user.as_hyphenated());
|
||||||
|
|
||||||
// TODO: settings API
|
|
||||||
let state: std::sync::Arc<State> = State::get().await?;
|
let state: std::sync::Arc<State> = State::get().await?;
|
||||||
let mut settings = state.settings.write().await;
|
let mut settings = state.settings.write().await;
|
||||||
|
|
||||||
|
|||||||
4
theseus_gui/.gitignore
vendored
4
theseus_gui/.gitignore
vendored
@ -9,8 +9,6 @@ yarn-error.log*
|
|||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
|
||||||
generated.js
|
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
@ -24,5 +22,3 @@ node_modules
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
generated.js
|
|
||||||
|
|||||||
9
theseus_gui/jsconfig.json
Normal file
9
theseus_gui/jsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ theseus = { path = "../../theseus", features = ["tauri"] }
|
|||||||
|
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tauri = { version = "1.2", features = ["dialog", "dialog-all", "protocol-asset", "window-close", "window-create"] }
|
tauri = { version = "1.2", features = ["dialog", "dialog-open", "protocol-asset", "window-close", "window-create"] }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio-stream = { version = "0.1", features = ["fs"] }
|
tokio-stream = { version = "0.1", features = ["fs"] }
|
||||||
|
|||||||
@ -40,7 +40,7 @@ pub async fn auth_has_user(user: uuid::Uuid) -> Result<bool> {
|
|||||||
/// Get a copy of the list of all user credentials
|
/// Get a copy of the list of all user credentials
|
||||||
// invoke('auth_users',user)
|
// invoke('auth_users',user)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn auth_users() -> Result<Box<[Credentials]>> {
|
pub async fn auth_users() -> Result<Vec<Credentials>> {
|
||||||
Ok(auth::users().await?)
|
Ok(auth::users().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lists active progress bars
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn progress_bars_list(
|
||||||
|
) -> Result<std::collections::HashMap<uuid::Uuid, theseus::LoadingBar>> {
|
||||||
|
let res = theseus::EventState::list_progress_bars().await?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
// This is a very simple macro that implements a very basic Serializable for each variant of TheseusSerializableError,
|
// This is a very simple macro that implements a very basic Serializable for each variant of TheseusSerializableError,
|
||||||
// where the field is the string. (This allows easy extension to errors without many match arms)
|
// where the field is the string. (This allows easy extension to errors without many match arms)
|
||||||
macro_rules! impl_serialize {
|
macro_rules! impl_serialize {
|
||||||
|
|||||||
@ -28,6 +28,53 @@ pub async fn profile_list(
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Syncs a profile's in memory state with the state on the disk
|
||||||
|
/// // invoke('profile_sync')
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn profile_sync(path: &Path) -> Result<()> {
|
||||||
|
profile::sync(path).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Installs/Repairs a profile
|
||||||
|
/// invoke('profile_install')
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn profile_install(path: &Path) -> Result<()> {
|
||||||
|
profile::install(path).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates all of the profile's projects
|
||||||
|
/// invoke('profile_update_all')
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn profile_update_all(path: &Path) -> Result<()> {
|
||||||
|
profile::update_all(path).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates a specified project
|
||||||
|
/// invoke('profile_update_project')
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn profile_update_project(
|
||||||
|
path: &Path,
|
||||||
|
project_path: &Path,
|
||||||
|
) -> Result<()> {
|
||||||
|
profile::update_project(path, project_path, None).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces a project with the given version ID
|
||||||
|
/// invoke('profile_replace_project')
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn profile_replace_project(
|
||||||
|
path: &Path,
|
||||||
|
project: &Path,
|
||||||
|
version_id: String,
|
||||||
|
) -> Result<PathBuf> {
|
||||||
|
let res = profile::replace_project(path, project, version_id).await?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a project to a profile from a version ID
|
// Adds a project to a profile from a version ID
|
||||||
// invoke('profile_add_project_from_version')
|
// invoke('profile_add_project_from_version')
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
|||||||
@ -27,6 +27,7 @@ pub async fn profile_create(
|
|||||||
Some(loader_version),
|
Some(loader_version),
|
||||||
icon,
|
icon,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
use crate::api::Result;
|
use crate::api::Result;
|
||||||
use theseus::tags::{
|
use theseus::tags::{Category, DonationPlatform, GameVersion, Loader, Tags};
|
||||||
Category, DonationPlatform, GameVersion, License, Loader, TagBundle,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Gets cached category tags from the database
|
/// Gets cached category tags from the database
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@ -27,12 +25,6 @@ pub async fn tags_get_game_versions() -> Result<Vec<GameVersion>> {
|
|||||||
Ok(theseus::tags::get_game_version_tags().await?)
|
Ok(theseus::tags::get_game_version_tags().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets cached license tags from the database
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn tags_get_licenses() -> Result<Vec<License>> {
|
|
||||||
Ok(theseus::tags::get_license_tags().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets cached donation platform tags from the database
|
/// Gets cached donation platform tags from the database
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn tags_get_donation_platforms() -> Result<Vec<DonationPlatform>> {
|
pub async fn tags_get_donation_platforms() -> Result<Vec<DonationPlatform>> {
|
||||||
@ -41,6 +33,6 @@ pub async fn tags_get_donation_platforms() -> Result<Vec<DonationPlatform>> {
|
|||||||
|
|
||||||
/// Gets cached tag bundle from the database
|
/// Gets cached tag bundle from the database
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn tags_get_tag_bundle() -> Result<TagBundle> {
|
pub async fn tags_get_tag_bundle() -> Result<Tags> {
|
||||||
Ok(theseus::tags::get_tag_bundle().await?)
|
Ok(theseus::tags::get_tag_bundle().await?)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ mod api;
|
|||||||
async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
||||||
theseus::EventState::init(app).await?;
|
theseus::EventState::init(app).await?;
|
||||||
State::get().await?;
|
State::get().await?;
|
||||||
|
State::update();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,11 +42,17 @@ fn main() {
|
|||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
initialize_state,
|
initialize_state,
|
||||||
should_disable_mouseover,
|
should_disable_mouseover,
|
||||||
|
api::progress_bars_list,
|
||||||
api::profile_create::profile_create_empty,
|
api::profile_create::profile_create_empty,
|
||||||
api::profile_create::profile_create,
|
api::profile_create::profile_create,
|
||||||
api::profile::profile_remove,
|
api::profile::profile_remove,
|
||||||
api::profile::profile_get,
|
api::profile::profile_get,
|
||||||
api::profile::profile_list,
|
api::profile::profile_list,
|
||||||
|
api::profile::profile_sync,
|
||||||
|
api::profile::profile_install,
|
||||||
|
api::profile::profile_update_all,
|
||||||
|
api::profile::profile_update_project,
|
||||||
|
api::profile::profile_replace_project,
|
||||||
api::profile::profile_add_project_from_version,
|
api::profile::profile_add_project_from_version,
|
||||||
api::profile::profile_add_project_from_path,
|
api::profile::profile_add_project_from_path,
|
||||||
api::profile::profile_toggle_disable_project,
|
api::profile::profile_toggle_disable_project,
|
||||||
@ -67,7 +74,6 @@ fn main() {
|
|||||||
api::tags::tags_get_donation_platforms,
|
api::tags::tags_get_donation_platforms,
|
||||||
api::tags::tags_get_game_versions,
|
api::tags::tags_get_game_versions,
|
||||||
api::tags::tags_get_loaders,
|
api::tags::tags_get_loaders,
|
||||||
api::tags::tags_get_licenses,
|
|
||||||
api::tags::tags_get_report_types,
|
api::tags::tags_get_report_types,
|
||||||
api::tags::tags_get_tag_bundle,
|
api::tags::tags_get_tag_bundle,
|
||||||
api::settings::settings_get,
|
api::settings::settings_get,
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"all": true
|
"open": true
|
||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"asset": true,
|
"asset": true,
|
||||||
@ -62,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"csp": "default-src 'self'; connect-src https://modrinth.com https://*.modrinth.com; style-src https://rsms.me/inter/ 'unsafe-inline'; font-src https://rsms.me/inter/; img-src tauri: https: data: blob: 'unsafe-inline' asset: https://asset.localhost"
|
"csp": "default-src 'self'; connect-src https://modrinth.com https://*.modrinth.com; font-src https://cdn-raw.modrinth.com/fonts/inter/; img-src tauri: https: data: blob: 'unsafe-inline' asset: https://asset.localhost"
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
"active": false
|
"active": false
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
@import url('https://rsms.me/inter/inter.css');
|
@import 'inter.scss';
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: var(--font-standard);
|
font-family: var(--font-standard);
|
||||||
|
|||||||
41
theseus_gui/src/assets/stylesheets/inter.scss
Normal file
41
theseus_gui/src/assets/stylesheets/inter.scss
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// TODO: move to omorphia
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Regular.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Regular.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Medium.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Medium.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-SemiBold.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-SemiBold.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Bold.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Bold.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-ExtraBold.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-ExtraBold.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
@ -42,26 +42,52 @@ export async function list() {
|
|||||||
return await invoke('profile_list')
|
return await invoke('profile_list')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Syncs a profile with the disk
|
||||||
|
export async function sync(path) {
|
||||||
|
return await invoke('profile_sync', { path })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Installs/Repairs a profile
|
||||||
|
export async function install(path) {
|
||||||
|
return await invoke('profile_install', { path })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates all of a profile's projects
|
||||||
|
export async function update_all(path) {
|
||||||
|
return await invoke('profile_update_all', { path })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates a specified project
|
||||||
|
export async function update_project(path, projectPath) {
|
||||||
|
return await invoke('profile_update_project', { path, projectPath })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces a given project with the specified version ID
|
||||||
|
// Returns a path to the new project file
|
||||||
|
export async function replace_project(path, projectPath, versionId) {
|
||||||
|
return await invoke('profile_replace_project', { path, projectPath, versionId })
|
||||||
|
}
|
||||||
|
|
||||||
// Add a project to a profile from a version
|
// Add a project to a profile from a version
|
||||||
// Returns a path to the new project file
|
// Returns a path to the new project file
|
||||||
export async function add_project_from_version(path, version_id) {
|
export async function add_project_from_version(path, versionId) {
|
||||||
return await invoke('profile_add_project_from_version', { path, version_id })
|
return await invoke('profile_add_project_from_version', { path, versionId })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a project to a profile from a path + project_type
|
// Add a project to a profile from a path + project_type
|
||||||
// Returns a path to the new project file
|
// Returns a path to the new project file
|
||||||
export async function add_project_from_path(path, project_path, project_type) {
|
export async function add_project_from_path(path, projectPath, projectType) {
|
||||||
return await invoke('profile_add_project_from_path', { path, project_path, project_type })
|
return await invoke('profile_add_project_from_path', { path, projectPath, projectType })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle disabling a project
|
// Toggle disabling a project
|
||||||
export async function toggle_disable_project(path, project_path) {
|
export async function toggle_disable_project(path, projectPath) {
|
||||||
return await invoke('profile_toggle_disable_project', { path, project_path })
|
return await invoke('profile_toggle_disable_project', { path, projectPath })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a project
|
// Remove a project
|
||||||
export async function remove_project(path, project_path) {
|
export async function remove_project(path, projectPath) {
|
||||||
return await invoke('profile_remove_project', { path, project_path })
|
return await invoke('profile_remove_project', { path, projectPath })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run Minecraft using a pathed profile
|
// Run Minecraft using a pathed profile
|
||||||
|
|||||||
@ -10,3 +10,8 @@ import { invoke } from '@tauri-apps/api/tauri'
|
|||||||
export async function initialize_state() {
|
export async function initialize_state() {
|
||||||
return await invoke('initialize_state')
|
return await invoke('initialize_state')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets active progress bars
|
||||||
|
export async function progress_bars_list() {
|
||||||
|
return await invoke('progress_bars_list')
|
||||||
|
}
|
||||||
|
|||||||
@ -25,11 +25,6 @@ export async function get_game_versions() {
|
|||||||
return await invoke('tags_get_game_versions')
|
return await invoke('tags_get_game_versions')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets cached licenses tags
|
|
||||||
export async function get_licenses() {
|
|
||||||
return await invoke('tags_get_licenses')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets cached donation_platforms tags
|
// Gets cached donation_platforms tags
|
||||||
export async function get_donation_platforms() {
|
export async function get_donation_platforms() {
|
||||||
return await invoke('tags_get_donation_platforms')
|
return await invoke('tags_get_donation_platforms')
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { createApp } from 'vue'
|
|||||||
import router from '@/routes'
|
import router from '@/routes'
|
||||||
import App from '@/App.vue'
|
import App from '@/App.vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import '../node_modules/omorphia/dist/style.css'
|
import 'omorphia/dist/style.css'
|
||||||
import '@/assets/stylesheets/global.scss'
|
import '@/assets/stylesheets/global.scss'
|
||||||
import FloatingVue from 'floating-vue'
|
import FloatingVue from 'floating-vue'
|
||||||
import { initialize_state } from '@/helpers/state'
|
import { initialize_state } from '@/helpers/state'
|
||||||
@ -10,8 +10,14 @@ import loadCssMixin from './mixins/macCssFix.js'
|
|||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
|
|
||||||
|
let app = createApp(App)
|
||||||
|
app.use(router)
|
||||||
|
app.use(pinia)
|
||||||
|
app.use(FloatingVue)
|
||||||
|
app.mixin(loadCssMixin)
|
||||||
|
|
||||||
initialize_state()
|
initialize_state()
|
||||||
.then(() => {
|
.then(() => app.mount('#app'))
|
||||||
createApp(App).use(router).use(pinia).use(FloatingVue).mixin(loadCssMixin).mount('#app')
|
.catch((err) => {
|
||||||
|
console.error(err)
|
||||||
})
|
})
|
||||||
.catch((err) => console.error(err))
|
|
||||||
|
|||||||
@ -19,7 +19,6 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
eslint(),
|
|
||||||
svgLoader({
|
svgLoader({
|
||||||
svgoConfig: {
|
svgoConfig: {
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -34,6 +33,7 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
eslint(),
|
||||||
],
|
],
|
||||||
|
|
||||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||||
|
|||||||
@ -7,115 +7,115 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17"
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17"
|
||||||
integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==
|
integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==
|
||||||
|
|
||||||
"@esbuild/android-arm64@0.17.17":
|
"@esbuild/android-arm64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.17.tgz#164b054d58551f8856285f386e1a8f45d9ba3a31"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz#4aa8d8afcffb4458736ca9b32baa97d7cb5861ea"
|
||||||
integrity sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==
|
integrity sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==
|
||||||
|
|
||||||
"@esbuild/android-arm@0.17.17":
|
"@esbuild/android-arm@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.17.tgz#1b3b5a702a69b88deef342a7a80df4c894e4f065"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.18.tgz#74a7e95af4ee212ebc9db9baa87c06a594f2a427"
|
||||||
integrity sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==
|
integrity sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==
|
||||||
|
|
||||||
"@esbuild/android-x64@0.17.17":
|
"@esbuild/android-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.17.tgz#6781527e3c4ea4de532b149d18a2167f06783e7f"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.18.tgz#1dcd13f201997c9fe0b204189d3a0da4eb4eb9b6"
|
||||||
integrity sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==
|
integrity sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==
|
||||||
|
|
||||||
"@esbuild/darwin-arm64@0.17.17":
|
"@esbuild/darwin-arm64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.17.tgz#c5961ef4d3c1cc80dafe905cc145b5a71d2ac196"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz#444f3b961d4da7a89eb9bd35cfa4415141537c2a"
|
||||||
integrity sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==
|
integrity sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==
|
||||||
|
|
||||||
"@esbuild/darwin-x64@0.17.17":
|
"@esbuild/darwin-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.17.tgz#b81f3259cc349691f67ae30f7b333a53899b3c20"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz#a6da308d0ac8a498c54d62e0b2bfb7119b22d315"
|
||||||
integrity sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==
|
integrity sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==
|
||||||
|
|
||||||
"@esbuild/freebsd-arm64@0.17.17":
|
"@esbuild/freebsd-arm64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.17.tgz#db846ad16cf916fd3acdda79b85ea867cb100e87"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz#b83122bb468889399d0d63475d5aea8d6829c2c2"
|
||||||
integrity sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==
|
integrity sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==
|
||||||
|
|
||||||
"@esbuild/freebsd-x64@0.17.17":
|
"@esbuild/freebsd-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.17.tgz#4dd99acbaaba00949d509e7c144b1b6ef9e1815b"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz#af59e0e03fcf7f221b34d4c5ab14094862c9c864"
|
||||||
integrity sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==
|
integrity sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==
|
||||||
|
|
||||||
"@esbuild/linux-arm64@0.17.17":
|
"@esbuild/linux-arm64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.17.tgz#7f9274140b2bb9f4230dbbfdf5dc2761215e30f6"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz#8551d72ba540c5bce4bab274a81c14ed01eafdcf"
|
||||||
integrity sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==
|
integrity sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==
|
||||||
|
|
||||||
"@esbuild/linux-arm@0.17.17":
|
"@esbuild/linux-arm@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.17.tgz#5c8e44c2af056bb2147cf9ad13840220bcb8948b"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz#e09e76e526df4f665d4d2720d28ff87d15cdf639"
|
||||||
integrity sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==
|
integrity sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==
|
||||||
|
|
||||||
"@esbuild/linux-ia32@0.17.17":
|
"@esbuild/linux-ia32@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.17.tgz#18a6b3798658be7f46e9873fa0c8d4bec54c9212"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz#47878860ce4fe73a36fd8627f5647bcbbef38ba4"
|
||||||
integrity sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==
|
integrity sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==
|
||||||
|
|
||||||
"@esbuild/linux-loong64@0.17.17":
|
"@esbuild/linux-loong64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.17.tgz#a8d93514a47f7b4232716c9f02aeb630bae24c40"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz#3f8fbf5267556fc387d20b2e708ce115de5c967a"
|
||||||
integrity sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==
|
integrity sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==
|
||||||
|
|
||||||
"@esbuild/linux-mips64el@0.17.17":
|
"@esbuild/linux-mips64el@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.17.tgz#4784efb1c3f0eac8133695fa89253d558149ee1b"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz#9d896d8f3c75f6c226cbeb840127462e37738226"
|
||||||
integrity sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==
|
integrity sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==
|
||||||
|
|
||||||
"@esbuild/linux-ppc64@0.17.17":
|
"@esbuild/linux-ppc64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.17.tgz#ef6558ec5e5dd9dc16886343e0ccdb0699d70d3c"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz#3d9deb60b2d32c9985bdc3e3be090d30b7472783"
|
||||||
integrity sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==
|
integrity sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==
|
||||||
|
|
||||||
"@esbuild/linux-riscv64@0.17.17":
|
"@esbuild/linux-riscv64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.17.tgz#13a87fdbcb462c46809c9d16bcf79817ecf9ce6f"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz#8a943cf13fd24ff7ed58aefb940ef178f93386bc"
|
||||||
integrity sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==
|
integrity sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==
|
||||||
|
|
||||||
"@esbuild/linux-s390x@0.17.17":
|
"@esbuild/linux-s390x@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.17.tgz#83cb16d1d3ac0dca803b3f031ba3dc13f1ec7ade"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz#66cb01f4a06423e5496facabdce4f7cae7cb80e5"
|
||||||
integrity sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==
|
integrity sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==
|
||||||
|
|
||||||
"@esbuild/linux-x64@0.17.17":
|
"@esbuild/linux-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.17.tgz#7bc400568690b688e20a0c94b2faabdd89ae1a79"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz#23c26050c6c5d1359c7b774823adc32b3883b6c9"
|
||||||
integrity sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==
|
integrity sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==
|
||||||
|
|
||||||
"@esbuild/netbsd-x64@0.17.17":
|
"@esbuild/netbsd-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.17.tgz#1b5dcfbc4bfba80e67a11e9148de836af5b58b6c"
|
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz#789a203d3115a52633ff6504f8cbf757f15e703b"
|
||||||
integrity sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==
|
integrity sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==
|
||||||
|
|
||||||
"@esbuild/openbsd-x64@0.17.17":
|
"@esbuild/openbsd-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.17.tgz#e275098902291149a5dcd012c9ea0796d6b7adff"
|
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz#d7b998a30878f8da40617a10af423f56f12a5e90"
|
||||||
integrity sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==
|
integrity sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==
|
||||||
|
|
||||||
"@esbuild/sunos-x64@0.17.17":
|
"@esbuild/sunos-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.17.tgz#10603474866f64986c0370a2d4fe5a2bb7fee4f5"
|
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz#ecad0736aa7dae07901ba273db9ef3d3e93df31f"
|
||||||
integrity sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==
|
integrity sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==
|
||||||
|
|
||||||
"@esbuild/win32-arm64@0.17.17":
|
"@esbuild/win32-arm64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.17.tgz#521a6d97ee0f96b7c435930353cc4e93078f0b54"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz#58dfc177da30acf956252d7c8ae9e54e424887c4"
|
||||||
integrity sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==
|
integrity sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==
|
||||||
|
|
||||||
"@esbuild/win32-ia32@0.17.17":
|
"@esbuild/win32-ia32@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.17.tgz#56f88462ebe82dad829dc2303175c0e0ccd8e38e"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz#340f6163172b5272b5ae60ec12c312485f69232b"
|
||||||
integrity sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==
|
integrity sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==
|
||||||
|
|
||||||
"@esbuild/win32-x64@0.17.17":
|
"@esbuild/win32-x64@0.17.18":
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.17.tgz#2b577b976e6844106715bbe0cdc57cd1528063f9"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz#3a8e57153905308db357fd02f57c180ee3a0a1fa"
|
||||||
integrity sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==
|
integrity sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==
|
||||||
|
|
||||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.3.0":
|
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.3.0":
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
@ -144,10 +144,10 @@
|
|||||||
minimatch "^3.1.2"
|
minimatch "^3.1.2"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
"@eslint/js@8.38.0":
|
"@eslint/js@8.39.0":
|
||||||
version "8.38.0"
|
version "8.39.0"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.38.0.tgz#73a8a0d8aa8a8e6fe270431c5e72ae91b5337892"
|
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.39.0.tgz#58b536bcc843f4cd1e02a7e6171da5c040f4d44b"
|
||||||
integrity sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==
|
integrity sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==
|
||||||
|
|
||||||
"@floating-ui/core@^0.3.0":
|
"@floating-ui/core@^0.3.0":
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
@ -305,9 +305,9 @@
|
|||||||
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
|
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
|
||||||
|
|
||||||
"@vitejs/plugin-vue@^4.0.0":
|
"@vitejs/plugin-vue@^4.0.0":
|
||||||
version "4.1.0"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.1.0.tgz#b6a9d83cd91575f7ee15593f6444397f68751073"
|
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.2.1.tgz#c3ccce9956e8cdca946f465188777e4e3e488f6a"
|
||||||
integrity sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ==
|
integrity sha512-ZTZjzo7bmxTRTkb8GSTwkPOYDIP7pwuyV+RV53c9PYUouwcbkIZIvWvNWlX2b1dYZqtOv7D6iUAnJLVNGcLrSw==
|
||||||
|
|
||||||
"@vue/compiler-core@3.2.47":
|
"@vue/compiler-core@3.2.47":
|
||||||
version "3.2.47"
|
version "3.2.47"
|
||||||
@ -667,32 +667,32 @@ entities@~3.0.1:
|
|||||||
integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
|
integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
|
||||||
|
|
||||||
esbuild@^0.17.5:
|
esbuild@^0.17.5:
|
||||||
version "0.17.17"
|
version "0.17.18"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.17.tgz#fa906ab11b11d2ed4700f494f4f764229b25c916"
|
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.18.tgz#f4f8eb6d77384d68cd71c53eb6601c7efe05e746"
|
||||||
integrity sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==
|
integrity sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@esbuild/android-arm" "0.17.17"
|
"@esbuild/android-arm" "0.17.18"
|
||||||
"@esbuild/android-arm64" "0.17.17"
|
"@esbuild/android-arm64" "0.17.18"
|
||||||
"@esbuild/android-x64" "0.17.17"
|
"@esbuild/android-x64" "0.17.18"
|
||||||
"@esbuild/darwin-arm64" "0.17.17"
|
"@esbuild/darwin-arm64" "0.17.18"
|
||||||
"@esbuild/darwin-x64" "0.17.17"
|
"@esbuild/darwin-x64" "0.17.18"
|
||||||
"@esbuild/freebsd-arm64" "0.17.17"
|
"@esbuild/freebsd-arm64" "0.17.18"
|
||||||
"@esbuild/freebsd-x64" "0.17.17"
|
"@esbuild/freebsd-x64" "0.17.18"
|
||||||
"@esbuild/linux-arm" "0.17.17"
|
"@esbuild/linux-arm" "0.17.18"
|
||||||
"@esbuild/linux-arm64" "0.17.17"
|
"@esbuild/linux-arm64" "0.17.18"
|
||||||
"@esbuild/linux-ia32" "0.17.17"
|
"@esbuild/linux-ia32" "0.17.18"
|
||||||
"@esbuild/linux-loong64" "0.17.17"
|
"@esbuild/linux-loong64" "0.17.18"
|
||||||
"@esbuild/linux-mips64el" "0.17.17"
|
"@esbuild/linux-mips64el" "0.17.18"
|
||||||
"@esbuild/linux-ppc64" "0.17.17"
|
"@esbuild/linux-ppc64" "0.17.18"
|
||||||
"@esbuild/linux-riscv64" "0.17.17"
|
"@esbuild/linux-riscv64" "0.17.18"
|
||||||
"@esbuild/linux-s390x" "0.17.17"
|
"@esbuild/linux-s390x" "0.17.18"
|
||||||
"@esbuild/linux-x64" "0.17.17"
|
"@esbuild/linux-x64" "0.17.18"
|
||||||
"@esbuild/netbsd-x64" "0.17.17"
|
"@esbuild/netbsd-x64" "0.17.18"
|
||||||
"@esbuild/openbsd-x64" "0.17.17"
|
"@esbuild/openbsd-x64" "0.17.18"
|
||||||
"@esbuild/sunos-x64" "0.17.17"
|
"@esbuild/sunos-x64" "0.17.18"
|
||||||
"@esbuild/win32-arm64" "0.17.17"
|
"@esbuild/win32-arm64" "0.17.18"
|
||||||
"@esbuild/win32-ia32" "0.17.17"
|
"@esbuild/win32-ia32" "0.17.18"
|
||||||
"@esbuild/win32-x64" "0.17.17"
|
"@esbuild/win32-x64" "0.17.18"
|
||||||
|
|
||||||
escape-string-regexp@^4.0.0:
|
escape-string-regexp@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
@ -717,7 +717,7 @@ eslint-plugin-vue@^9.9.0:
|
|||||||
vue-eslint-parser "^9.0.1"
|
vue-eslint-parser "^9.0.1"
|
||||||
xml-name-validator "^4.0.0"
|
xml-name-validator "^4.0.0"
|
||||||
|
|
||||||
eslint-scope@^7.1.1:
|
eslint-scope@^7.1.1, eslint-scope@^7.2.0:
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
|
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
|
||||||
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
|
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
|
||||||
@ -731,14 +731,14 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0:
|
|||||||
integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==
|
integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==
|
||||||
|
|
||||||
eslint@^8.35.0:
|
eslint@^8.35.0:
|
||||||
version "8.38.0"
|
version "8.39.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.38.0.tgz#a62c6f36e548a5574dd35728ac3c6209bd1e2f1a"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.39.0.tgz#7fd20a295ef92d43809e914b70c39fd5a23cf3f1"
|
||||||
integrity sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==
|
integrity sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils" "^4.2.0"
|
"@eslint-community/eslint-utils" "^4.2.0"
|
||||||
"@eslint-community/regexpp" "^4.4.0"
|
"@eslint-community/regexpp" "^4.4.0"
|
||||||
"@eslint/eslintrc" "^2.0.2"
|
"@eslint/eslintrc" "^2.0.2"
|
||||||
"@eslint/js" "8.38.0"
|
"@eslint/js" "8.39.0"
|
||||||
"@humanwhocodes/config-array" "^0.11.8"
|
"@humanwhocodes/config-array" "^0.11.8"
|
||||||
"@humanwhocodes/module-importer" "^1.0.1"
|
"@humanwhocodes/module-importer" "^1.0.1"
|
||||||
"@nodelib/fs.walk" "^1.2.8"
|
"@nodelib/fs.walk" "^1.2.8"
|
||||||
@ -748,7 +748,7 @@ eslint@^8.35.0:
|
|||||||
debug "^4.3.2"
|
debug "^4.3.2"
|
||||||
doctrine "^3.0.0"
|
doctrine "^3.0.0"
|
||||||
escape-string-regexp "^4.0.0"
|
escape-string-regexp "^4.0.0"
|
||||||
eslint-scope "^7.1.1"
|
eslint-scope "^7.2.0"
|
||||||
eslint-visitor-keys "^3.4.0"
|
eslint-visitor-keys "^3.4.0"
|
||||||
espree "^9.5.1"
|
espree "^9.5.1"
|
||||||
esquery "^1.4.2"
|
esquery "^1.4.2"
|
||||||
@ -889,11 +889,6 @@ fsevents@~2.3.2:
|
|||||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||||
|
|
||||||
function-bind@^1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
|
||||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
|
||||||
|
|
||||||
glob-parent@^6.0.2:
|
glob-parent@^6.0.2:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
|
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
|
||||||
@ -937,13 +932,6 @@ has-flag@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
|
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
|
||||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||||
|
|
||||||
has@^1.0.3:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
|
||||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
|
||||||
dependencies:
|
|
||||||
function-bind "^1.1.1"
|
|
||||||
|
|
||||||
highlight.js@^11.7.0:
|
highlight.js@^11.7.0:
|
||||||
version "11.7.0"
|
version "11.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.7.0.tgz#3ff0165bc843f8c9bce1fd89e2fda9143d24b11e"
|
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.7.0.tgz#3ff0165bc843f8c9bce1fd89e2fda9143d24b11e"
|
||||||
@ -992,13 +980,6 @@ is-binary-path@~2.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
binary-extensions "^2.0.0"
|
binary-extensions "^2.0.0"
|
||||||
|
|
||||||
is-core-module@^2.11.0:
|
|
||||||
version "2.12.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4"
|
|
||||||
integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==
|
|
||||||
dependencies:
|
|
||||||
has "^1.0.3"
|
|
||||||
|
|
||||||
is-extglob@^2.1.1:
|
is-extglob@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||||
@ -1168,7 +1149,7 @@ ofetch@^1.0.1:
|
|||||||
node-fetch-native "^1.0.2"
|
node-fetch-native "^1.0.2"
|
||||||
ufo "^1.1.0"
|
ufo "^1.1.0"
|
||||||
|
|
||||||
omorphia@^0.4.11:
|
omorphia@^0.4.10:
|
||||||
version "0.4.10"
|
version "0.4.10"
|
||||||
resolved "https://registry.yarnpkg.com/omorphia/-/omorphia-0.4.10.tgz#93c0e6a08a233f27d76587286e42450af44bb55d"
|
resolved "https://registry.yarnpkg.com/omorphia/-/omorphia-0.4.10.tgz#93c0e6a08a233f27d76587286e42450af44bb55d"
|
||||||
integrity sha512-WgSFosOqoM0IRpzGNYyprfZSRyBLgqs6sTmKRuWo96ZpzrHRWAom2upIm/HAxAC+YBwFni5sgUeBemXYI7wmuw==
|
integrity sha512-WgSFosOqoM0IRpzGNYyprfZSRyBLgqs6sTmKRuWo96ZpzrHRWAom2upIm/HAxAC+YBwFni5sgUeBemXYI7wmuw==
|
||||||
@ -1237,11 +1218,6 @@ path-key@^3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||||
|
|
||||||
path-parse@^1.0.7:
|
|
||||||
version "1.0.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
|
||||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
|
||||||
|
|
||||||
picocolors@^1.0.0:
|
picocolors@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||||
@ -1253,9 +1229,9 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
|
|||||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||||
|
|
||||||
pinia@^2.0.33:
|
pinia@^2.0.33:
|
||||||
version "2.0.34"
|
version "2.0.35"
|
||||||
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.34.tgz#6c0c84f06b631c30c030633fa64e525c609105a9"
|
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.35.tgz#aa2597038bb55ea14ad689f83065d2814ebb8c10"
|
||||||
integrity sha512-cgOoGUiyqX0SSgX8XelK9+Ri4XA2/YyNtgjogwfzIx1g7iZTaZPxm7/bZYMCLU2qHRiHhxG7SuQO0eBacFNc2Q==
|
integrity sha512-P1IKKQWhxGXiiZ3atOaNI75bYlFUbRxtJdhPLX059Z7+b9Z04rnTZdSY8Aph1LA+/4QEMAYHsTQ638Wfe+6K5g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.5.0"
|
"@vue/devtools-api" "^6.5.0"
|
||||||
vue-demi "*"
|
vue-demi "*"
|
||||||
@ -1268,7 +1244,7 @@ postcss-selector-parser@^6.0.9:
|
|||||||
cssesc "^3.0.0"
|
cssesc "^3.0.0"
|
||||||
util-deprecate "^1.0.2"
|
util-deprecate "^1.0.2"
|
||||||
|
|
||||||
postcss@^8.1.10, postcss@^8.4.21:
|
postcss@^8.1.10, postcss@^8.4.23:
|
||||||
version "8.4.23"
|
version "8.4.23"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab"
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab"
|
||||||
integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==
|
integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==
|
||||||
@ -1283,9 +1259,9 @@ prelude-ls@^1.2.1:
|
|||||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||||
|
|
||||||
prettier@^2.8.7:
|
prettier@^2.8.7:
|
||||||
version "2.8.7"
|
version "2.8.8"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
|
||||||
integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==
|
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
|
||||||
|
|
||||||
punycode@^2.1.0:
|
punycode@^2.1.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
@ -1309,15 +1285,6 @@ resolve-from@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||||
|
|
||||||
resolve@^1.22.1:
|
|
||||||
version "1.22.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
|
|
||||||
integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
|
|
||||||
dependencies:
|
|
||||||
is-core-module "^2.11.0"
|
|
||||||
path-parse "^1.0.7"
|
|
||||||
supports-preserve-symlinks-flag "^1.0.0"
|
|
||||||
|
|
||||||
reusify@^1.0.4:
|
reusify@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||||
@ -1337,10 +1304,10 @@ rollup@^2.77.2:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
rollup@^3.18.0:
|
rollup@^3.21.0:
|
||||||
version "3.20.6"
|
version "3.21.0"
|
||||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.20.6.tgz#53c0fd73e397269d2ce5f0ec12851457dd53cacd"
|
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.21.0.tgz#0a71517db56e150222670f88e5e7acfa4fede7c8"
|
||||||
integrity sha512-2yEB3nQXp/tBQDN0hJScJQheXdvU2wFhh6ld7K/aiZ1vYcak6N/BKjY1QrU6BvO2JWYS8bEs14FRaxXosxy2zw==
|
integrity sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
@ -1352,9 +1319,9 @@ run-parallel@^1.1.9:
|
|||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
sass@^1.58.3:
|
sass@^1.58.3:
|
||||||
version "1.62.0"
|
version "1.62.1"
|
||||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.62.0.tgz#3686b2195b93295d20765135e562366b33ece37d"
|
resolved "https://registry.yarnpkg.com/sass/-/sass-1.62.1.tgz#caa8d6bf098935bc92fc73fa169fb3790cacd029"
|
||||||
integrity sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==
|
integrity sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar ">=3.0.0 <4.0.0"
|
chokidar ">=3.0.0 <4.0.0"
|
||||||
immutable "^4.0.0"
|
immutable "^4.0.0"
|
||||||
@ -1418,11 +1385,6 @@ supports-color@^7.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
|
||||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
|
||||||
|
|
||||||
svgo@^3.0.2:
|
svgo@^3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a"
|
resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a"
|
||||||
@ -1499,14 +1461,13 @@ vite-svg-loader@^4.0.0:
|
|||||||
svgo "^3.0.2"
|
svgo "^3.0.2"
|
||||||
|
|
||||||
vite@^4.0.0:
|
vite@^4.0.0:
|
||||||
version "4.2.2"
|
version "4.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-4.2.2.tgz#014c30e5163844f6e96d7fe18fbb702236516dc6"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.3.tgz#26adb4aa01439fc4546c480ea547674d87289396"
|
||||||
integrity sha512-PcNtT5HeDxb3QaSqFYkEum8f5sCVe0R3WK20qxgIvNBZPXU/Obxs/+ubBMeE7nLWeCo2LDzv+8hRYSlcaSehig==
|
integrity sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.17.5"
|
esbuild "^0.17.5"
|
||||||
postcss "^8.4.21"
|
postcss "^8.4.23"
|
||||||
resolve "^1.22.1"
|
rollup "^3.21.0"
|
||||||
rollup "^3.18.0"
|
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,8 @@ async fn main() -> theseus::Result<()> {
|
|||||||
|
|
||||||
// Initialize state
|
// Initialize state
|
||||||
let st = State::get().await?;
|
let st = State::get().await?;
|
||||||
|
State::update();
|
||||||
|
|
||||||
st.settings.write().await.max_concurrent_downloads = 5;
|
st.settings.write().await.max_concurrent_downloads = 5;
|
||||||
st.settings.write().await.hooks.post_exit =
|
st.settings.write().await.hooks.post_exit =
|
||||||
Some("echo This is after Minecraft runs- global setting!".to_string());
|
Some("echo This is after Minecraft runs- global setting!".to_string());
|
||||||
@ -61,26 +63,30 @@ async fn main() -> theseus::Result<()> {
|
|||||||
Some(loader_version),
|
Some(loader_version),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
println!("Adding sodium");
|
// let mut value = list().await?;
|
||||||
let sodium_path = profile::add_project_from_version(
|
// let profile_path = value.iter().next().map(|x| x.0).unwrap();
|
||||||
&profile_path,
|
|
||||||
"rAfhHfow".to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mod_menu_path = profile::add_project_from_version(
|
// println!("Adding sodium");
|
||||||
&profile_path,
|
// let sodium_path = profile::add_project_from_version(
|
||||||
"gSoPJyVn".to_string(),
|
// &profile_path,
|
||||||
)
|
// "rAfhHfow".to_string(),
|
||||||
.await?;
|
// )
|
||||||
|
// .await?;
|
||||||
println!("Disabling sodium");
|
//
|
||||||
profile::toggle_disable_project(&profile_path, &sodium_path).await?;
|
// let mod_menu_path = profile::add_project_from_version(
|
||||||
|
// &profile_path,
|
||||||
profile::remove_project(&profile_path, &mod_menu_path).await?;
|
// "gSoPJyVn".to_string(),
|
||||||
|
// )
|
||||||
|
// .await?;
|
||||||
|
//
|
||||||
|
// println!("Disabling sodium");
|
||||||
|
// profile::toggle_disable_project(&profile_path, &sodium_path).await?;
|
||||||
|
//
|
||||||
|
// profile::remove_project(&profile_path, &mod_menu_path).await?;
|
||||||
// let profile_path =
|
// let profile_path =
|
||||||
// pack::install_pack_from_version_id("KxUUUFh5".to_string())
|
// pack::install_pack_from_version_id("KxUUUFh5".to_string())
|
||||||
// .await
|
// .await
|
||||||
@ -102,7 +108,7 @@ async fn main() -> theseus::Result<()> {
|
|||||||
State::sync().await?;
|
State::sync().await?;
|
||||||
|
|
||||||
// Attempt to run game
|
// Attempt to run game
|
||||||
if auth::users().await?.len() == 0 {
|
if auth::users().await?.is_empty() {
|
||||||
println!("No users found, authenticating.");
|
println!("No users found, authenticating.");
|
||||||
authenticate_run().await?; // could take credentials from here direct, but also deposited in state users
|
authenticate_run().await?; // could take credentials from here direct, but also deposited in state users
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user