Misc improvements and fixes (#109)
* now utilizing tracing better * better tracing * fix mac vs pc oppositional env var issue * modified loading package * added droppable loadingbarid that sends completion message * loading bar * regressed bug on mac * fixed non-updated loading bar on playground * Loading bar improvements --------- Co-authored-by: Jai A <jaiagr+gpg@pm.me>
This commit is contained in:
parent
c79d5c32a6
commit
65c1942037
154
Cargo.lock
generated
154
Cargo.lock
generated
@ -50,6 +50,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.70"
|
version = "1.0.70"
|
||||||
@ -468,7 +477,7 @@ dependencies = [
|
|||||||
"indenter",
|
"indenter",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
"tracing-error",
|
"tracing-error 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -480,7 +489,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-error",
|
"tracing-error 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1001,9 +1010,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
|
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
@ -1011,9 +1020,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
|
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-executor"
|
name = "futures-executor"
|
||||||
@ -1028,38 +1037,38 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
|
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
|
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
|
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879"
|
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
|
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -1608,6 +1617,18 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indicatif"
|
||||||
|
version = "0.17.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"number_prefix",
|
||||||
|
"portable-atomic",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "infer"
|
name = "infer"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -1820,7 +1841,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber 0.3.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1863,6 +1884,15 @@ dependencies = [
|
|||||||
"tendril",
|
"tendril",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2077,6 +2107,12 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "number_prefix"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc"
|
name = "objc"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@ -2458,6 +2494,12 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "0.3.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@ -2699,10 +2741,12 @@ dependencies = [
|
|||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
|
"tokio-util",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"url",
|
"url",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
|
"wasm-streams",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winreg 0.10.1",
|
"winreg 0.10.1",
|
||||||
]
|
]
|
||||||
@ -3516,8 +3560,8 @@ dependencies = [
|
|||||||
"dirs",
|
"dirs",
|
||||||
"dunce",
|
"dunce",
|
||||||
"futures",
|
"futures",
|
||||||
|
"indicatif",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
|
||||||
"paste",
|
"paste",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -3532,7 +3576,8 @@ dependencies = [
|
|||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"toml 0.7.3",
|
"toml 0.7.3",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-error",
|
"tracing-error 0.1.2",
|
||||||
|
"tracing-subscriber 0.2.25",
|
||||||
"url",
|
"url",
|
||||||
"uuid 1.3.0",
|
"uuid 1.3.0",
|
||||||
"winreg 0.11.0",
|
"winreg 0.11.0",
|
||||||
@ -3557,9 +3602,9 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-error",
|
"tracing-error 0.2.0",
|
||||||
"tracing-futures",
|
"tracing-futures",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber 0.3.16",
|
||||||
"url",
|
"url",
|
||||||
"uuid 1.3.0",
|
"uuid 1.3.0",
|
||||||
"webbrowser",
|
"webbrowser",
|
||||||
@ -3582,6 +3627,9 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
"tracing",
|
||||||
|
"tracing-error 0.1.2",
|
||||||
|
"tracing-subscriber 0.2.25",
|
||||||
"url",
|
"url",
|
||||||
"uuid 1.3.0",
|
"uuid 1.3.0",
|
||||||
]
|
]
|
||||||
@ -3600,6 +3648,9 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
"tracing",
|
||||||
|
"tracing-error 0.1.2",
|
||||||
|
"tracing-subscriber 0.2.25",
|
||||||
"url",
|
"url",
|
||||||
"uuid 1.3.0",
|
"uuid 1.3.0",
|
||||||
"webbrowser",
|
"webbrowser",
|
||||||
@ -3842,6 +3893,16 @@ dependencies = [
|
|||||||
"valuable",
|
"valuable",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-error"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24"
|
||||||
|
dependencies = [
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber 0.2.25",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-error"
|
name = "tracing-error"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -3849,7 +3910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber 0.3.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3873,13 +3934,45 @@ dependencies = [
|
|||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-serde"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.2.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"chrono",
|
||||||
|
"lazy_static",
|
||||||
|
"matchers 0.0.1",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
|
"tracing-serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.16"
|
version = "0.3.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matchers",
|
"matchers 0.1.0",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
"regex",
|
||||||
@ -4139,6 +4232,19 @@ version = "0.2.84"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-streams"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078"
|
||||||
|
dependencies = [
|
||||||
|
"futures-util",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.61"
|
version = "0.3.61"
|
||||||
|
|||||||
@ -22,19 +22,21 @@ chrono = { version = "0.4.19", features = ["serde"] }
|
|||||||
daedalus = { version = "0.1.20" }
|
daedalus = { version = "0.1.20" }
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
|
|
||||||
log = "0.4.14"
|
|
||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
sys-info = "0.9.0"
|
sys-info = "0.9.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tracing = "0.1"
|
tracing = "0.1.37"
|
||||||
tracing-error = "0.2"
|
tracing-subscriber = "0.2"
|
||||||
|
tracing-error = "0.1"
|
||||||
|
|
||||||
|
paste = { version = "1.0"}
|
||||||
|
|
||||||
tauri = { version = "1.2", optional = true}
|
tauri = { version = "1.2", optional = true}
|
||||||
paste = { version = "1.0", optional = true}
|
indicatif = { version = "0.17.3", optional = true }
|
||||||
|
|
||||||
async-tungstenite = { version = "0.20.0", features = ["tokio-runtime", "tokio-native-tls"] }
|
async-tungstenite = { version = "0.20.0", features = ["tokio-runtime", "tokio-native-tls"] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
reqwest = { version = "0.11", features = ["json"] }
|
reqwest = { version = "0.11", features = ["json", "stream"] }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tokio-stream = { version = "0.1", features = ["fs"] }
|
tokio-stream = { version = "0.1", features = ["fs"] }
|
||||||
|
|
||||||
@ -45,4 +47,5 @@ dunce = "1.0.3"
|
|||||||
winreg = "0.11.0"
|
winreg = "0.11.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
tauri = ["dep:tauri", "dep:paste"]
|
tauri = ["dep:tauri"]
|
||||||
|
cli = ["dep:indicatif"]
|
||||||
@ -46,7 +46,7 @@ pub async fn authenticate(
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let credentials = flow.extract_credentials(&state.io_semaphore).await?;
|
let credentials = flow.extract_credentials(&state.fetch_semaphore).await?;
|
||||||
users.insert(&credentials).await?;
|
users.insert(&credentials).await?;
|
||||||
|
|
||||||
if state.settings.read().await.default_user.is_none() {
|
if state.settings.read().await.default_user.is_none() {
|
||||||
@ -64,7 +64,7 @@ pub async fn refresh(user: uuid::Uuid) -> crate::Result<Credentials> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let mut users = state.users.write().await;
|
let mut users = state.users.write().await;
|
||||||
|
|
||||||
let io_sempahore = &state.io_semaphore;
|
let fetch_semaphore = &state.fetch_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}"
|
||||||
@ -73,7 +73,8 @@ pub async fn refresh(user: uuid::Uuid) -> crate::Result<Credentials> {
|
|||||||
}))
|
}))
|
||||||
.and_then(|mut credentials| async move {
|
.and_then(|mut credentials| async move {
|
||||||
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, fetch_semaphore)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
users.insert(&credentials).await?;
|
users.insert(&credentials).await?;
|
||||||
Ok(credentials)
|
Ok(credentials)
|
||||||
|
|||||||
@ -61,6 +61,7 @@ pub async fn get_optimal_jre_key(profile: &Profile) -> crate::Result<String> {
|
|||||||
version,
|
version,
|
||||||
profile.metadata.loader_version.as_ref(),
|
profile.metadata.loader_version.as_ref(),
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let optimal_key = match version_info
|
let optimal_key = match version_info
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
use crate::config::MODRINTH_API_URL;
|
use crate::config::MODRINTH_API_URL;
|
||||||
use crate::data::ModLoader;
|
use crate::data::ModLoader;
|
||||||
use crate::event::emit::{
|
use crate::event::emit::{
|
||||||
emit_loading, init_loading, loading_try_for_each_concurrent,
|
emit_loading, init_loading, init_or_edit_loading,
|
||||||
|
loading_try_for_each_concurrent,
|
||||||
};
|
};
|
||||||
use crate::event::LoadingBarType;
|
use crate::event::{LoadingBarId, LoadingBarType};
|
||||||
use crate::state::{LinkedData, 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_advanced, fetch_json, fetch_mirrors, write, write_cached_icon,
|
||||||
};
|
};
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use async_zip::tokio::read::seek::ZipFileReader;
|
use async_zip::tokio::read::seek::ZipFileReader;
|
||||||
@ -75,17 +76,30 @@ enum PackDependency {
|
|||||||
|
|
||||||
pub async fn install_pack_from_version_id(
|
pub async fn install_pack_from_version_id(
|
||||||
version_id: String,
|
version_id: String,
|
||||||
|
title: Option<String>,
|
||||||
) -> crate::Result<PathBuf> {
|
) -> crate::Result<PathBuf> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
|
||||||
|
let loading_bar = init_loading(
|
||||||
|
LoadingBarType::PackFileDownload {
|
||||||
|
pack_name: title,
|
||||||
|
pack_version: version_id.clone(),
|
||||||
|
},
|
||||||
|
100.0,
|
||||||
|
"Downloading pack file",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
emit_loading(&loading_bar, 0.0, Some("Fetching version")).await?;
|
||||||
let version: ModrinthVersion = fetch_json(
|
let version: ModrinthVersion = fetch_json(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
&format!("{}version/{}", MODRINTH_API_URL, version_id),
|
&format!("{}version/{}", MODRINTH_API_URL, version_id),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&state.io_semaphore,
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
emit_loading(&loading_bar, 10.0, None).await?;
|
||||||
|
|
||||||
let (url, hash) =
|
let (url, hash) =
|
||||||
if let Some(file) = version.files.iter().find(|x| x.primary) {
|
if let Some(file) = version.files.iter().find(|x| x.primary) {
|
||||||
@ -102,20 +116,31 @@ pub async fn install_pack_from_version_id(
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let file = fetch(&url, hash.map(|x| &**x), &state.io_semaphore).await?;
|
let file = fetch_advanced(
|
||||||
|
Method::GET,
|
||||||
|
&url,
|
||||||
|
hash.map(|x| &**x),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Some((&loading_bar, 70.0)),
|
||||||
|
&state.fetch_semaphore,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
emit_loading(&loading_bar, 0.0, Some("Fetching project metadata")).await?;
|
||||||
|
|
||||||
let project: ModrinthProject = fetch_json(
|
let project: ModrinthProject = fetch_json(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
&format!("{}project/{}", MODRINTH_API_URL, version.project_id),
|
&format!("{}project/{}", MODRINTH_API_URL, version.project_id),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&state.io_semaphore,
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
emit_loading(&loading_bar, 10.0, Some("Retrieving icon")).await?;
|
||||||
let icon = if let Some(icon_url) = project.icon_url {
|
let icon = if let Some(icon_url) = project.icon_url {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let icon_bytes = fetch(&icon_url, None, &state.io_semaphore).await?;
|
let icon_bytes = fetch(&icon_url, None, &state.fetch_semaphore).await?;
|
||||||
|
|
||||||
let filename = icon_url.rsplit('/').next();
|
let filename = icon_url.rsplit('/').next();
|
||||||
|
|
||||||
@ -135,6 +160,7 @@ pub async fn install_pack_from_version_id(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
emit_loading(&loading_bar, 10.0, None).await?;
|
||||||
|
|
||||||
install_pack(
|
install_pack(
|
||||||
file,
|
file,
|
||||||
@ -142,6 +168,7 @@ pub async fn install_pack_from_version_id(
|
|||||||
Some(project.title),
|
Some(project.title),
|
||||||
Some(version.project_id),
|
Some(version.project_id),
|
||||||
Some(version.id),
|
Some(version.id),
|
||||||
|
Some(loading_bar),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@ -149,7 +176,7 @@ pub async fn install_pack_from_version_id(
|
|||||||
pub async fn install_pack_from_file(path: PathBuf) -> crate::Result<PathBuf> {
|
pub async fn install_pack_from_file(path: PathBuf) -> crate::Result<PathBuf> {
|
||||||
let file = fs::read(path).await?;
|
let file = fs::read(path).await?;
|
||||||
|
|
||||||
install_pack(bytes::Bytes::from(file), None, None, None, None).await
|
install_pack(bytes::Bytes::from(file), None, None, None, None, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn install_pack(
|
async fn install_pack(
|
||||||
@ -158,6 +185,7 @@ async fn install_pack(
|
|||||||
override_title: Option<String>,
|
override_title: Option<String>,
|
||||||
project_id: Option<String>,
|
project_id: Option<String>,
|
||||||
version_id: Option<String>,
|
version_id: Option<String>,
|
||||||
|
existing_loading_bar: Option<LoadingBarId>,
|
||||||
) -> crate::Result<PathBuf> {
|
) -> crate::Result<PathBuf> {
|
||||||
let state = &State::get().await?;
|
let state = &State::get().await?;
|
||||||
|
|
||||||
@ -242,14 +270,15 @@ async fn install_pack(
|
|||||||
.await?;
|
.await?;
|
||||||
let profile = profile_raw.clone();
|
let profile = profile_raw.clone();
|
||||||
let result = async {
|
let result = async {
|
||||||
let loading_bar = init_loading(
|
let loading_bar = init_or_edit_loading(
|
||||||
|
existing_loading_bar,
|
||||||
LoadingBarType::PackDownload {
|
LoadingBarType::PackDownload {
|
||||||
pack_name: pack.name.clone(),
|
pack_name: pack.name.clone(),
|
||||||
pack_id: project_id,
|
pack_id: project_id,
|
||||||
pack_version: version_id,
|
pack_version: version_id,
|
||||||
},
|
},
|
||||||
100.0,
|
100.0,
|
||||||
"Downloading modpack...",
|
"Downloading modpack",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -260,7 +289,7 @@ async fn install_pack(
|
|||||||
.map(Ok::<PackFile, crate::Error>),
|
.map(Ok::<PackFile, crate::Error>),
|
||||||
None,
|
None,
|
||||||
Some(&loading_bar),
|
Some(&loading_bar),
|
||||||
80.0,
|
70.0,
|
||||||
num_files,
|
num_files,
|
||||||
None,
|
None,
|
||||||
|project| {
|
|project| {
|
||||||
@ -287,7 +316,7 @@ async fn install_pack(
|
|||||||
.hashes
|
.hashes
|
||||||
.get(&PackFileHash::Sha1)
|
.get(&PackFileHash::Sha1)
|
||||||
.map(|x| &**x),
|
.map(|x| &**x),
|
||||||
&state.io_semaphore,
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -365,11 +394,11 @@ async fn install_pack(
|
|||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
|
|
||||||
emit_loading(&loading_bar, 0.05, Some("Extracting overrides"))
|
emit_loading(&loading_bar, 0.0, Some("Extracting overrides"))
|
||||||
.await?;
|
.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"))
|
emit_loading(&loading_bar, 29.9, Some("Done extacting overrides"))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(profile) = crate::api::profile::get(&profile).await? {
|
if let Some(profile) = crate::api::profile::get(&profile).await? {
|
||||||
@ -380,13 +409,6 @@ async fn install_pack(
|
|||||||
Some(loading_bar)
|
Some(loading_bar)
|
||||||
),
|
),
|
||||||
)?;
|
)?;
|
||||||
} else {
|
|
||||||
emit_loading(
|
|
||||||
&loading_bar,
|
|
||||||
0.1,
|
|
||||||
Some("Done extacting overrides"),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok::<PathBuf, crate::Error>(profile)
|
Ok::<PathBuf, crate::Error>(profile)
|
||||||
|
|||||||
@ -148,7 +148,7 @@ pub async fn update_all(profile_path: &Path) -> crate::Result<()> {
|
|||||||
profile_name: profile.metadata.name.clone(),
|
profile_name: profile.metadata.name.clone(),
|
||||||
},
|
},
|
||||||
100.0,
|
100.0,
|
||||||
"Updating profile...",
|
"Updating profile",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ pub async fn update_all(profile_path: &Path) -> crate::Result<()> {
|
|||||||
None,
|
None,
|
||||||
Some(&loading_bar),
|
Some(&loading_bar),
|
||||||
100.0,
|
100.0,
|
||||||
profile.projects.len(),
|
profile.projects.keys().len(),
|
||||||
None,
|
None,
|
||||||
|project| update_project(profile_path, project, Some(true)),
|
|project| update_project(profile_path, project, Some(true)),
|
||||||
)
|
)
|
||||||
@ -344,7 +344,7 @@ pub async fn remove_project(
|
|||||||
}
|
}
|
||||||
/// Run Minecraft using a profile and the default credentials, logged in credentials,
|
/// Run Minecraft using a profile and the default credentials, logged in credentials,
|
||||||
/// failing with an error if no credentials are available
|
/// failing with an error if no credentials are available
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument]
|
||||||
pub async fn run(path: &Path) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
pub async fn run(path: &Path) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
|
||||||
@ -367,7 +367,7 @@ pub async fn run(path: &Path) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
|||||||
|
|
||||||
/// Run Minecraft using a profile, and credentials for authentication
|
/// Run Minecraft using a profile, and credentials for authentication
|
||||||
/// Returns Arc pointer to RwLock to Child
|
/// Returns Arc pointer to RwLock to Child
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument]
|
||||||
pub async fn run_credentials(
|
pub async fn run_credentials(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
credentials: &auth::Credentials,
|
credentials: &auth::Credentials,
|
||||||
@ -398,6 +398,7 @@ pub async fn run_credentials(
|
|||||||
version,
|
version,
|
||||||
profile.metadata.loader_version.as_ref(),
|
profile.metadata.loader_version.as_ref(),
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let pre_launch_hooks =
|
let pre_launch_hooks =
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
//! Theseus profile management interface
|
//! Theseus profile management interface
|
||||||
|
use crate::event::emit::emit_warning;
|
||||||
use crate::state::LinkedData;
|
use crate::state::LinkedData;
|
||||||
use crate::{
|
use crate::{
|
||||||
event::{emit::emit_profile, ProfilePayloadType},
|
event::{emit::emit_profile, ProfilePayloadType},
|
||||||
@ -15,6 +16,7 @@ use futures::prelude::*;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tokio_stream::wrappers::ReadDirStream;
|
use tokio_stream::wrappers::ReadDirStream;
|
||||||
|
use tracing::{info, trace};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const DEFAULT_NAME: &str = "Untitled Instance";
|
const DEFAULT_NAME: &str = "Untitled Instance";
|
||||||
@ -47,6 +49,7 @@ pub async fn profile_create(
|
|||||||
linked_data: Option<LinkedData>, // 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>,
|
skip_install_profile: Option<bool>,
|
||||||
) -> crate::Result<PathBuf> {
|
) -> crate::Result<PathBuf> {
|
||||||
|
trace!("Creating new profile. {}", name);
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let metadata = state.metadata.read().await;
|
let metadata = state.metadata.read().await;
|
||||||
|
|
||||||
@ -74,7 +77,7 @@ pub async fn profile_create(
|
|||||||
fs::create_dir_all(&path).await?;
|
fs::create_dir_all(&path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
info!(
|
||||||
"Creating profile at path {}",
|
"Creating profile at path {}",
|
||||||
&canonicalize(&path)?.display()
|
&canonicalize(&path)?.display()
|
||||||
);
|
);
|
||||||
@ -173,7 +176,7 @@ pub async fn profile_create(
|
|||||||
extra_arguments: None,
|
extra_arguments: None,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
println!("Could not detect optimal JRE: {optimal_version_key}, falling back to system default.");
|
emit_warning(&format!("Could not detect optimal JRE: {optimal_version_key}, falling back to system default.")).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_profile(
|
emit_profile(
|
||||||
|
|||||||
@ -19,8 +19,22 @@ pub async fn get() -> crate::Result<Settings> {
|
|||||||
pub async fn set(settings: Settings) -> crate::Result<()> {
|
pub async fn set(settings: Settings) -> crate::Result<()> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
// Replaces the settings struct in the RwLock with the passed argument
|
// Replaces the settings struct in the RwLock with the passed argument
|
||||||
|
let (reset_io, reset_fetch) = async {
|
||||||
|
let read = state.settings.read().await;
|
||||||
|
(
|
||||||
|
settings.max_concurrent_writes != read.max_concurrent_writes,
|
||||||
|
settings.max_concurrent_downloads != read.max_concurrent_downloads,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
*state.settings.write().await = settings;
|
*state.settings.write().await = settings;
|
||||||
state.reset_semaphore().await; // reset semaphore to new max
|
if reset_io {
|
||||||
|
state.reset_io_semaphore().await;
|
||||||
|
}
|
||||||
|
if reset_fetch {
|
||||||
|
state.reset_fetch_semaphore().await;
|
||||||
|
}
|
||||||
State::sync().await?;
|
State::sync().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
|
use super::LoadingBarId;
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
EventError, LoadingBar, LoadingBarType, ProcessPayloadType,
|
EventError, LoadingBar, LoadingBarType, ProcessPayloadType,
|
||||||
ProfilePayloadType,
|
ProfilePayloadType,
|
||||||
};
|
};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
#[cfg(feature = "tauri")]
|
#[cfg(feature = "tauri")]
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
@ -13,6 +15,9 @@ use crate::event::{
|
|||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[cfg(feature = "cli")]
|
||||||
|
const CLI_PROGRESS_BAR_TOTAL: u64 = 1000;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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.
|
||||||
We include a feature flag for Tauri, so that we can compile this code without Tauri.
|
We include a feature flag for Tauri, so that we can compile this code without Tauri.
|
||||||
@ -45,18 +50,34 @@ pub async fn init_loading(
|
|||||||
bar_type: LoadingBarType,
|
bar_type: LoadingBarType,
|
||||||
total: f64,
|
total: f64,
|
||||||
title: &str,
|
title: &str,
|
||||||
) -> crate::Result<Uuid> {
|
) -> crate::Result<LoadingBarId> {
|
||||||
let event_state = crate::EventState::get().await?;
|
let event_state = crate::EventState::get().await?;
|
||||||
let key = Uuid::new_v4();
|
let key = LoadingBarId(Uuid::new_v4());
|
||||||
|
|
||||||
event_state.loading_bars.write().await.insert(
|
event_state.loading_bars.write().await.insert(
|
||||||
key,
|
key.0,
|
||||||
LoadingBar {
|
LoadingBar {
|
||||||
loading_bar_id: key,
|
loading_bar_uuid: key.0,
|
||||||
message: title.to_string(),
|
message: title.to_string(),
|
||||||
total,
|
total,
|
||||||
current: 0.0,
|
current: 0.0,
|
||||||
bar_type,
|
bar_type,
|
||||||
|
#[cfg(feature = "cli")]
|
||||||
|
cli_progress_bar: {
|
||||||
|
let pb = indicatif::ProgressBar::new(CLI_PROGRESS_BAR_TOTAL);
|
||||||
|
|
||||||
|
pb.set_position(0);
|
||||||
|
pb.set_style(
|
||||||
|
indicatif::ProgressStyle::default_bar()
|
||||||
|
.template(
|
||||||
|
"{spinner:.green} [{elapsed_precise}] [{bar:.lime/green}] {pos}/{len} {msg}",
|
||||||
|
).unwrap()
|
||||||
|
.progress_chars("#>-"),
|
||||||
|
);
|
||||||
|
//pb.set_message(title);
|
||||||
|
|
||||||
|
pb
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// attempt an initial loading_emit event to the frontend
|
// attempt an initial loading_emit event to the frontend
|
||||||
@ -65,13 +86,13 @@ pub async fn init_loading(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init_or_edit_loading(
|
pub async fn init_or_edit_loading(
|
||||||
id: Option<Uuid>,
|
id: Option<LoadingBarId>,
|
||||||
bar_type: LoadingBarType,
|
bar_type: LoadingBarType,
|
||||||
total: f64,
|
total: f64,
|
||||||
title: &str,
|
title: &str,
|
||||||
) -> crate::Result<Uuid> {
|
) -> crate::Result<LoadingBarId> {
|
||||||
if let Some(id) = id {
|
if let Some(id) = id {
|
||||||
edit_loading(id, bar_type, total, title).await?;
|
edit_loading(&id, bar_type, total, title).await?;
|
||||||
|
|
||||||
Ok(id)
|
Ok(id)
|
||||||
} else {
|
} else {
|
||||||
@ -80,21 +101,27 @@ pub async fn init_or_edit_loading(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Edits a loading bar's type
|
// Edits a loading bar's type
|
||||||
|
// This also resets the bar's current progress to 0
|
||||||
pub async fn edit_loading(
|
pub async fn edit_loading(
|
||||||
id: Uuid,
|
id: &LoadingBarId,
|
||||||
bar_type: LoadingBarType,
|
bar_type: LoadingBarType,
|
||||||
total: f64,
|
total: f64,
|
||||||
title: &str,
|
title: &str,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let event_state = crate::EventState::get().await?;
|
let event_state = crate::EventState::get().await?;
|
||||||
|
|
||||||
if let Some(bar) = event_state.loading_bars.write().await.get_mut(&id) {
|
if let Some(bar) = event_state.loading_bars.write().await.get_mut(&id.0) {
|
||||||
bar.bar_type = bar_type;
|
bar.bar_type = bar_type;
|
||||||
bar.total = total;
|
bar.total = total;
|
||||||
bar.message = title.to_string();
|
bar.message = title.to_string();
|
||||||
|
bar.current = 0.0;
|
||||||
|
#[cfg(feature = "cli")]
|
||||||
|
{
|
||||||
|
bar.cli_progress_bar.reset(); // indicatif::ProgressBar::new(CLI_PROGRESS_BAR_TOTAL as u64);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
emit_loading(&id, 0.0, None).await?;
|
emit_loading(id, 0.0, None).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,18 +131,19 @@ pub async fn edit_loading(
|
|||||||
// message is the message to display on the loading bar- if None, use the loading bar's default one
|
// message is the message to display on the loading bar- if None, use the loading bar's default one
|
||||||
// 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)]
|
||||||
|
#[tracing::instrument(level = "debug")]
|
||||||
pub async fn emit_loading(
|
pub async fn emit_loading(
|
||||||
key: &Uuid,
|
key: &LoadingBarId,
|
||||||
increment_frac: f64,
|
increment_frac: f64,
|
||||||
message: Option<&str>,
|
message: Option<&str>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let event_state = crate::EventState::get().await?;
|
let event_state = crate::EventState::get().await?;
|
||||||
|
|
||||||
let mut loading_bar = event_state.loading_bars.write().await;
|
let mut loading_bar = event_state.loading_bars.write().await;
|
||||||
let loading_bar = match loading_bar.get_mut(key) {
|
let loading_bar = match loading_bar.get_mut(&key.0) {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => {
|
None => {
|
||||||
return Err(EventError::NoLoadingBar(*key).into());
|
return Err(EventError::NoLoadingBar(key.0).into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -128,6 +156,22 @@ pub async fn emit_loading(
|
|||||||
} else {
|
} else {
|
||||||
Some(display_frac)
|
Some(display_frac)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Emit event to indicatif progress bar
|
||||||
|
#[cfg(feature = "cli")]
|
||||||
|
{
|
||||||
|
loading_bar.cli_progress_bar.set_message(
|
||||||
|
message
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.unwrap_or(loading_bar.message.clone()),
|
||||||
|
);
|
||||||
|
loading_bar.cli_progress_bar.set_position(
|
||||||
|
((loading_bar.current / loading_bar.total)
|
||||||
|
* CLI_PROGRESS_BAR_TOTAL as f64)
|
||||||
|
.round() as u64,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Emit event to tauri
|
// Emit event to tauri
|
||||||
#[cfg(feature = "tauri")]
|
#[cfg(feature = "tauri")]
|
||||||
event_state
|
event_state
|
||||||
@ -138,7 +182,7 @@ pub async fn emit_loading(
|
|||||||
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: loading_bar.bar_type.clone(),
|
event: loading_bar.bar_type.clone(),
|
||||||
loader_uuid: loading_bar.loading_bar_id,
|
loader_uuid: loading_bar.loading_bar_uuid,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.map_err(EventError::from)?;
|
.map_err(EventError::from)?;
|
||||||
@ -162,6 +206,7 @@ pub async fn emit_warning(message: &str) -> crate::Result<()> {
|
|||||||
)
|
)
|
||||||
.map_err(EventError::from)?;
|
.map_err(EventError::from)?;
|
||||||
}
|
}
|
||||||
|
warn!("{}", message);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +280,6 @@ macro_rules! count {
|
|||||||
() => (0usize);
|
() => (0usize);
|
||||||
( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*));
|
( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*));
|
||||||
}
|
}
|
||||||
#[cfg(feature = "tauri")]
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! loading_join {
|
macro_rules! loading_join {
|
||||||
($key:expr, $total:expr, $message:expr; $($task:expr $(,)?)+) => {
|
($key:expr, $total:expr, $message:expr; $($task:expr $(,)?)+) => {
|
||||||
@ -272,24 +316,16 @@ macro_rules! loading_join {
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "tauri"))]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! loading_join {
|
|
||||||
($start:expr, $end:expr, $message:expr; $($future:expr $(,)?)+) => {{
|
|
||||||
tokio::try_join!($($future),+)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// A drop in replacement to try_for_each_concurrent that emits loading events as it goes
|
// A drop in replacement to try_for_each_concurrent that emits loading events as it goes
|
||||||
// Key is the key to use for which loading bar- a LoadingBarId. If None, does nothing
|
// Key is the key to use for which loading bar- a LoadingBarId. If None, does nothing
|
||||||
// Total is the total amount of progress that the loading bar should take up by all futures in this (will be split evenly amongst them).
|
// Total is the total amount of progress that the loading bar should take up by all futures in this (will be split evenly amongst them).
|
||||||
// If message is Some(t) you will overwrite this loading bar's message with a custom one
|
// If message is Some(t) you will overwrite this loading bar's message with a custom one
|
||||||
// num_futs is the number of futures that will be run, which is needed as we allow Iterator to be passed in, which doesn't have a size
|
// num_futs is the number of futures that will be run, which is needed as we allow Iterator to be passed in, which doesn't have a size
|
||||||
#[cfg(feature = "tauri")]
|
|
||||||
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<&Uuid>,
|
key: Option<&LoadingBarId>,
|
||||||
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>,
|
||||||
@ -316,31 +352,3 @@ where
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "tauri"))]
|
|
||||||
pub async fn loading_try_for_each_concurrent<I, F, Fut, T>(
|
|
||||||
stream: I,
|
|
||||||
limit: Option<usize>,
|
|
||||||
_key: Option<&Uuid>,
|
|
||||||
_total: f64,
|
|
||||||
_num_futs: usize, // num is in here as we allow Iterator to be passed in, which doesn't have a size
|
|
||||||
_message: Option<&str>,
|
|
||||||
f: F,
|
|
||||||
) -> crate::Result<()>
|
|
||||||
where
|
|
||||||
I: futures::TryStreamExt<Error = crate::Error> + TryStream<Ok = T>,
|
|
||||||
F: FnMut(T) -> Fut + Send,
|
|
||||||
Fut: Future<Output = crate::Result<()>> + Send,
|
|
||||||
T: Send,
|
|
||||||
{
|
|
||||||
let mut f = f;
|
|
||||||
stream
|
|
||||||
.try_for_each_concurrent(limit, |item| {
|
|
||||||
let f = f(item);
|
|
||||||
async move {
|
|
||||||
f.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|||||||
@ -48,11 +48,18 @@ impl EventState {
|
|||||||
Ok(EVENT_STATE.get().ok_or(EventError::NotInitialized)?.clone())
|
Ok(EVENT_STATE.get().ok_or(EventError::NotInitialized)?.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Values provided should not be used directly, as they are clones and are not guaranteed to be up-to-date
|
||||||
pub async fn list_progress_bars() -> crate::Result<HashMap<Uuid, LoadingBar>>
|
pub async fn list_progress_bars() -> crate::Result<HashMap<Uuid, LoadingBar>>
|
||||||
{
|
{
|
||||||
let value = Self::get().await?;
|
let value = Self::get().await?;
|
||||||
let read = value.loading_bars.read().await;
|
let read = value.loading_bars.read().await;
|
||||||
Ok(read.clone())
|
|
||||||
|
let mut display_list: HashMap<Uuid, LoadingBar> = HashMap::new();
|
||||||
|
for (uuid, loading_bar) in read.iter() {
|
||||||
|
display_list.insert(*uuid, loading_bar.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(display_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@ -64,16 +71,84 @@ impl EventState {
|
|||||||
|
|
||||||
#[derive(Serialize, Debug, Clone)]
|
#[derive(Serialize, Debug, Clone)]
|
||||||
pub struct LoadingBar {
|
pub struct LoadingBar {
|
||||||
pub loading_bar_id: Uuid,
|
// loading_bar_uuid not be used directly by external functions as it may not reflect the current state of the loading bar/hashmap
|
||||||
|
pub loading_bar_uuid: Uuid,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub total: f64,
|
pub total: f64,
|
||||||
pub current: f64,
|
pub current: f64,
|
||||||
pub bar_type: LoadingBarType,
|
pub bar_type: LoadingBarType,
|
||||||
|
#[cfg(feature = "cli")]
|
||||||
|
#[serde(skip)]
|
||||||
|
pub cli_progress_bar: indicatif::ProgressBar,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
pub struct LoadingBarId(Uuid);
|
||||||
|
|
||||||
|
// When Loading bar id is dropped, we should remove it from the hashmap
|
||||||
|
impl Drop for LoadingBarId {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let loader_uuid = self.0;
|
||||||
|
let _event = LoadingBarType::StateInit;
|
||||||
|
let _message = "finished".to_string();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Ok(event_state) = crate::EventState::get().await {
|
||||||
|
{
|
||||||
|
let mut bars = event_state.loading_bars.write().await;
|
||||||
|
bars.remove(&loader_uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When Loading bar is dropped, should attempt to throw out one last event to indicate that the loading bar is done
|
||||||
|
#[cfg(feature = "tauri")]
|
||||||
|
impl Drop for LoadingBar {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let loader_uuid = self.loading_bar_uuid;
|
||||||
|
let event = self.bar_type.clone();
|
||||||
|
let fraction = self.current / self.total;
|
||||||
|
let cli_progress_bar = self.cli_progress_bar.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
#[cfg(feature = "tauri")]
|
||||||
|
{
|
||||||
|
use tauri::Manager;
|
||||||
|
if let Ok(event_state) = crate::EventState::get().await {
|
||||||
|
let _ = event_state.app.emit_all(
|
||||||
|
"loading",
|
||||||
|
LoadingPayload {
|
||||||
|
fraction: None,
|
||||||
|
message: "Completed".to_string(),
|
||||||
|
event,
|
||||||
|
loader_uuid,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
tracing::debug!(
|
||||||
|
"Exited at {fraction} for loading bar: {:?}",
|
||||||
|
loader_uuid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Emit event to indicatif progress bar arc
|
||||||
|
#[cfg(feature = "cli")]
|
||||||
|
{
|
||||||
|
cli_progress_bar.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum LoadingBarType {
|
pub enum LoadingBarType {
|
||||||
StateInit,
|
StateInit,
|
||||||
|
PackFileDownload {
|
||||||
|
pack_name: Option<String>,
|
||||||
|
pack_version: String,
|
||||||
|
},
|
||||||
PackDownload {
|
PackDownload {
|
||||||
pack_name: String,
|
pack_name: String,
|
||||||
pack_id: Option<String>,
|
pack_id: Option<String>,
|
||||||
@ -124,6 +199,7 @@ pub struct ProfilePayload {
|
|||||||
pub event: ProfilePayloadType,
|
pub event: ProfilePayloadType,
|
||||||
}
|
}
|
||||||
#[derive(Serialize, Clone)]
|
#[derive(Serialize, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ProfilePayloadType {
|
pub enum ProfilePayloadType {
|
||||||
Created,
|
Created,
|
||||||
Added, // also triggered when Created
|
Added, // also triggered when Created
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
//! 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, FetchSemaphore};
|
||||||
use async_tungstenite as ws;
|
use async_tungstenite as ws;
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{RwLock, Semaphore};
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -95,7 +94,7 @@ impl HydraAuthFlow<ws::tokio::ConnectStream> {
|
|||||||
|
|
||||||
pub async fn extract_credentials(
|
pub async fn extract_credentials(
|
||||||
&mut self,
|
&mut self,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<Credentials> {
|
) -> crate::Result<Credentials> {
|
||||||
// Minecraft bearer token
|
// Minecraft bearer token
|
||||||
let token_resp = self
|
let token_resp = self
|
||||||
@ -130,7 +129,7 @@ impl HydraAuthFlow<ws::tokio::ConnectStream> {
|
|||||||
|
|
||||||
pub async fn refresh_credentials(
|
pub async fn refresh_credentials(
|
||||||
credentials: &mut Credentials,
|
credentials: &mut Credentials,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let resp = fetch_json::<TokenJSON>(
|
let resp = fetch_json::<TokenJSON>(
|
||||||
Method::POST,
|
Method::POST,
|
||||||
@ -152,7 +151,7 @@ pub async fn refresh_credentials(
|
|||||||
// Helpers
|
// Helpers
|
||||||
async fn fetch_info(
|
async fn fetch_info(
|
||||||
token: &str,
|
token: &str,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<ProfileInfoJSON> {
|
) -> crate::Result<ProfileInfoJSON> {
|
||||||
let result = fetch_advanced(
|
let result = fetch_advanced(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
@ -160,6 +159,7 @@ async fn fetch_info(
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(("Authorization", &format!("Bearer {token}"))),
|
Some(("Authorization", &format!("Bearer {token}"))),
|
||||||
|
None,
|
||||||
semaphore,
|
semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
//! Downloader for Minecraft data
|
//! Downloader for Minecraft data
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
event::emit::{emit_loading, loading_try_for_each_concurrent},
|
event::{
|
||||||
|
emit::{emit_loading, loading_try_for_each_concurrent},
|
||||||
|
LoadingBarId,
|
||||||
|
},
|
||||||
state::State,
|
state::State,
|
||||||
util::{fetch::*, platform::OsExt},
|
util::{fetch::*, platform::OsExt},
|
||||||
};
|
};
|
||||||
@ -15,24 +18,26 @@ 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,
|
||||||
loading_bar: Uuid,
|
loading_bar: &LoadingBarId,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
log::info!("Downloading Minecraft version {}", version.id);
|
tracing::info!("Downloading Minecraft version {}", version.id);
|
||||||
let assets_index = download_assets_index(st, version).await?;
|
// 5
|
||||||
|
let assets_index =
|
||||||
|
download_assets_index(st, version, Some(loading_bar)).await?;
|
||||||
|
|
||||||
tokio::try_join! {
|
tokio::try_join! {
|
||||||
download_client(st, version, Some(&loading_bar)),
|
// Total loading sums to 80
|
||||||
download_assets(st, version.assets == "legacy", &assets_index, Some(&loading_bar)),
|
download_client(st, version, Some(loading_bar)), // 10
|
||||||
download_libraries(st, version.libraries.as_slice(), &version.id, Some(&loading_bar))
|
download_assets(st, version.assets == "legacy", &assets_index, Some(loading_bar)), // 35
|
||||||
|
download_libraries(st, version.libraries.as_slice(), &version.id, Some(loading_bar)) // 35
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
log::info!("Done downloading Minecraft!");
|
tracing::info!("Done downloading Minecraft!");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,10 +47,11 @@ pub async fn download_version_info(
|
|||||||
version: &GameVersion,
|
version: &GameVersion,
|
||||||
loader: Option<&LoaderVersion>,
|
loader: Option<&LoaderVersion>,
|
||||||
force: Option<bool>,
|
force: Option<bool>,
|
||||||
|
loading_bar: Option<&LoadingBarId>,
|
||||||
) -> 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));
|
||||||
log::debug!("Loading version info for Minecraft {version_id}");
|
tracing::debug!("Loading version info for Minecraft {version_id}");
|
||||||
let path = st
|
let path = st
|
||||||
.directories
|
.directories
|
||||||
.version_dir(&version_id)
|
.version_dir(&version_id)
|
||||||
@ -57,7 +63,7 @@ pub async fn download_version_info(
|
|||||||
.await
|
.await
|
||||||
.and_then(|ref it| Ok(serde_json::from_slice(it)?))
|
.and_then(|ref it| Ok(serde_json::from_slice(it)?))
|
||||||
} else {
|
} else {
|
||||||
log::info!("Downloading version info for version {}", &version.id);
|
tracing::info!("Downloading version info for version {}", &version.id);
|
||||||
let mut info = d::minecraft::fetch_version_info(version).await?;
|
let mut info = d::minecraft::fetch_version_info(version).await?;
|
||||||
|
|
||||||
if let Some(loader) = loader {
|
if let Some(loader) = loader {
|
||||||
@ -70,7 +76,25 @@ pub async fn download_version_info(
|
|||||||
Ok(info)
|
Ok(info)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
log::debug!("Loaded version info for Minecraft {version_id}");
|
if let Some(loading_bar) = loading_bar {
|
||||||
|
emit_loading(
|
||||||
|
loading_bar,
|
||||||
|
if res
|
||||||
|
.processors
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| !x.is_empty())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
5.0
|
||||||
|
} else {
|
||||||
|
15.0
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::debug!("Loaded version info for Minecraft {version_id}");
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,10 +102,10 @@ 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<&Uuid>,
|
loading_bar: Option<&LoadingBarId>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let version = &version_info.id;
|
let version = &version_info.id;
|
||||||
log::debug!("Locating client for version {version}");
|
tracing::debug!("Locating client for version {version}");
|
||||||
let client_download = version_info
|
let client_download = version_info
|
||||||
.downloads
|
.downloads
|
||||||
.get(&d::minecraft::DownloadType::Client)
|
.get(&d::minecraft::DownloadType::Client)
|
||||||
@ -100,17 +124,17 @@ pub async fn download_client(
|
|||||||
let bytes = fetch(
|
let bytes = fetch(
|
||||||
&client_download.url,
|
&client_download.url,
|
||||||
Some(&client_download.sha1),
|
Some(&client_download.sha1),
|
||||||
&st.io_semaphore,
|
&st.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
write(&path, &bytes, &st.io_semaphore).await?;
|
write(&path, &bytes, &st.io_semaphore).await?;
|
||||||
log::info!("Fetched client version {version}");
|
tracing::trace!("Fetched client version {version}");
|
||||||
}
|
}
|
||||||
if let Some(loading_bar) = loading_bar {
|
if let Some(loading_bar) = loading_bar {
|
||||||
emit_loading(loading_bar, 20.0, None).await?;
|
emit_loading(loading_bar, 10.0, None).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("Client loaded for version {version}!");
|
tracing::debug!("Client loaded for version {version}!");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +142,9 @@ pub async fn download_client(
|
|||||||
pub async fn download_assets_index(
|
pub async fn download_assets_index(
|
||||||
st: &State,
|
st: &State,
|
||||||
version: &GameVersionInfo,
|
version: &GameVersionInfo,
|
||||||
|
loading_bar: Option<&LoadingBarId>,
|
||||||
) -> crate::Result<AssetsIndex> {
|
) -> crate::Result<AssetsIndex> {
|
||||||
log::debug!("Loading assets index");
|
tracing::debug!("Loading assets index");
|
||||||
let path = st
|
let path = st
|
||||||
.directories
|
.directories
|
||||||
.assets_index_dir()
|
.assets_index_dir()
|
||||||
@ -133,11 +158,14 @@ pub async fn download_assets_index(
|
|||||||
} else {
|
} else {
|
||||||
let index = d::minecraft::fetch_assets_index(version).await?;
|
let index = d::minecraft::fetch_assets_index(version).await?;
|
||||||
write(&path, &serde_json::to_vec(&index)?, &st.io_semaphore).await?;
|
write(&path, &serde_json::to_vec(&index)?, &st.io_semaphore).await?;
|
||||||
log::info!("Fetched assets index");
|
tracing::info!("Fetched assets index");
|
||||||
Ok(index)
|
Ok(index)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
log::debug!("Assets index successfully loaded!");
|
if let Some(loading_bar) = loading_bar {
|
||||||
|
emit_loading(loading_bar, 5.0, None).await?;
|
||||||
|
}
|
||||||
|
tracing::debug!("Assets index successfully loaded!");
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,9 +174,9 @@ pub async fn download_assets(
|
|||||||
st: &State,
|
st: &State,
|
||||||
with_legacy: bool,
|
with_legacy: bool,
|
||||||
index: &AssetsIndex,
|
index: &AssetsIndex,
|
||||||
loading_bar: Option<&Uuid>,
|
loading_bar: Option<&LoadingBarId>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
log::debug!("Loading assets");
|
tracing::debug!("Loading assets");
|
||||||
let num_futs = index.objects.len();
|
let num_futs = index.objects.len();
|
||||||
let assets = stream::iter(index.objects.iter())
|
let assets = stream::iter(index.objects.iter())
|
||||||
.map(Ok::<(&String, &Asset), crate::Error>);
|
.map(Ok::<(&String, &Asset), crate::Error>);
|
||||||
@ -156,7 +184,7 @@ pub async fn download_assets(
|
|||||||
loading_try_for_each_concurrent(assets,
|
loading_try_for_each_concurrent(assets,
|
||||||
None,
|
None,
|
||||||
loading_bar,
|
loading_bar,
|
||||||
50.0,
|
35.0,
|
||||||
num_futs,
|
num_futs,
|
||||||
None,
|
None,
|
||||||
|(name, asset)| async move {
|
|(name, asset)| async move {
|
||||||
@ -172,33 +200,33 @@ pub async fn download_assets(
|
|||||||
async {
|
async {
|
||||||
if !resource_path.exists() {
|
if !resource_path.exists() {
|
||||||
let resource = fetch_cell
|
let resource = fetch_cell
|
||||||
.get_or_try_init(|| fetch(&url, Some(hash), &st.io_semaphore))
|
.get_or_try_init(|| fetch(&url, Some(hash), &st.fetch_semaphore))
|
||||||
.await?;
|
.await?;
|
||||||
write(&resource_path, resource, &st.io_semaphore).await?;
|
write(&resource_path, resource, &st.io_semaphore).await?;
|
||||||
log::info!("Fetched asset with hash {hash}");
|
tracing::trace!("Fetched asset with hash {hash}");
|
||||||
}
|
}
|
||||||
Ok::<_, crate::Error>(())
|
Ok::<_, crate::Error>(())
|
||||||
},
|
},
|
||||||
async {
|
async {
|
||||||
if with_legacy {
|
if with_legacy {
|
||||||
let resource = fetch_cell
|
let resource = fetch_cell
|
||||||
.get_or_try_init(|| fetch(&url, Some(hash), &st.io_semaphore))
|
.get_or_try_init(|| fetch(&url, Some(hash), &st.fetch_semaphore))
|
||||||
.await?;
|
.await?;
|
||||||
let resource_path = st.directories.legacy_assets_dir().join(
|
let resource_path = st.directories.legacy_assets_dir().join(
|
||||||
name.replace('/', &String::from(std::path::MAIN_SEPARATOR))
|
name.replace('/', &String::from(std::path::MAIN_SEPARATOR))
|
||||||
);
|
);
|
||||||
write(&resource_path, resource, &st.io_semaphore).await?;
|
write(&resource_path, resource, &st.io_semaphore).await?;
|
||||||
log::info!("Fetched legacy asset with hash {hash}");
|
tracing::trace!("Fetched legacy asset with hash {hash}");
|
||||||
}
|
}
|
||||||
Ok::<_, crate::Error>(())
|
Ok::<_, crate::Error>(())
|
||||||
},
|
},
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
log::debug!("Loaded asset with hash {hash}");
|
tracing::trace!("Loaded asset with hash {hash}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
log::debug!("Done loading assets!");
|
tracing::debug!("Done loading assets!");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,9 +235,9 @@ pub async fn download_libraries(
|
|||||||
st: &State,
|
st: &State,
|
||||||
libraries: &[Library],
|
libraries: &[Library],
|
||||||
version: &str,
|
version: &str,
|
||||||
loading_bar: Option<&Uuid>,
|
loading_bar: Option<&LoadingBarId>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
log::debug!("Loading libraries");
|
tracing::debug!("Loading libraries");
|
||||||
|
|
||||||
tokio::try_join! {
|
tokio::try_join! {
|
||||||
fs::create_dir_all(st.directories.libraries_dir()),
|
fs::create_dir_all(st.directories.libraries_dir()),
|
||||||
@ -218,7 +246,7 @@ pub async fn download_libraries(
|
|||||||
let num_files = libraries.len();
|
let num_files = libraries.len();
|
||||||
loading_try_for_each_concurrent(
|
loading_try_for_each_concurrent(
|
||||||
stream::iter(libraries.iter())
|
stream::iter(libraries.iter())
|
||||||
.map(Ok::<&Library, crate::Error>), None, loading_bar,50.0,num_files, None,|library| async move {
|
.map(Ok::<&Library, crate::Error>), None, loading_bar,35.0,num_files, None,|library| async move {
|
||||||
if let Some(rules) = &library.rules {
|
if let Some(rules) = &library.rules {
|
||||||
if !rules.iter().all(super::parse_rule) {
|
if !rules.iter().all(super::parse_rule) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -235,10 +263,10 @@ pub async fn download_libraries(
|
|||||||
artifact: Some(ref artifact),
|
artifact: Some(ref artifact),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let bytes = fetch(&artifact.url, Some(&artifact.sha1), &st.io_semaphore)
|
let bytes = fetch(&artifact.url, Some(&artifact.sha1), &st.fetch_semaphore)
|
||||||
.await?;
|
.await?;
|
||||||
write(&path, &bytes, &st.io_semaphore).await?;
|
write(&path, &bytes, &st.io_semaphore).await?;
|
||||||
log::info!("Fetched library {}", &library.name);
|
tracing::trace!("Fetched library {}", &library.name);
|
||||||
Ok::<_, crate::Error>(())
|
Ok::<_, crate::Error>(())
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -250,9 +278,9 @@ pub async fn download_libraries(
|
|||||||
&artifact_path
|
&artifact_path
|
||||||
].concat();
|
].concat();
|
||||||
|
|
||||||
let bytes = fetch(&url, None, &st.io_semaphore).await?;
|
let bytes = fetch(&url, None, &st.fetch_semaphore).await?;
|
||||||
write(&path, &bytes, &st.io_semaphore).await?;
|
write(&path, &bytes, &st.io_semaphore).await?;
|
||||||
log::info!("Fetched library {}", &library.name);
|
tracing::trace!("Fetched library {}", &library.name);
|
||||||
Ok::<_, crate::Error>(())
|
Ok::<_, crate::Error>(())
|
||||||
}
|
}
|
||||||
_ => Ok(())
|
_ => Ok(())
|
||||||
@ -277,15 +305,15 @@ pub async fn download_libraries(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(native) = classifiers.get(&parsed_key) {
|
if let Some(native) = classifiers.get(&parsed_key) {
|
||||||
let data = fetch(&native.url, Some(&native.sha1), &st.io_semaphore).await?;
|
let data = fetch(&native.url, Some(&native.sha1), &st.fetch_semaphore).await?;
|
||||||
let reader = std::io::Cursor::new(&data);
|
let reader = std::io::Cursor::new(&data);
|
||||||
if let Ok(mut archive) = zip::ZipArchive::new(reader) {
|
if let Ok(mut archive) = zip::ZipArchive::new(reader) {
|
||||||
match archive.extract(&st.directories.version_natives_dir(version)) {
|
match archive.extract(&st.directories.version_natives_dir(version)) {
|
||||||
Ok(_) => log::info!("Fetched native {}", &library.name),
|
Ok(_) => tracing::info!("Fetched native {}", &library.name),
|
||||||
Err(err) => log::error!("Failed extracting native {}. err: {}", &library.name, err)
|
Err(err) => tracing::error!("Failed extracting native {}. err: {}", &library.name, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::error!("Failed extracting native {}", &library.name)
|
tracing::error!("Failed extracting native {}", &library.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,11 +322,11 @@ pub async fn download_libraries(
|
|||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
log::debug!("Loaded library {}", library.name);
|
tracing::debug!("Loaded library {}", library.name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
log::debug!("Done loading libraries!");
|
tracing::debug!("Done loading libraries!");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! Logic for launching Minecraft
|
//! Logic for launching Minecraft
|
||||||
use crate::event::emit::{emit_loading, init_or_edit_loading};
|
use crate::event::emit::{emit_loading, init_or_edit_loading};
|
||||||
use crate::event::LoadingBarType;
|
use crate::event::{LoadingBarId, LoadingBarType};
|
||||||
use crate::{
|
use crate::{
|
||||||
process,
|
process,
|
||||||
state::{self as st, MinecraftChild},
|
state::{self as st, MinecraftChild},
|
||||||
@ -53,9 +53,10 @@ macro_rules! processor_rules {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(profile))]
|
||||||
pub async fn install_minecraft(
|
pub async fn install_minecraft(
|
||||||
profile: &Profile,
|
profile: &Profile,
|
||||||
existing_loading_bar: Option<Uuid>,
|
existing_loading_bar: Option<LoadingBarId>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let instance_path = &canonicalize(&profile.path)?;
|
let instance_path = &canonicalize(&profile.path)?;
|
||||||
@ -79,14 +80,6 @@ pub async fn install_minecraft(
|
|||||||
format!("{}-{}", version.id.clone(), it.id.clone())
|
format!("{}-{}", version.id.clone(), it.id.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut version_info = download::download_version_info(
|
|
||||||
&state,
|
|
||||||
version,
|
|
||||||
profile.metadata.loader_version.as_ref(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let loading_bar = init_or_edit_loading(
|
let loading_bar = init_or_edit_loading(
|
||||||
existing_loading_bar,
|
existing_loading_bar,
|
||||||
LoadingBarType::MinecraftDownload {
|
LoadingBarType::MinecraftDownload {
|
||||||
@ -95,11 +88,22 @@ pub async fn install_minecraft(
|
|||||||
profile_uuid: profile.uuid,
|
profile_uuid: profile.uuid,
|
||||||
},
|
},
|
||||||
100.0,
|
100.0,
|
||||||
"Downloading Minecraft...",
|
"Downloading Minecraft",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
download::download_minecraft(&state, &version_info, loading_bar).await?;
|
// Download version info
|
||||||
|
let mut version_info = download::download_version_info(
|
||||||
|
&state,
|
||||||
|
version,
|
||||||
|
profile.metadata.loader_version.as_ref(),
|
||||||
|
None,
|
||||||
|
Some(&loading_bar),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Download minecraft (5-90)
|
||||||
|
download::download_minecraft(&state, &version_info, &loading_bar).await?;
|
||||||
|
|
||||||
let client_path = state
|
let client_path = state
|
||||||
.directories
|
.directories
|
||||||
@ -131,10 +135,11 @@ pub async fn install_minecraft(
|
|||||||
.await?;
|
.await?;
|
||||||
let total_length = processors.len();
|
let total_length = processors.len();
|
||||||
|
|
||||||
|
// Forge processors (90-100)
|
||||||
for (index, processor) in processors.iter().enumerate() {
|
for (index, processor) in processors.iter().enumerate() {
|
||||||
emit_loading(
|
emit_loading(
|
||||||
&loading_bar,
|
&loading_bar,
|
||||||
index as f64 / total_length as f64,
|
10.0 / total_length as f64,
|
||||||
Some(&format!(
|
Some(&format!(
|
||||||
"Running forge processor {}/{}",
|
"Running forge processor {}/{}",
|
||||||
index, total_length
|
index, total_length
|
||||||
@ -223,7 +228,7 @@ pub async fn launch_minecraft(
|
|||||||
install_minecraft(profile, None).await?;
|
install_minecraft(profile, None).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = st::State::get().await?;
|
let state = State::get().await?;
|
||||||
let metadata = state.metadata.read().await;
|
let metadata = state.metadata.read().await;
|
||||||
let instance_path = &canonicalize(&profile.path)?;
|
let instance_path = &canonicalize(&profile.path)?;
|
||||||
|
|
||||||
@ -250,6 +255,7 @@ pub async fn launch_minecraft(
|
|||||||
version,
|
version,
|
||||||
profile.metadata.loader_version.as_ref(),
|
profile.metadata.loader_version.as_ref(),
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -320,8 +326,12 @@ pub async fn launch_minecraft(
|
|||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped());
|
.stderr(Stdio::piped());
|
||||||
|
|
||||||
// Clear cargo-added env varaibles for debugging, and add settings env vars
|
// CARGO-set DYLD_LIBRARY_PATH breaks Minecraft on macOS during testing on playground
|
||||||
clear_cargo_env_vals(&mut command).envs(env_args);
|
#[cfg(target_os = "macos")]
|
||||||
|
if std::env::var("CARGO").is_ok() {
|
||||||
|
command.env_remove("DYLD_FALLBACK_LIBRARY_PATH");
|
||||||
|
}
|
||||||
|
command.envs(env_args);
|
||||||
|
|
||||||
// Get Modrinth logs directories
|
// Get Modrinth logs directories
|
||||||
let datetime_string =
|
let datetime_string =
|
||||||
@ -351,14 +361,3 @@ pub async fn launch_minecraft(
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_cargo_env_vals(command: &mut Command) -> &mut Command {
|
|
||||||
for (key, _) in std::env::vars() {
|
|
||||||
command.env_remove(key);
|
|
||||||
|
|
||||||
// if key.starts_with("CARGO") {
|
|
||||||
// command.env_remove(key);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
command
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use tokio::process::Child;
|
|||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::process::{ChildStderr, ChildStdout};
|
use tokio::process::{ChildStderr, ChildStdout};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
use crate::event::emit::emit_process;
|
use crate::event::emit::emit_process;
|
||||||
use crate::event::ProcessPayloadType;
|
use crate::event::ProcessPayloadType;
|
||||||
@ -55,7 +56,7 @@ impl Children {
|
|||||||
let stdout_clone = stdout.clone();
|
let stdout_clone = stdout.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = stdout_clone.read_stdout(child_stdout).await {
|
if let Err(e) = stdout_clone.read_stdout(child_stdout).await {
|
||||||
eprintln!("Stdout process died with error: {}", e);
|
error!("Stdout process died with error: {}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -64,7 +65,7 @@ impl Children {
|
|||||||
let stderr_clone = stderr.clone();
|
let stderr_clone = stderr.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = stderr_clone.read_stderr(child_stderr).await {
|
if let Err(e) = stderr_clone.read_stderr(child_stderr).await {
|
||||||
eprintln!("Stderr process died with error: {}", e);
|
error!("Stderr process died with error: {}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! Theseus metadata
|
//! Theseus metadata
|
||||||
use crate::data::DirectoryInfo;
|
use crate::data::DirectoryInfo;
|
||||||
use crate::util::fetch::{read_json, write};
|
use crate::util::fetch::{read_json, write, IoSemaphore};
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use daedalus::{
|
use daedalus::{
|
||||||
minecraft::{fetch_version_manifest, VersionManifest as MinecraftManifest},
|
minecraft::{fetch_version_manifest, VersionManifest as MinecraftManifest},
|
||||||
@ -9,7 +9,6 @@ use daedalus::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{RwLock, Semaphore};
|
|
||||||
|
|
||||||
const METADATA_URL: &str = "https://meta.modrinth.com";
|
const METADATA_URL: &str = "https://meta.modrinth.com";
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ impl Metadata {
|
|||||||
// Attempt to fetch metadata and store in sled DB
|
// Attempt to fetch metadata and store in sled DB
|
||||||
pub async fn init(
|
pub async fn init(
|
||||||
dirs: &DirectoryInfo,
|
dirs: &DirectoryInfo,
|
||||||
io_semaphore: &RwLock<Semaphore>,
|
io_semaphore: &IoSemaphore,
|
||||||
) -> crate::Result<Self> {
|
) -> crate::Result<Self> {
|
||||||
let mut metadata = None;
|
let mut metadata = None;
|
||||||
let metadata_path = dirs.caches_meta_dir().join("metadata.json");
|
let metadata_path = dirs.caches_meta_dir().join("metadata.json");
|
||||||
@ -79,7 +78,7 @@ impl Metadata {
|
|||||||
match res {
|
match res {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Unable to fetch launcher metadata: {err}")
|
tracing::warn!("Unable to fetch launcher metadata: {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +119,7 @@ impl Metadata {
|
|||||||
match res {
|
match res {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Unable to update launcher metadata: {err}")
|
tracing::warn!("Unable to update launcher metadata: {err}")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use crate::event::LoadingBarType;
|
|||||||
use crate::loading_join;
|
use crate::loading_join;
|
||||||
|
|
||||||
use crate::state::users::Users;
|
use crate::state::users::Users;
|
||||||
|
use crate::util::fetch::{FetchSemaphore, IoSemaphore};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{OnceCell, RwLock, Semaphore};
|
use tokio::sync::{OnceCell, RwLock, Semaphore};
|
||||||
|
|
||||||
@ -44,10 +45,16 @@ static LAUNCHER_STATE: OnceCell<Arc<State>> = OnceCell::const_new();
|
|||||||
pub struct State {
|
pub struct State {
|
||||||
/// Information on the location of files used in the launcher
|
/// Information on the location of files used in the launcher
|
||||||
pub directories: DirectoryInfo,
|
pub directories: DirectoryInfo,
|
||||||
|
|
||||||
|
/// Semaphore used to limit concurrent network requests and avoid errors
|
||||||
|
pub fetch_semaphore: FetchSemaphore,
|
||||||
|
/// Stored maximum number of sempahores of current fetch_semaphore
|
||||||
|
pub fetch_semaphore_max: RwLock<u32>,
|
||||||
/// Semaphore used to limit concurrent I/O and avoid errors
|
/// Semaphore used to limit concurrent I/O and avoid errors
|
||||||
pub io_semaphore: RwLock<Semaphore>,
|
pub io_semaphore: IoSemaphore,
|
||||||
/// 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: RwLock<Metadata>,
|
pub metadata: RwLock<Metadata>,
|
||||||
/// Launcher configuration
|
/// Launcher configuration
|
||||||
@ -73,7 +80,7 @@ impl State {
|
|||||||
let loading_bar = init_loading(
|
let loading_bar = init_loading(
|
||||||
LoadingBarType::StateInit,
|
LoadingBarType::StateInit,
|
||||||
100.0,
|
100.0,
|
||||||
"Initializing launcher...",
|
"Initializing launcher",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -83,20 +90,26 @@ impl State {
|
|||||||
// Settings
|
// Settings
|
||||||
let settings =
|
let settings =
|
||||||
Settings::init(&directories.settings_file()).await?;
|
Settings::init(&directories.settings_file()).await?;
|
||||||
let io_semaphore = RwLock::new(Semaphore::new(
|
let fetch_semaphore = FetchSemaphore(RwLock::new(
|
||||||
settings.max_concurrent_downloads,
|
Semaphore::new(settings.max_concurrent_downloads),
|
||||||
|
));
|
||||||
|
let io_semaphore = IoSemaphore(RwLock::new(
|
||||||
|
Semaphore::new(settings.max_concurrent_writes),
|
||||||
));
|
));
|
||||||
emit_loading(&loading_bar, 10.0, None).await?;
|
emit_loading(&loading_bar, 10.0, None).await?;
|
||||||
|
|
||||||
let metadata_fut =
|
let metadata_fut =
|
||||||
Metadata::init(&directories, &io_semaphore);
|
Metadata::init(&directories, &io_semaphore);
|
||||||
let profiles_fut =
|
let profiles_fut = Profiles::init(&directories);
|
||||||
Profiles::init(&directories, &io_semaphore);
|
let tags_fut = Tags::init(
|
||||||
let tags_fut = Tags::init(&directories, &io_semaphore);
|
&directories,
|
||||||
|
&io_semaphore,
|
||||||
|
&fetch_semaphore,
|
||||||
|
);
|
||||||
let users_fut = Users::init(&directories, &io_semaphore);
|
let users_fut = Users::init(&directories, &io_semaphore);
|
||||||
// Launcher data
|
// Launcher data
|
||||||
let (metadata, profiles, tags, users) = loading_join! {
|
let (metadata, profiles, tags, users) = loading_join! {
|
||||||
Some(&loading_bar), 70.0, Some("Initializing...");
|
Some(&loading_bar), 70.0, Some("Loading metadata");
|
||||||
metadata_fut,
|
metadata_fut,
|
||||||
profiles_fut,
|
profiles_fut,
|
||||||
tags_fut,
|
tags_fut,
|
||||||
@ -109,9 +122,13 @@ impl State {
|
|||||||
|
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
directories,
|
directories,
|
||||||
|
fetch_semaphore,
|
||||||
|
fetch_semaphore_max: RwLock::new(
|
||||||
|
settings.max_concurrent_downloads as u32,
|
||||||
|
),
|
||||||
io_semaphore,
|
io_semaphore,
|
||||||
io_semaphore_max: RwLock::new(
|
io_semaphore_max: RwLock::new(
|
||||||
settings.max_concurrent_downloads as u32,
|
settings.max_concurrent_writes as u32,
|
||||||
),
|
),
|
||||||
metadata: RwLock::new(metadata),
|
metadata: RwLock::new(metadata),
|
||||||
settings: RwLock::new(settings),
|
settings: RwLock::new(settings),
|
||||||
@ -169,17 +186,34 @@ impl State {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset semaphores to default values
|
/// Reset IO semaphore to default values
|
||||||
/// This will block until all uses of the semaphore are complete, so it should only be called
|
/// This will block until all uses of the semaphore are complete, so it should only be called
|
||||||
/// when we are not in the middle of downloading something (ie: changing the settings!)
|
/// when we are not in the middle of downloading something (ie: changing the settings!)
|
||||||
pub async fn reset_semaphore(&self) {
|
pub async fn reset_io_semaphore(&self) {
|
||||||
let settings = self.settings.read().await;
|
let settings = self.settings.read().await;
|
||||||
let mut io_semaphore = self.io_semaphore.write().await;
|
let mut io_semaphore = self.io_semaphore.0.write().await;
|
||||||
let mut total_permits = self.io_semaphore_max.write().await;
|
let mut total_permits = self.io_semaphore_max.write().await;
|
||||||
|
|
||||||
// Wait to get all permits back
|
// Wait to get all permits back
|
||||||
let _ = io_semaphore.acquire_many(*total_permits).await;
|
let _ = io_semaphore.acquire_many(*total_permits).await;
|
||||||
|
|
||||||
|
// Reset the semaphore
|
||||||
|
io_semaphore.close();
|
||||||
|
*total_permits = settings.max_concurrent_writes as u32;
|
||||||
|
*io_semaphore = Semaphore::new(settings.max_concurrent_writes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset IO semaphore to default values
|
||||||
|
/// This will block until all uses of the semaphore are complete, so it should only be called
|
||||||
|
/// when we are not in the middle of downloading something (ie: changing the settings!)
|
||||||
|
pub async fn reset_fetch_semaphore(&self) {
|
||||||
|
let settings = self.settings.read().await;
|
||||||
|
let mut io_semaphore = self.fetch_semaphore.0.write().await;
|
||||||
|
let mut total_permits = self.fetch_semaphore_max.write().await;
|
||||||
|
|
||||||
|
// Wait to get all permits back
|
||||||
|
let _ = io_semaphore.acquire_many(*total_permits).await;
|
||||||
|
|
||||||
// Reset the semaphore
|
// Reset the semaphore
|
||||||
io_semaphore.close();
|
io_semaphore.close();
|
||||||
*total_permits = settings.max_concurrent_downloads as u32;
|
*total_permits = settings.max_concurrent_downloads as u32;
|
||||||
|
|||||||
@ -5,7 +5,9 @@ use crate::event::emit::emit_profile;
|
|||||||
use crate::event::ProfilePayloadType;
|
use crate::event::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, IoSemaphore,
|
||||||
|
};
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use daedalus::modded::LoaderVersion;
|
use daedalus::modded::LoaderVersion;
|
||||||
use dunce::canonicalize;
|
use dunce::canonicalize;
|
||||||
@ -17,8 +19,7 @@ use std::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use tokio::sync::Semaphore;
|
use tokio::fs;
|
||||||
use tokio::{fs, sync::RwLock};
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const PROFILE_JSON_PATH: &str = "profile.json";
|
const PROFILE_JSON_PATH: &str = "profile.json";
|
||||||
@ -149,7 +150,7 @@ impl Profile {
|
|||||||
pub async fn set_icon<'a>(
|
pub async fn set_icon<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
cache_dir: &Path,
|
cache_dir: &Path,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &IoSemaphore,
|
||||||
icon: bytes::Bytes,
|
icon: bytes::Bytes,
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
) -> crate::Result<&'a mut Self> {
|
) -> crate::Result<&'a mut Self> {
|
||||||
@ -168,6 +169,7 @@ impl Profile {
|
|||||||
paths,
|
paths,
|
||||||
state.directories.caches_dir(),
|
state.directories.caches_dir(),
|
||||||
&state.io_semaphore,
|
&state.io_semaphore,
|
||||||
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -218,7 +220,7 @@ impl Profile {
|
|||||||
&format!("{MODRINTH_API_URL}version/{version_id}"),
|
&format!("{MODRINTH_API_URL}version/{version_id}"),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&state.io_semaphore,
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -237,7 +239,7 @@ impl Profile {
|
|||||||
let bytes = fetch(
|
let bytes = fetch(
|
||||||
&file.url,
|
&file.url,
|
||||||
file.hashes.get("sha1").map(|x| &**x),
|
file.hashes.get("sha1").map(|x| &**x),
|
||||||
&state.io_semaphore,
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -345,10 +347,7 @@ impl Profile {
|
|||||||
|
|
||||||
impl Profiles {
|
impl Profiles {
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn init(
|
pub async fn init(dirs: &DirectoryInfo) -> crate::Result<Self> {
|
||||||
dirs: &DirectoryInfo,
|
|
||||||
io_sempahore: &RwLock<Semaphore>,
|
|
||||||
) -> crate::Result<Self> {
|
|
||||||
let mut profiles = HashMap::new();
|
let mut profiles = HashMap::new();
|
||||||
fs::create_dir_all(dirs.profiles_dir()).await?;
|
fs::create_dir_all(dirs.profiles_dir()).await?;
|
||||||
let mut entries = fs::read_dir(dirs.profiles_dir()).await?;
|
let mut entries = fs::read_dir(dirs.profiles_dir()).await?;
|
||||||
@ -358,7 +357,9 @@ impl Profiles {
|
|||||||
let prof = match Self::read_profile_from_dir(&path).await {
|
let prof = match Self::read_profile_from_dir(&path).await {
|
||||||
Ok(prof) => Some(prof),
|
Ok(prof) => Some(prof),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Error loading profile: {err}. Skipping...");
|
tracing::warn!(
|
||||||
|
"Error loading profile: {err}. Skipping..."
|
||||||
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -395,6 +396,7 @@ impl Profiles {
|
|||||||
files,
|
files,
|
||||||
state.directories.caches_dir(),
|
state.directories.caches_dir(),
|
||||||
&state.io_semaphore,
|
&state.io_semaphore,
|
||||||
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -417,7 +419,7 @@ impl Profiles {
|
|||||||
match res {
|
match res {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Unable to fetch profile projects: {err}")
|
tracing::warn!("Unable to fetch profile projects: {err}")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
use crate::config::MODRINTH_API_URL;
|
use crate::config::MODRINTH_API_URL;
|
||||||
use crate::state::Profile;
|
use crate::state::Profile;
|
||||||
use crate::util::fetch::{fetch_json, write_cached_icon};
|
use crate::util::fetch::{
|
||||||
|
fetch_json, write_cached_icon, FetchSemaphore, IoSemaphore,
|
||||||
|
};
|
||||||
use async_zip::tokio::read::fs::ZipFileReader;
|
use async_zip::tokio::read::fs::ZipFileReader;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
@ -12,7 +14,6 @@ use sha2::Digest;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
use tokio::sync::{RwLock, Semaphore};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
@ -203,7 +204,7 @@ async fn read_icon_from_file(
|
|||||||
icon_path: Option<String>,
|
icon_path: Option<String>,
|
||||||
cache_dir: &Path,
|
cache_dir: &Path,
|
||||||
path: &PathBuf,
|
path: &PathBuf,
|
||||||
io_semaphore: &RwLock<Semaphore>,
|
io_semaphore: &IoSemaphore,
|
||||||
) -> crate::Result<Option<PathBuf>> {
|
) -> crate::Result<Option<PathBuf>> {
|
||||||
if let Some(icon_path) = icon_path {
|
if let Some(icon_path) = icon_path {
|
||||||
// we have to repoen the zip twice here :(
|
// we have to repoen the zip twice here :(
|
||||||
@ -252,7 +253,8 @@ pub async fn infer_data_from_files(
|
|||||||
profile: Profile,
|
profile: Profile,
|
||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
cache_dir: PathBuf,
|
cache_dir: PathBuf,
|
||||||
io_semaphore: &RwLock<Semaphore>,
|
io_semaphore: &IoSemaphore,
|
||||||
|
fetch_semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<HashMap<PathBuf, Project>> {
|
) -> crate::Result<HashMap<PathBuf, Project>> {
|
||||||
let mut file_path_hashes = HashMap::new();
|
let mut file_path_hashes = HashMap::new();
|
||||||
|
|
||||||
@ -278,7 +280,7 @@ pub async fn infer_data_from_files(
|
|||||||
"hashes": file_path_hashes.keys().collect::<Vec<_>>(),
|
"hashes": file_path_hashes.keys().collect::<Vec<_>>(),
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
})),
|
})),
|
||||||
io_semaphore,
|
fetch_semaphore,
|
||||||
),
|
),
|
||||||
fetch_json::<HashMap<String, ModrinthVersion>>(
|
fetch_json::<HashMap<String, ModrinthVersion>>(
|
||||||
Method::POST,
|
Method::POST,
|
||||||
@ -290,7 +292,7 @@ pub async fn infer_data_from_files(
|
|||||||
"loaders": [profile.metadata.loader],
|
"loaders": [profile.metadata.loader],
|
||||||
"game_versions": [profile.metadata.game_version]
|
"game_versions": [profile.metadata.game_version]
|
||||||
})),
|
})),
|
||||||
io_semaphore,
|
fetch_semaphore,
|
||||||
)
|
)
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -308,7 +310,7 @@ pub async fn infer_data_from_files(
|
|||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
io_semaphore,
|
fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -325,7 +327,7 @@ pub async fn infer_data_from_files(
|
|||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
io_semaphore,
|
fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@ -23,6 +23,7 @@ pub struct Settings {
|
|||||||
pub default_user: Option<uuid::Uuid>,
|
pub default_user: Option<uuid::Uuid>,
|
||||||
pub hooks: Hooks,
|
pub hooks: Hooks,
|
||||||
pub max_concurrent_downloads: usize,
|
pub max_concurrent_downloads: usize,
|
||||||
|
pub max_concurrent_writes: usize,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub collapsed_navigation: bool,
|
pub collapsed_navigation: bool,
|
||||||
}
|
}
|
||||||
@ -39,6 +40,7 @@ impl Default for Settings {
|
|||||||
default_user: None,
|
default_user: None,
|
||||||
hooks: Hooks::default(),
|
hooks: Hooks::default(),
|
||||||
max_concurrent_downloads: 64,
|
max_concurrent_downloads: 64,
|
||||||
|
max_concurrent_writes: 100,
|
||||||
version: CURRENT_FORMAT_VERSION,
|
version: CURRENT_FORMAT_VERSION,
|
||||||
collapsed_navigation: false,
|
collapsed_navigation: false,
|
||||||
}
|
}
|
||||||
@ -84,7 +86,7 @@ impl Settings {
|
|||||||
match res {
|
match res {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Unable to update launcher java: {err}")
|
tracing::warn!("Unable to update launcher java: {err}")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,12 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{RwLock, Semaphore};
|
|
||||||
|
|
||||||
use crate::config::MODRINTH_API_URL;
|
use crate::config::MODRINTH_API_URL;
|
||||||
use crate::data::DirectoryInfo;
|
use crate::data::DirectoryInfo;
|
||||||
use crate::util::fetch::{fetch_json, read_json, write};
|
use crate::util::fetch::{
|
||||||
|
fetch_json, read_json, write, FetchSemaphore, IoSemaphore,
|
||||||
|
};
|
||||||
|
|
||||||
// Serializeable struct for all tags to be fetched together by the frontend
|
// Serializeable struct for all tags to be fetched together by the frontend
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -21,7 +22,8 @@ pub struct Tags {
|
|||||||
impl Tags {
|
impl Tags {
|
||||||
pub async fn init(
|
pub async fn init(
|
||||||
dirs: &DirectoryInfo,
|
dirs: &DirectoryInfo,
|
||||||
io_semaphore: &RwLock<Semaphore>,
|
io_semaphore: &IoSemaphore,
|
||||||
|
fetch_sempahore: &FetchSemaphore,
|
||||||
) -> crate::Result<Self> {
|
) -> crate::Result<Self> {
|
||||||
let mut tags = None;
|
let mut tags = None;
|
||||||
let tags_path = dirs.caches_meta_dir().join("tags.json");
|
let tags_path = dirs.caches_meta_dir().join("tags.json");
|
||||||
@ -30,10 +32,10 @@ impl Tags {
|
|||||||
{
|
{
|
||||||
tags = Some(tags_json);
|
tags = Some(tags_json);
|
||||||
} else {
|
} else {
|
||||||
match Self::fetch(io_semaphore).await {
|
match Self::fetch(fetch_sempahore).await {
|
||||||
Ok(tags_fetch) => tags = Some(tags_fetch),
|
Ok(tags_fetch) => tags = Some(tags_fetch),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Unable to fetch launcher tags: {err}")
|
tracing::warn!("Unable to fetch launcher tags: {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,7 +53,7 @@ impl Tags {
|
|||||||
pub async fn update() {
|
pub async fn update() {
|
||||||
let res = async {
|
let res = async {
|
||||||
let state = crate::State::get().await?;
|
let state = crate::State::get().await?;
|
||||||
let tags_fetch = Tags::fetch(&state.io_semaphore).await?;
|
let tags_fetch = Tags::fetch(&state.fetch_semaphore).await?;
|
||||||
|
|
||||||
let tags_path =
|
let tags_path =
|
||||||
state.directories.caches_meta_dir().join("tags.json");
|
state.directories.caches_meta_dir().join("tags.json");
|
||||||
@ -74,7 +76,7 @@ impl Tags {
|
|||||||
match res {
|
match res {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Unable to update launcher tags: {err}")
|
tracing::warn!("Unable to update launcher tags: {err}")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -116,7 +118,7 @@ impl Tags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
pub async fn fetch(semaphore: &RwLock<Semaphore>) -> crate::Result<Self> {
|
pub async fn fetch(semaphore: &FetchSemaphore) -> crate::Result<Self> {
|
||||||
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");
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
//! User login info
|
//! User login info
|
||||||
use crate::auth::Credentials;
|
use crate::auth::Credentials;
|
||||||
use crate::data::DirectoryInfo;
|
use crate::data::DirectoryInfo;
|
||||||
use crate::util::fetch::{read_json, write};
|
use crate::util::fetch::{read_json, write, IoSemaphore};
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tokio::sync::{RwLock, Semaphore};
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const USERS_JSON: &str = "users.json";
|
const USERS_JSON: &str = "users.json";
|
||||||
@ -16,7 +15,7 @@ pub(crate) struct Users(pub(crate) HashMap<Uuid, Credentials>);
|
|||||||
impl Users {
|
impl Users {
|
||||||
pub async fn init(
|
pub async fn init(
|
||||||
dirs: &DirectoryInfo,
|
dirs: &DirectoryInfo,
|
||||||
io_semaphore: &RwLock<Semaphore>,
|
io_semaphore: &IoSemaphore,
|
||||||
) -> crate::Result<Self> {
|
) -> crate::Result<Self> {
|
||||||
let users_path = dirs.caches_meta_dir().join(USERS_JSON);
|
let users_path = dirs.caches_meta_dir().join(USERS_JSON);
|
||||||
let users = read_json(&users_path, io_semaphore).await.ok();
|
let users = read_json(&users_path, io_semaphore).await.ok();
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
//! Functions for fetching infromation from the Internet
|
//! Functions for fetching infromation from the Internet
|
||||||
|
use crate::event::emit::emit_loading;
|
||||||
|
use crate::event::LoadingBarId;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
@ -12,6 +14,11 @@ use tokio::{
|
|||||||
io::AsyncWriteExt,
|
io::AsyncWriteExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IoSemaphore(pub RwLock<Semaphore>);
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FetchSemaphore(pub RwLock<Semaphore>);
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref REQWEST_CLIENT: reqwest::Client = {
|
static ref REQWEST_CLIENT: reqwest::Client = {
|
||||||
let mut headers = reqwest::header::HeaderMap::new();
|
let mut headers = reqwest::header::HeaderMap::new();
|
||||||
@ -34,9 +41,9 @@ const FETCH_ATTEMPTS: usize = 3;
|
|||||||
pub async fn fetch(
|
pub async fn fetch(
|
||||||
url: &str,
|
url: &str,
|
||||||
sha1: Option<&str>,
|
sha1: Option<&str>,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<Bytes> {
|
) -> crate::Result<Bytes> {
|
||||||
fetch_advanced(Method::GET, url, sha1, None, None, semaphore).await
|
fetch_advanced(Method::GET, url, sha1, None, None, None, semaphore).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(json_body, semaphore))]
|
#[tracing::instrument(skip(json_body, semaphore))]
|
||||||
@ -45,13 +52,14 @@ pub async fn fetch_json<T>(
|
|||||||
url: &str,
|
url: &str,
|
||||||
sha1: Option<&str>,
|
sha1: Option<&str>,
|
||||||
json_body: Option<serde_json::Value>,
|
json_body: Option<serde_json::Value>,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<T>
|
) -> crate::Result<T>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let result =
|
let result =
|
||||||
fetch_advanced(method, url, sha1, json_body, None, semaphore).await?;
|
fetch_advanced(method, url, sha1, json_body, None, None, semaphore)
|
||||||
|
.await?;
|
||||||
let value = serde_json::from_slice(&result)?;
|
let value = serde_json::from_slice(&result)?;
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
@ -64,9 +72,10 @@ pub async fn fetch_advanced(
|
|||||||
sha1: Option<&str>,
|
sha1: Option<&str>,
|
||||||
json_body: Option<serde_json::Value>,
|
json_body: Option<serde_json::Value>,
|
||||||
header: Option<(&str, &str)>,
|
header: Option<(&str, &str)>,
|
||||||
semaphore: &RwLock<Semaphore>,
|
loading_bar: Option<(&LoadingBarId, f64)>,
|
||||||
|
semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<Bytes> {
|
) -> crate::Result<Bytes> {
|
||||||
let io_semaphore = semaphore.read().await;
|
let io_semaphore = semaphore.0.read().await;
|
||||||
let _permit = io_semaphore.acquire().await?;
|
let _permit = io_semaphore.acquire().await?;
|
||||||
|
|
||||||
for attempt in 1..=(FETCH_ATTEMPTS + 1) {
|
for attempt in 1..=(FETCH_ATTEMPTS + 1) {
|
||||||
@ -83,7 +92,35 @@ pub async fn fetch_advanced(
|
|||||||
let result = req.send().await;
|
let result = req.send().await;
|
||||||
match result {
|
match result {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
let bytes = x.bytes().await;
|
let bytes = if let Some((bar, total)) = &loading_bar {
|
||||||
|
let length = x.content_length();
|
||||||
|
if let Some(total_size) = length {
|
||||||
|
use futures::StreamExt;
|
||||||
|
let mut stream = x.bytes_stream();
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
while let Some(item) = stream.next().await {
|
||||||
|
let chunk = item.or(Err(
|
||||||
|
crate::error::ErrorKind::NoValueFor(
|
||||||
|
"fetch bytes".to_string(),
|
||||||
|
),
|
||||||
|
))?;
|
||||||
|
bytes.append(&mut chunk.to_vec());
|
||||||
|
emit_loading(
|
||||||
|
bar,
|
||||||
|
(chunk.len() as f64 / total_size as f64)
|
||||||
|
* total,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(bytes::Bytes::from(bytes))
|
||||||
|
} else {
|
||||||
|
x.bytes().await
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x.bytes().await
|
||||||
|
};
|
||||||
|
|
||||||
if let Ok(bytes) = bytes {
|
if let Ok(bytes) = bytes {
|
||||||
if let Some(sha1) = sha1 {
|
if let Some(sha1) = sha1 {
|
||||||
@ -101,7 +138,7 @@ pub async fn fetch_advanced(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("Done downloading URL {url}");
|
tracing::trace!("Done downloading URL {url}");
|
||||||
return Ok(bytes);
|
return Ok(bytes);
|
||||||
} else if attempt <= 3 {
|
} else if attempt <= 3 {
|
||||||
continue;
|
continue;
|
||||||
@ -124,7 +161,7 @@ pub async fn fetch_advanced(
|
|||||||
pub async fn fetch_mirrors(
|
pub async fn fetch_mirrors(
|
||||||
mirrors: &[&str],
|
mirrors: &[&str],
|
||||||
sha1: Option<&str>,
|
sha1: Option<&str>,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &FetchSemaphore,
|
||||||
) -> crate::Result<Bytes> {
|
) -> crate::Result<Bytes> {
|
||||||
if mirrors.is_empty() {
|
if mirrors.is_empty() {
|
||||||
return Err(crate::ErrorKind::InputError(
|
return Err(crate::ErrorKind::InputError(
|
||||||
@ -146,12 +183,12 @@ pub async fn fetch_mirrors(
|
|||||||
|
|
||||||
pub async fn read_json<T>(
|
pub async fn read_json<T>(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &IoSemaphore,
|
||||||
) -> crate::Result<T>
|
) -> crate::Result<T>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let io_semaphore = semaphore.read().await;
|
let io_semaphore = semaphore.0.read().await;
|
||||||
let _permit = io_semaphore.acquire().await?;
|
let _permit = io_semaphore.acquire().await?;
|
||||||
|
|
||||||
let json = fs::read(path).await?;
|
let json = fs::read(path).await?;
|
||||||
@ -164,9 +201,9 @@ where
|
|||||||
pub async fn write<'a>(
|
pub async fn write<'a>(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &IoSemaphore,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let io_semaphore = semaphore.read().await;
|
let io_semaphore = semaphore.0.read().await;
|
||||||
let _permit = io_semaphore.acquire().await?;
|
let _permit = io_semaphore.acquire().await?;
|
||||||
|
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
@ -175,7 +212,7 @@ pub async fn write<'a>(
|
|||||||
|
|
||||||
let mut file = File::create(path).await?;
|
let mut file = File::create(path).await?;
|
||||||
file.write_all(bytes).await?;
|
file.write_all(bytes).await?;
|
||||||
log::debug!("Done writing file {}", path.display());
|
tracing::trace!("Done writing file {}", path.display());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +221,7 @@ pub async fn write_cached_icon(
|
|||||||
icon_path: &str,
|
icon_path: &str,
|
||||||
cache_dir: &Path,
|
cache_dir: &Path,
|
||||||
bytes: Bytes,
|
bytes: Bytes,
|
||||||
semaphore: &RwLock<Semaphore>,
|
semaphore: &IoSemaphore,
|
||||||
) -> crate::Result<PathBuf> {
|
) -> crate::Result<PathBuf> {
|
||||||
let extension = Path::new(&icon_path).extension().and_then(OsStr::to_str);
|
let extension = Path::new(&icon_path).extension().and_then(OsStr::to_str);
|
||||||
let hash = sha1_async(bytes.clone()).await?;
|
let hash = sha1_async(bytes.clone()).await?;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
theseus = { path = "../theseus" }
|
theseus = { path = "../theseus", features = ["cli"] }
|
||||||
daedalus = {version = "0.1.15", features = ["bincode"]}
|
daedalus = {version = "0.1.15", features = ["bincode"]}
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tokio-stream = { version = "0.1", features = ["fs"] }
|
tokio-stream = { version = "0.1", features = ["fs"] }
|
||||||
|
|||||||
@ -15,7 +15,7 @@ tauri-build = { version = "1.2", features = [] }
|
|||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
theseus = { path = "../../theseus", features = ["tauri"] }
|
theseus = { path = "../../theseus", features = ["tauri", "cli"] }
|
||||||
|
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
@ -30,6 +30,10 @@ url = "2.2"
|
|||||||
uuid = { version = "1.1", features = ["serde", "v4"] }
|
uuid = { version = "1.1", features = ["serde", "v4"] }
|
||||||
os_info = "3.7.0"
|
os_info = "3.7.0"
|
||||||
|
|
||||||
|
tracing = "0.1.37"
|
||||||
|
tracing-subscriber = "0.2"
|
||||||
|
tracing-error = "0.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||||
|
|||||||
@ -47,6 +47,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lists active progress bars
|
// Lists active progress bars
|
||||||
|
// Create a new HashMap with the same keys
|
||||||
|
// Values provided should not be used directly, as they are not guaranteed to be up-to-date
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn progress_bars_list(
|
pub async fn progress_bars_list(
|
||||||
) -> Result<std::collections::HashMap<uuid::Uuid, theseus::LoadingBar>> {
|
) -> Result<std::collections::HashMap<uuid::Uuid, theseus::LoadingBar>> {
|
||||||
@ -64,6 +66,16 @@ macro_rules! impl_serialize {
|
|||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
|
// For the Theseus variant, we add a special display for the error,
|
||||||
|
// to view the spans if subscribed to them (which is information that is lost when serializing)
|
||||||
|
TheseusSerializableError::Theseus(theseus_error) => {
|
||||||
|
$crate::error::display_tracing_error(theseus_error);
|
||||||
|
|
||||||
|
let mut state = serializer.serialize_struct("Theseus", 2)?;
|
||||||
|
state.serialize_field("field_name", "Theseus")?;
|
||||||
|
state.serialize_field("message", &theseus_error.to_string())?;
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
$(
|
$(
|
||||||
TheseusSerializableError::$variant(message) => {
|
TheseusSerializableError::$variant(message) => {
|
||||||
let mut state = serializer.serialize_struct(stringify!($variant), 2)?;
|
let mut state = serializer.serialize_struct(stringify!($variant), 2)?;
|
||||||
@ -80,7 +92,6 @@ macro_rules! impl_serialize {
|
|||||||
|
|
||||||
// Use the macro to implement Serialize for TheseusSerializableError
|
// Use the macro to implement Serialize for TheseusSerializableError
|
||||||
impl_serialize! {
|
impl_serialize! {
|
||||||
Theseus,
|
|
||||||
IO,
|
IO,
|
||||||
NoProfileFound,
|
NoProfileFound,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,12 @@ use theseus::prelude::*;
|
|||||||
// Creates a pack from a version ID (returns a path to the created profile)
|
// Creates a pack from a version ID (returns a path to the created profile)
|
||||||
// invoke('pack_install_version_id', version_id)
|
// invoke('pack_install_version_id', version_id)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn pack_install_version_id(version_id: String) -> Result<PathBuf> {
|
pub async fn pack_install_version_id(
|
||||||
let res = pack::install_pack_from_version_id(version_id).await?;
|
version_id: String,
|
||||||
|
pack_title: Option<String>,
|
||||||
|
) -> Result<PathBuf> {
|
||||||
|
let res =
|
||||||
|
pack::install_pack_from_version_id(version_id, pack_title).await?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ pub struct FrontendSettings {
|
|||||||
pub default_user: Option<uuid::Uuid>,
|
pub default_user: Option<uuid::Uuid>,
|
||||||
pub hooks: Hooks,
|
pub hooks: Hooks,
|
||||||
pub max_concurrent_downloads: usize,
|
pub max_concurrent_downloads: usize,
|
||||||
|
pub max_concurrent_writes: usize,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub collapsed_navigation: bool,
|
pub collapsed_navigation: bool,
|
||||||
}
|
}
|
||||||
@ -39,6 +40,7 @@ pub async fn settings_get() -> Result<FrontendSettings> {
|
|||||||
default_user: backend_settings.default_user,
|
default_user: backend_settings.default_user,
|
||||||
hooks: backend_settings.hooks,
|
hooks: backend_settings.hooks,
|
||||||
max_concurrent_downloads: backend_settings.max_concurrent_downloads,
|
max_concurrent_downloads: backend_settings.max_concurrent_downloads,
|
||||||
|
max_concurrent_writes: backend_settings.max_concurrent_writes,
|
||||||
version: backend_settings.version,
|
version: backend_settings.version,
|
||||||
collapsed_navigation: backend_settings.collapsed_navigation,
|
collapsed_navigation: backend_settings.collapsed_navigation,
|
||||||
};
|
};
|
||||||
@ -77,6 +79,7 @@ pub async fn settings_set(settings: FrontendSettings) -> Result<()> {
|
|||||||
default_user: settings.default_user,
|
default_user: settings.default_user,
|
||||||
hooks: settings.hooks,
|
hooks: settings.hooks,
|
||||||
max_concurrent_downloads: settings.max_concurrent_downloads,
|
max_concurrent_downloads: settings.max_concurrent_downloads,
|
||||||
|
max_concurrent_writes: settings.max_concurrent_writes,
|
||||||
version: settings.version,
|
version: settings.version,
|
||||||
collapsed_navigation: settings.collapsed_navigation,
|
collapsed_navigation: settings.collapsed_navigation,
|
||||||
};
|
};
|
||||||
|
|||||||
18
theseus_gui/src-tauri/src/error.rs
Normal file
18
theseus_gui/src-tauri/src/error.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use tracing_error::ExtractSpanTrace;
|
||||||
|
|
||||||
|
pub fn display_tracing_error(err: &theseus::Error) {
|
||||||
|
match get_span_trace(err) {
|
||||||
|
Some(span_trace) => {
|
||||||
|
tracing::error!(error = %err, span_trace = %span_trace);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
tracing::error!(error = %err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_span_trace<'a>(
|
||||||
|
error: &'a (dyn std::error::Error + 'static),
|
||||||
|
) -> Option<&'a tracing_error::SpanTrace> {
|
||||||
|
error.source().and_then(|e| e.span_trace())
|
||||||
|
}
|
||||||
@ -5,7 +5,11 @@
|
|||||||
|
|
||||||
use theseus::prelude::*;
|
use theseus::prelude::*;
|
||||||
|
|
||||||
|
use tracing_error::ErrorLayer;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
|
mod error;
|
||||||
|
|
||||||
// Should be called in launcher initialization
|
// Should be called in launcher initialization
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@ -37,7 +41,34 @@ async fn should_disable_mouseover() -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use tracing_subscriber::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
/*
|
||||||
|
tracing is set basd on the environment variable RUST_LOG=xxx, depending on the amount of logs to show
|
||||||
|
ERROR > WARN > INFO > DEBUG > TRACE
|
||||||
|
eg. RUST_LOG=info will show info, warn, and error logs
|
||||||
|
RUST_LOG="theseus=trace" will show *all* messages but from theseus only (and not dependencies using similar crates)
|
||||||
|
RUST_LOG="theseus=trace" will show *all* messages but from theseus only (and not dependencies using similar crates)
|
||||||
|
|
||||||
|
Error messages returned to Tauri will display as traced error logs if they return an error.
|
||||||
|
This will also include an attached span trace if the error is from a tracing error, and the level is set to info, debug, or trace
|
||||||
|
|
||||||
|
on unix:
|
||||||
|
RUST_LOG="theseus=trace" {run command}
|
||||||
|
|
||||||
|
*/
|
||||||
|
let filter = EnvFilter::try_from_default_env()
|
||||||
|
.unwrap_or_else(|_| EnvFilter::new("theseus=info"));
|
||||||
|
|
||||||
|
let subscriber = tracing_subscriber::registry()
|
||||||
|
.with(tracing_subscriber::fmt::layer())
|
||||||
|
.with(filter)
|
||||||
|
.with(ErrorLayer::default());
|
||||||
|
|
||||||
|
tracing::subscriber::set_global_default(subscriber)
|
||||||
|
.expect("setting default subscriber failed");
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
initialize_state,
|
initialize_state,
|
||||||
|
|||||||
@ -25,15 +25,16 @@ import { listen } from '@tauri-apps/api/event'
|
|||||||
/// Payload for the 'loading' event
|
/// Payload for the 'loading' event
|
||||||
/*
|
/*
|
||||||
LoadingPayload {
|
LoadingPayload {
|
||||||
event: "StateInit", "PackDownload", etc
|
event: {
|
||||||
- Certain states have additional fields:
|
type: string, one of "StateInit", "PackDownload", etc
|
||||||
- PackDownload: {
|
(Optional fields depending on event type)
|
||||||
pack_name: name of the pack
|
pack_name: name of the pack
|
||||||
pack_id, optional, the id of the modpack
|
pack_id, optional, the id of the modpack
|
||||||
pack_version, optional, the version of the modpack
|
pack_version, optional, the version of the modpack
|
||||||
- MinecraftDownload: {
|
profile_name: name of the profile
|
||||||
profile_name: name of the profile
|
profile_uuid: unique identification of the profile
|
||||||
profile_uuid: unique identification of the profile
|
|
||||||
|
}
|
||||||
loader_uuid: unique identification of the loading bar
|
loader_uuid: unique identification of the loading bar
|
||||||
fraction: number, (as a fraction of 1, how much we'vel oaded so far). If null, by convention, loading is finished
|
fraction: number, (as a fraction of 1, how much we'vel oaded so far). If null, by convention, loading is finished
|
||||||
message: message to display to the user
|
message: message to display to the user
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
import { invoke } from '@tauri-apps/api/tauri'
|
import { invoke } from '@tauri-apps/api/tauri'
|
||||||
|
|
||||||
// Installs pack from a version ID
|
// Installs pack from a version ID
|
||||||
export async function install(versionId) {
|
export async function install(versionId, packTitle) {
|
||||||
return await invoke('pack_install_version_id', { versionId })
|
return await invoke('pack_install_version_id', { versionId, packTitle })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Installs pack from a path
|
// Installs pack from a path
|
||||||
|
|||||||
@ -6,7 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
theseus = { path = "../theseus" }
|
theseus = { path = "../theseus", features = ["cli"] }
|
||||||
|
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
@ -21,3 +21,7 @@ tokio-stream = { version = "0.1", features = ["fs"] }
|
|||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
daedalus = {version = "0.1.15", features = ["bincode"] }
|
daedalus = {version = "0.1.15", features = ["bincode"] }
|
||||||
uuid = { version = "1.1", features = ["serde", "v4"] }
|
uuid = { version = "1.1", features = ["serde", "v4"] }
|
||||||
|
|
||||||
|
tracing = "0.1.37"
|
||||||
|
tracing-subscriber = "0.2"
|
||||||
|
tracing-error = "0.1"
|
||||||
|
|||||||
@ -8,6 +8,9 @@ use theseus::jre::autodetect_java_globals;
|
|||||||
use theseus::prelude::*;
|
use theseus::prelude::*;
|
||||||
use theseus::profile_create::profile_create;
|
use theseus::profile_create::profile_create;
|
||||||
use tokio::time::{sleep, Duration};
|
use tokio::time::{sleep, Duration};
|
||||||
|
use tracing_error::ErrorLayer;
|
||||||
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
// A simple Rust implementation of the authentication run
|
// A simple Rust implementation of the authentication run
|
||||||
// 1) call the authenticate_begin_flow() function to get the URL to open (like you would in the frontend)
|
// 1) call the authenticate_begin_flow() function to get the URL to open (like you would in the frontend)
|
||||||
@ -31,16 +34,27 @@ pub async fn authenticate_run() -> theseus::Result<Credentials> {
|
|||||||
async fn main() -> theseus::Result<()> {
|
async fn main() -> theseus::Result<()> {
|
||||||
println!("Starting.");
|
println!("Starting.");
|
||||||
|
|
||||||
|
let filter = EnvFilter::try_from_default_env()
|
||||||
|
.unwrap_or_else(|_| EnvFilter::new("theseus=info"));
|
||||||
|
|
||||||
|
let subscriber = tracing_subscriber::registry()
|
||||||
|
.with(tracing_subscriber::fmt::layer())
|
||||||
|
.with(filter)
|
||||||
|
.with(ErrorLayer::default());
|
||||||
|
|
||||||
|
tracing::subscriber::set_global_default(subscriber)
|
||||||
|
.expect("setting default subscriber failed");
|
||||||
|
|
||||||
// Initialize state
|
// Initialize state
|
||||||
let st = State::get().await?;
|
let st = State::get().await?;
|
||||||
//State::update();
|
//State::update();
|
||||||
|
|
||||||
st.settings.write().await.java_globals = autodetect_java_globals().await?;
|
st.settings.write().await.java_globals = autodetect_java_globals().await?;
|
||||||
st.settings.write().await.max_concurrent_downloads = 5;
|
st.settings.write().await.max_concurrent_downloads = 50;
|
||||||
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());
|
||||||
// Changed the settings, so need to reset the semaphore
|
// Changed the settings, so need to reset the semaphore
|
||||||
st.reset_semaphore().await;
|
st.reset_fetch_semaphore().await;
|
||||||
|
|
||||||
// Clear profiles
|
// Clear profiles
|
||||||
println!("Clearing profiles.");
|
println!("Clearing profiles.");
|
||||||
@ -53,21 +67,21 @@ async fn main() -> theseus::Result<()> {
|
|||||||
|
|
||||||
println!("Creating/adding profile.");
|
println!("Creating/adding profile.");
|
||||||
|
|
||||||
let name = "Example".to_string();
|
// let name = "Example".to_string();
|
||||||
let game_version = "1.19.2".to_string();
|
// let game_version = "1.19.2".to_string();
|
||||||
let modloader = ModLoader::Vanilla;
|
// let modloader = ModLoader::Vanilla;
|
||||||
let loader_version = "stable".to_string();
|
// let loader_version = "stable".to_string();
|
||||||
|
//
|
||||||
let profile_path = profile_create(
|
// let profile_path = profile_create(
|
||||||
name.clone(),
|
// name.clone(),
|
||||||
game_version,
|
// game_version,
|
||||||
modloader,
|
// modloader,
|
||||||
Some(loader_version),
|
// Some(loader_version),
|
||||||
None,
|
// None,
|
||||||
None,
|
// None,
|
||||||
None,
|
// None,
|
||||||
)
|
// )
|
||||||
.await?;
|
// .await?;
|
||||||
|
|
||||||
// let mut value = list().await?;
|
// let mut value = list().await?;
|
||||||
// let profile_path = value.iter().next().map(|x| x.0).unwrap();
|
// let profile_path = value.iter().next().map(|x| x.0).unwrap();
|
||||||
@ -89,10 +103,12 @@ async fn main() -> theseus::Result<()> {
|
|||||||
// profile::toggle_disable_project(&profile_path, &sodium_path).await?;
|
// profile::toggle_disable_project(&profile_path, &sodium_path).await?;
|
||||||
//
|
//
|
||||||
// profile::remove_project(&profile_path, &mod_menu_path).await?;
|
// profile::remove_project(&profile_path, &mod_menu_path).await?;
|
||||||
// let profile_path =
|
let profile_path = pack::install_pack_from_version_id(
|
||||||
// pack::install_pack_from_version_id("zroFQG1k".to_string())
|
"zroFQG1k".to_string(),
|
||||||
// .await
|
Some("Technical Electrical".to_string()),
|
||||||
// .unwrap();
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// async closure for testing any desired edits
|
// async closure for testing any desired edits
|
||||||
// (ie: changing the java runtime of an added profile)
|
// (ie: changing the java runtime of an added profile)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user