aboutsummaryrefslogtreecommitdiff
path: root/src-tauri
diff options
context:
space:
mode:
Diffstat (limited to 'src-tauri')
-rw-r--r--src-tauri/Cargo.lock2303
-rw-r--r--src-tauri/Cargo.toml36
-rw-r--r--src-tauri/capabilities/default.json10
-rw-r--r--src-tauri/capabilities/desktop.json15
-rw-r--r--src-tauri/capabilities/migrated.json82
-rw-r--r--src-tauri/src/constants.rs60
-rw-r--r--src-tauri/src/development/mod.rs84
-rw-r--r--src-tauri/src/github/mod.rs312
-rw-r--r--src-tauri/src/github/pull_requests.rs398
-rw-r--r--src-tauri/src/github/release_notes.rs244
-rw-r--r--src-tauri/src/lib.rs237
-rw-r--r--src-tauri/src/main.rs3
-rw-r--r--src-tauri/src/mod_management/legacy.rs213
-rw-r--r--src-tauri/src/mod_management/mod.rs797
-rw-r--r--src-tauri/src/mod_management/plugins.rs26
-rw-r--r--src-tauri/src/northstar/install.rs358
-rw-r--r--src-tauri/src/northstar/mod.rs276
-rw-r--r--src-tauri/src/northstar/profile.rs121
-rw-r--r--src-tauri/src/platform_specific/linux.rs98
-rw-r--r--src-tauri/src/platform_specific/mod.rs50
-rw-r--r--src-tauri/src/platform_specific/windows.rs104
-rw-r--r--src-tauri/src/repair_and_verify/mod.rs137
-rw-r--r--src-tauri/src/thunderstore/mod.rs86
-rw-r--r--src-tauri/src/util.rs324
-rw-r--r--src-tauri/tauri.conf.json65
25 files changed, 5662 insertions, 777 deletions
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index 1700ce57..083cfca3 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -4,24 +4,24 @@ version = 4
[[package]]
name = "addr2line"
-version = "0.24.2"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
dependencies = [
"gimli",
]
[[package]]
-name = "adler2"
-version = "2.0.0"
+name = "adler"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aes"
-version = "0.8.4"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
dependencies = [
"cfg-if",
"cipher",
@@ -30,9 +30,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
-version = "1.1.3"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
dependencies = [
"memchr",
]
@@ -69,9 +69,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.95"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
+checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
[[package]]
name = "arbitrary"
@@ -83,10 +83,49 @@ dependencies = [
]
[[package]]
+name = "arboard"
+version = "3.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4"
+dependencies = [
+ "clipboard-win",
+ "core-graphics 0.23.2",
+ "image",
+ "log",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "parking_lot",
+ "windows-sys 0.48.0",
+ "x11rb",
+]
+
+[[package]]
name = "arc-swap"
-version = "1.7.1"
+version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
+checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
+
+[[package]]
+name = "ashpd"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d43c03d9e36dd40cab48435be0b09646da362c278223ca535493877b2c1dee9"
+dependencies = [
+ "enumflags2",
+ "futures-channel",
+ "futures-util",
+ "rand 0.8.5",
+ "raw-window-handle",
+ "serde",
+ "serde_repr",
+ "tokio",
+ "url",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "zbus",
+]
[[package]]
name = "async-broadcast"
@@ -168,21 +207,20 @@ dependencies = [
[[package]]
name = "async-process"
-version = "2.3.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
+checksum = "451e3cf68011bd56771c79db04a9e333095ab6349f7e47592b788e9b98720cc8"
dependencies = [
"async-channel",
"async-io",
"async-lock",
"async-signal",
- "async-task",
"blocking",
"cfg-if",
"event-listener",
"futures-lite",
"rustix",
- "tracing",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -193,7 +231,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -222,13 +260,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-trait"
-version = "0.1.83"
+version = "0.1.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
+checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -262,36 +300,36 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
-version = "1.4.0"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
-version = "0.3.74"
+version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
dependencies = [
"addr2line",
+ "cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
- "windows-targets 0.52.6",
]
[[package]]
name = "base64"
-version = "0.21.7"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
[[package]]
name = "base64"
-version = "0.22.1"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
[[package]]
name = "base64ct"
@@ -374,27 +412,33 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.16.0"
+version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "bytemuck"
-version = "1.21.0"
+version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
+checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
[[package]]
name = "byteorder"
-version = "1.5.0"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "byteorder-lite"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
-version = "1.9.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
dependencies = [
"serde",
]
@@ -431,7 +475,7 @@ dependencies = [
"glib",
"libc",
"once_cell",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -474,7 +518,7 @@ dependencies = [
"semver",
"serde",
"serde_json",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -489,13 +533,12 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.5"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"jobserver",
"libc",
- "shlex",
]
[[package]]
@@ -517,9 +560,9 @@ dependencies = [
[[package]]
name = "cfg-expr"
-version = "0.15.8"
+version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
+checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9"
dependencies = [
"smallvec",
"target-lexicon",
@@ -539,9 +582,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
-version = "0.4.39"
+version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -563,6 +606,15 @@ dependencies = [
]
[[package]]
+name = "clipboard-win"
+version = "5.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
+dependencies = [
+ "error-code",
+]
+
+[[package]]
name = "cocoa"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -572,7 +624,7 @@ dependencies = [
"block",
"cocoa-foundation",
"core-foundation 0.10.0",
- "core-graphics",
+ "core-graphics 0.24.0",
"foreign-types 0.5.0",
"libc",
"objc",
@@ -587,16 +639,16 @@ dependencies = [
"bitflags 2.6.0",
"block",
"core-foundation 0.10.0",
- "core-graphics-types",
+ "core-graphics-types 0.2.0",
"libc",
"objc",
]
[[package]]
name = "combine"
-version = "4.6.7"
+version = "4.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
dependencies = [
"bytes",
"memchr",
@@ -613,18 +665,18 @@ dependencies = [
[[package]]
name = "const_format"
-version = "0.2.34"
+version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd"
+checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
-version = "0.2.34"
+version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
+checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1"
dependencies = [
"proc-macro2",
"quote",
@@ -645,15 +697,33 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "cookie"
-version = "0.18.1"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
+checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
dependencies = [
+ "percent-encoding",
"time",
"version_check",
]
[[package]]
+name = "cookie_store"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6"
+dependencies = [
+ "cookie",
+ "idna 0.3.0",
+ "log",
+ "publicsuffix",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "time",
+ "url",
+]
+
+[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -681,19 +751,43 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "core-graphics"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.9.4",
+ "core-graphics-types 0.1.3",
+ "foreign-types 0.5.0",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
dependencies = [
"bitflags 2.6.0",
"core-foundation 0.10.0",
- "core-graphics-types",
+ "core-graphics-types 0.2.0",
"foreign-types 0.5.0",
"libc",
]
[[package]]
name = "core-graphics-types"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.9.4",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
@@ -705,9 +799,9 @@ dependencies = [
[[package]]
name = "cpufeatures"
-version = "0.2.16"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
+checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [
"libc",
]
@@ -738,30 +832,36 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
-version = "0.5.14"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
+ "cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
-version = "0.8.6"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
+ "cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
-version = "0.9.18"
+version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
+ "autocfg",
+ "cfg-if",
"crossbeam-utils",
+ "memoffset",
+ "scopeguard",
]
[[package]]
@@ -804,24 +904,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "ctor"
-version = "0.2.9"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
+checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e"
dependencies = [
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "darling"
-version = "0.20.10"
+version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [
"darling_core",
"darling_macro",
@@ -829,30 +929,36 @@ dependencies = [
[[package]]
name = "darling_core"
-version = "0.20.10"
+version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "darling_macro"
-version = "0.20.10"
+version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
+name = "data-url"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
+
+[[package]]
name = "debugid"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -891,20 +997,20 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "derive_more"
-version = "0.99.18"
+version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce"
+checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version",
- "syn 2.0.91",
+ "syn 1.0.109",
]
[[package]]
@@ -928,6 +1034,16 @@ dependencies = [
]
[[package]]
+name = "dirs-next"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
+dependencies = [
+ "cfg-if",
+ "dirs-sys-next",
+]
+
+[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -940,6 +1056,17 @@ dependencies = [
]
[[package]]
+name = "dirs-sys-next"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
name = "dispatch"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -953,7 +1080,16 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "dlib"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
+dependencies = [
+ "libloading",
]
[[package]]
@@ -976,10 +1112,16 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
+name = "downcast-rs"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
+
+[[package]]
name = "dpi"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -996,18 +1138,18 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
[[package]]
name = "dtoa-short"
-version = "0.3.5"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
+checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74"
dependencies = [
"dtoa",
]
[[package]]
name = "dunce"
-version = "1.0.5"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
[[package]]
name = "dyn-clone"
@@ -1017,22 +1159,21 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "either"
-version = "1.13.0"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "embed-resource"
-version = "2.5.1"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b68b6f9f63a0b6a38bc447d4ce84e2b388f3ec95c99c641c8ff0dd3ef89a6379"
+checksum = "f7f1e82a60222fc67bfd50d752a9c89da5cce4c39ed39decc84a443b07bbd69a"
dependencies = [
"cc",
- "memchr",
"rustc_version",
- "toml 0.8.2",
+ "toml 0.7.6",
"vswhom",
- "winreg 0.52.0",
+ "winreg 0.11.0",
]
[[package]]
@@ -1043,9 +1184,9 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
[[package]]
name = "encoding_rs"
-version = "0.8.35"
+version = "0.8.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
dependencies = [
"cfg-if",
]
@@ -1074,14 +1215,14 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "env_logger"
-version = "0.10.2"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
"humantime",
"is-terminal",
@@ -1117,6 +1258,12 @@ dependencies = [
]
[[package]]
+name = "error-code"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f"
+
+[[package]]
name = "event-listener"
version = "5.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1139,15 +1286,15 @@ dependencies = [
[[package]]
name = "fastrand"
-version = "2.3.0"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]]
name = "fdeflate"
-version = "0.3.7"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
+checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10"
dependencies = [
"simd-adler32",
]
@@ -1164,14 +1311,14 @@ dependencies = [
[[package]]
name = "filetime"
-version = "0.2.25"
+version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
+checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
dependencies = [
"cfg-if",
"libc",
- "libredox",
- "windows-sys 0.59.0",
+ "redox_syscall 0.2.16",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -1188,9 +1335,9 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.35"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
+checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1225,7 +1372,17 @@ dependencies = [
"sysinfo",
"tauri",
"tauri-build",
- "tauri-plugin-opener",
+ "tauri-plugin-clipboard-manager",
+ "tauri-plugin-dialog",
+ "tauri-plugin-fs",
+ "tauri-plugin-global-shortcut",
+ "tauri-plugin-http",
+ "tauri-plugin-notification",
+ "tauri-plugin-os",
+ "tauri-plugin-process",
+ "tauri-plugin-shell",
+ "tauri-plugin-store",
+ "tauri-plugin-updater",
"tokio",
"ts-rs",
"winapi",
@@ -1267,7 +1424,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -1284,9 +1441,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
name = "form_urlencoded"
-version = "1.2.1"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
dependencies = [
"percent-encoding",
]
@@ -1303,9 +1460,9 @@ dependencies = [
[[package]]
name = "futures"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [
"futures-channel",
"futures-core",
@@ -1318,9 +1475,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [
"futures-core",
"futures-sink",
@@ -1328,15 +1485,15 @@ dependencies = [
[[package]]
name = "futures-core"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-executor"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [
"futures-core",
"futures-task",
@@ -1345,9 +1502,9 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]]
name = "futures-lite"
@@ -1364,32 +1521,32 @@ dependencies = [
[[package]]
name = "futures-macro"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "futures-sink"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[package]]
name = "futures-task"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
[[package]]
name = "futures-util"
-version = "0.3.31"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
"futures-channel",
"futures-core",
@@ -1522,6 +1679,26 @@ dependencies = [
]
[[package]]
+name = "gethostname"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
+dependencies = [
+ "libc",
+ "windows-targets 0.48.1",
+]
+
+[[package]]
+name = "gethostname"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30"
+dependencies = [
+ "rustix",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1534,9 +1711,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.15"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"js-sys",
@@ -1547,9 +1724,9 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.31.1"
+version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
[[package]]
name = "gio"
@@ -1567,7 +1744,7 @@ dependencies = [
"once_cell",
"pin-project-lite",
"smallvec",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -1603,7 +1780,7 @@ dependencies = [
"memchr",
"once_cell",
"smallvec",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -1617,7 +1794,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -1637,6 +1814,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
+name = "global-hotkey"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b00d88f1be7bf4cd2e61623ce08e84be2dfa4eab458e5d632d3dab95f16c1f64"
+dependencies = [
+ "crossbeam-channel",
+ "keyboard-types",
+ "objc2",
+ "objc2-app-kit",
+ "once_cell",
+ "serde",
+ "thiserror 1.0.58",
+ "windows-sys 0.59.0",
+ "x11-dl",
+]
+
+[[package]]
name = "gobject-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1696,22 +1890,41 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "h2"
-version = "0.3.26"
+version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
+checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
- "http 0.2.12",
- "indexmap 2.7.0",
+ "http 0.2.9",
+ "indexmap 1.9.3",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "h2"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http 1.2.0",
+ "indexmap 2.2.5",
"slab",
"tokio",
"tokio-util",
@@ -1726,9 +1939,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
-version = "0.15.2"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heck"
@@ -1744,6 +1957,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "hermit-abi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
@@ -1764,15 +1983,6 @@ dependencies = [
]
[[package]]
-name = "home"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
name = "hostname"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1799,13 +2009,13 @@ dependencies = [
[[package]]
name = "http"
-version = "0.2.12"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
+checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
dependencies = [
"bytes",
"fnv",
- "itoa 1.0.14",
+ "itoa 1.0.9",
]
[[package]]
@@ -1816,25 +2026,25 @@ checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
dependencies = [
"bytes",
"fnv",
- "itoa 1.0.14",
+ "itoa 1.0.9",
]
[[package]]
name = "http-body"
-version = "0.4.6"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"bytes",
- "http 0.2.12",
+ "http 0.2.9",
"pin-project-lite",
]
[[package]]
name = "http-body"
-version = "1.0.1"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes",
"http 1.2.0",
@@ -1842,28 +2052,28 @@ dependencies = [
[[package]]
name = "http-body-util"
-version = "0.1.2"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
dependencies = [
"bytes",
"futures-util",
"http 1.2.0",
- "http-body 1.0.1",
+ "http-body 1.0.0",
"pin-project-lite",
]
[[package]]
name = "httparse"
-version = "1.9.5"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
+checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "httpdate"
-version = "1.0.3"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "humantime"
@@ -1873,22 +2083,22 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
-version = "0.14.32"
+version = "0.14.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
+checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
- "h2",
- "http 0.2.12",
- "http-body 0.4.6",
+ "h2 0.3.20",
+ "http 0.2.9",
+ "http-body 0.4.5",
"httparse",
"httpdate",
- "itoa 1.0.14",
+ "itoa 1.0.9",
"pin-project-lite",
- "socket2",
+ "socket2 0.4.9",
"tokio",
"tower-service",
"tracing",
@@ -1897,19 +2107,19 @@ dependencies = [
[[package]]
name = "hyper"
-version = "1.5.2"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
+checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
+ "h2 0.4.7",
"http 1.2.0",
- "http-body 1.0.1",
+ "http-body 1.0.0",
"httparse",
- "itoa 1.0.14",
+ "itoa 1.0.9",
"pin-project-lite",
- "smallvec",
"tokio",
"want",
]
@@ -1922,10 +2132,10 @@ checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
dependencies = [
"futures-util",
"http 1.2.0",
- "hyper 1.5.2",
+ "hyper 1.1.0",
"hyper-util",
"log",
- "rustls 0.22.4",
+ "rustls 0.22.2",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
@@ -1935,11 +2145,11 @@ dependencies = [
[[package]]
name = "hyper-timeout"
-version = "0.5.2"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
+checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793"
dependencies = [
- "hyper 1.5.2",
+ "hyper 1.1.0",
"hyper-util",
"pin-project-lite",
"tokio",
@@ -1953,7 +2163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
- "hyper 0.14.32",
+ "hyper 0.14.27",
"native-tls",
"tokio",
"tokio-native-tls",
@@ -1967,7 +2177,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes",
"http-body-util",
- "hyper 1.5.2",
+ "hyper 1.1.0",
"hyper-util",
"native-tls",
"tokio",
@@ -1977,35 +2187,36 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.10"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.2.0",
- "http-body 1.0.1",
- "hyper 1.5.2",
+ "http-body 1.0.0",
+ "hyper 1.1.0",
"pin-project-lite",
- "socket2",
+ "socket2 0.5.5",
"tokio",
+ "tower",
"tower-service",
"tracing",
]
[[package]]
name = "iana-time-zone"
-version = "0.1.61"
+version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
- "windows-core 0.52.0",
+ "windows 0.48.0",
]
[[package]]
@@ -2142,7 +2353,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -2153,6 +2364,26 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
@@ -2173,6 +2404,19 @@ dependencies = [
]
[[package]]
+name = "image"
+version = "0.25.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
+dependencies = [
+ "bytemuck",
+ "byteorder-lite",
+ "num-traits",
+ "png",
+ "tiff",
+]
+
+[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2185,13 +2429,12 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.7.0"
+version = "2.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
+checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
dependencies = [
"equivalent",
- "hashbrown 0.15.2",
- "serde",
+ "hashbrown 0.14.3",
]
[[package]]
@@ -2214,24 +2457,24 @@ dependencies = [
[[package]]
name = "instant"
-version = "0.1.13"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "ipnet"
-version = "2.10.1"
+version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
+checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]]
name = "iri-string"
-version = "0.7.7"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc0f0a572e8ffe56e2ff4f769f32ffe919282c3916799f8b68688b6030063bea"
+checksum = "21859b667d66a4c1dacd9df0863b3efb65785474255face87f5bca39dd8407c0"
dependencies = [
"memchr",
"serde",
@@ -2248,13 +2491,13 @@ dependencies = [
[[package]]
name = "is-terminal"
-version = "0.4.13"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
+checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
- "hermit-abi",
- "libc",
- "windows-sys 0.52.0",
+ "hermit-abi 0.3.9",
+ "rustix",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -2275,9 +2518,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
-version = "1.0.14"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
+checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "javascriptcore-rs"
@@ -2313,7 +2556,7 @@ dependencies = [
"combine",
"jni-sys",
"log",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"walkdir",
"windows-sys 0.45.0",
]
@@ -2326,20 +2569,25 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
-version = "0.1.32"
+version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
dependencies = [
"libc",
]
[[package]]
+name = "jpeg-decoder"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
+
+[[package]]
name = "js-sys"
-version = "0.3.76"
+version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
- "once_cell",
"wasm-bindgen",
]
@@ -2352,7 +2600,7 @@ dependencies = [
"jsonptr",
"serde",
"serde_json",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -2378,14 +2626,14 @@ dependencies = [
[[package]]
name = "jsonwebtoken"
-version = "9.3.0"
+version = "9.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f"
+checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4"
dependencies = [
- "base64 0.21.7",
+ "base64 0.21.2",
"js-sys",
"pem",
- "ring",
+ "ring 0.17.7",
"serde",
"serde_json",
"simple_asn1",
@@ -2410,7 +2658,7 @@ checksum = "7e4c8354918309196302015ac9cae43362f1a13d0d5c5539a33b4c2fd2cd6d25"
dependencies = [
"pest",
"pest_derive",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -2421,7 +2669,7 @@ checksum = "0447866c47c00f8bd1949618e8f63017cf93e985b4684dc28d784527e2882390"
dependencies = [
"keyvalues-parser",
"serde",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -2439,9 +2687,9 @@ dependencies = [
[[package]]
name = "lazy_static"
-version = "1.5.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libappindicator"
@@ -2484,32 +2732,31 @@ dependencies = [
]
[[package]]
-name = "libredox"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
-dependencies = [
- "bitflags 2.6.0",
- "libc",
- "redox_syscall",
-]
-
-[[package]]
name = "libthermite"
-version = "0.8.2"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "878f5ca735da1a3365239d6fcb3a403c5cd347896e9a45d864b9fbfad727298e"
+checksum = "c27ac02c14161a4b0db739b37618d929d7f2af320c1f993e3d674599f77b79e7"
dependencies = [
"flate2",
"json5",
+ "lazy_static",
"regex",
"serde",
"serde_json",
"tar",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"tracing",
"ureq",
- "zip 2.2.2",
+ "zip 0.6.6",
+]
+
+[[package]]
+name = "line-wrap"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
+dependencies = [
+ "safemem",
]
[[package]]
@@ -2526,21 +2773,15 @@ checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]]
name = "lock_api"
-version = "0.4.12"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
-name = "lockfree-object-pool"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
-
-[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2553,6 +2794,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
+name = "mac-notification-sys"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce8f34f3717aa37177e723df6c1fc5fb02b2a1087374ea3fe0ea42316dc8f91"
+dependencies = [
+ "cc",
+ "dirs-next",
+ "objc-foundation",
+ "objc_id",
+ "time",
+]
+
+[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2583,15 +2837,15 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "memchr"
-version = "2.7.4"
+version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]]
name = "memoffset"
-version = "0.9.1"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
@@ -2603,21 +2857,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
+name = "minisign-verify"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6367d84fb54d4242af283086402907277715b8fe46976963af5ebf173f8efba3"
+
+[[package]]
name = "miniz_oxide"
-version = "0.8.2"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
- "adler2",
+ "adler",
"simd-adler32",
]
[[package]]
name = "mio"
-version = "1.0.3"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
dependencies = [
+ "hermit-abi 0.3.9",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
@@ -2639,16 +2900,17 @@ dependencies = [
"once_cell",
"png",
"serde",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"windows-sys 0.59.0",
]
[[package]]
name = "native-tls"
-version = "0.2.12"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
+ "lazy_static",
"libc",
"log",
"openssl",
@@ -2672,7 +2934,7 @@ dependencies = [
"ndk-sys",
"num_enum",
"raw-window-handle",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
]
[[package]]
@@ -2692,9 +2954,9 @@ dependencies = [
[[package]]
name = "new_debug_unreachable"
-version = "1.0.6"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
@@ -2715,6 +2977,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
+name = "notify-rust"
+version = "4.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5134a72dc570b178bff81b01e81ab14a6fcc015391ed4b3b14853090658cd3a3"
+dependencies = [
+ "log",
+ "mac-notification-sys",
+ "serde",
+ "tauri-winrt-notification",
+ "zbus",
+]
+
+[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2725,10 +3000,11 @@ dependencies = [
[[package]]
name = "num-bigint"
-version = "0.4.6"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
+ "autocfg",
"num-integer",
"num-traits",
]
@@ -2741,18 +3017,19 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
-version = "0.1.46"
+version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
+ "autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
-version = "0.2.19"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
@@ -2775,7 +3052,7 @@ dependencies = [
"proc-macro-crate 2.0.2",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -2788,6 +3065,17 @@ dependencies = [
]
[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
+[[package]]
name = "objc-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2896,6 +3184,7 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
"bitflags 2.6.0",
"block2",
+ "dispatch",
"libc",
"objc2",
]
@@ -3006,10 +3295,19 @@ dependencies = [
]
[[package]]
+name = "objc_id"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+dependencies = [
+ "objc",
+]
+
+[[package]]
name = "object"
-version = "0.36.7"
+version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
dependencies = [
"memchr",
]
@@ -3022,7 +3320,7 @@ checksum = "68a8a3df00728324ad654ecd1ed449a60157c55b7ff8c109af3a35989687c367"
dependencies = [
"arc-swap",
"async-trait",
- "base64 0.22.1",
+ "base64 0.22.0",
"bytes",
"cfg-if",
"chrono",
@@ -3030,9 +3328,9 @@ dependencies = [
"futures",
"futures-util",
"http 1.2.0",
- "http-body 1.0.1",
+ "http-body 1.0.0",
"http-body-util",
- "hyper 1.5.2",
+ "hyper 1.1.0",
"hyper-rustls",
"hyper-timeout",
"hyper-util",
@@ -3055,15 +3353,15 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.20.2"
+version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "open"
-version = "5.3.1"
+version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c"
+checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3"
dependencies = [
"is-wsl",
"libc",
@@ -3072,11 +3370,11 @@ dependencies = [
[[package]]
name = "openssl"
-version = "0.10.68"
+version = "0.10.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
+checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
dependencies = [
- "bitflags 2.6.0",
+ "bitflags 1.3.2",
"cfg-if",
"foreign-types 0.3.2",
"libc",
@@ -3093,7 +3391,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -3104,9 +3402,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
-version = "0.9.104"
+version = "0.9.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
+checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
dependencies = [
"cc",
"libc",
@@ -3132,13 +3430,23 @@ dependencies = [
[[package]]
name = "os_info"
-version = "3.9.1"
+version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb6651f4be5e39563c4fe5cc8326349eb99a25d805a3493f791d5bfd0269e430"
+checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e"
dependencies = [
"log",
"serde",
- "windows-sys 0.52.0",
+ "winapi",
+]
+
+[[package]]
+name = "os_pipe"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -3174,9 +3482,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "parking_lot"
-version = "0.12.3"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
@@ -3184,15 +3492,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.10"
+version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.3.5",
"smallvec",
- "windows-targets 0.52.6",
+ "windows-targets 0.48.1",
]
[[package]]
@@ -3208,9 +3516,9 @@ dependencies = [
[[package]]
name = "pathdiff"
-version = "0.2.3"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "pbkdf2"
@@ -3226,36 +3534,35 @@ dependencies = [
[[package]]
name = "pem"
-version = "3.0.4"
+version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae"
+checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310"
dependencies = [
- "base64 0.22.1",
+ "base64 0.21.2",
"serde",
]
[[package]]
name = "percent-encoding"
-version = "2.3.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "pest"
-version = "2.7.15"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
+checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a"
dependencies = [
- "memchr",
- "thiserror 2.0.9",
+ "thiserror 1.0.58",
"ucd-trie",
]
[[package]]
name = "pest_derive"
-version = "2.7.15"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
+checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853"
dependencies = [
"pest",
"pest_generator",
@@ -3263,22 +3570,22 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.7.15"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
+checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "pest_meta"
-version = "2.7.15"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
+checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48"
dependencies = [
"once_cell",
"pest",
@@ -3389,7 +3696,7 @@ dependencies = [
"phf_shared 0.11.2",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -3421,29 +3728,29 @@ dependencies = [
[[package]]
name = "pin-project"
-version = "1.1.7"
+version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
+checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
-version = "1.1.7"
+version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
+checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "pin-project-lite"
-version = "0.2.15"
+version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "pin-utils"
@@ -3464,28 +3771,29 @@ dependencies = [
[[package]]
name = "pkg-config"
-version = "0.3.31"
+version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "plist"
-version = "1.7.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
+checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06"
dependencies = [
- "base64 0.22.1",
- "indexmap 2.7.0",
- "quick-xml",
+ "base64 0.21.2",
+ "indexmap 1.9.3",
+ "line-wrap",
+ "quick-xml 0.29.0",
"serde",
"time",
]
[[package]]
name = "png"
-version = "0.17.16"
+version = "0.17.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
+checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
@@ -3502,7 +3810,7 @@ checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
dependencies = [
"cfg-if",
"concurrent-queue",
- "hermit-abi",
+ "hermit-abi 0.4.0",
"pin-project-lite",
"rustix",
"tracing",
@@ -3517,12 +3825,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
-version = "0.2.20"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
-dependencies = [
- "zerocopy",
-]
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "precomputed-hash"
@@ -3547,7 +3852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [
"once_cell",
- "toml_edit 0.19.15",
+ "toml_edit 0.19.14",
]
[[package]]
@@ -3600,19 +3905,53 @@ dependencies = [
]
[[package]]
+name = "psl-types"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
+
+[[package]]
+name = "publicsuffix"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf"
+dependencies = [
+ "idna 1.0.3",
+ "psl-types",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "quick-xml"
-version = "0.32.0"
+version = "0.36.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
+checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
-version = "1.0.37"
+version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@@ -3677,7 +4016,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom 0.2.15",
+ "getrandom 0.2.10",
]
[[package]]
@@ -3706,9 +4045,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rayon"
-version = "1.10.0"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
dependencies = [
"either",
"rayon-core",
@@ -3726,6 +4065,24 @@ dependencies = [
[[package]]
name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_syscall"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
@@ -3735,20 +4092,20 @@ dependencies = [
[[package]]
name = "redox_users"
-version = "0.4.6"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
- "getrandom 0.2.15",
- "libredox",
- "thiserror 1.0.69",
+ "getrandom 0.2.10",
+ "redox_syscall 0.2.16",
+ "thiserror 1.0.58",
]
[[package]]
name = "regex"
-version = "1.11.1"
+version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
@@ -3758,9 +4115,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.9"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a"
dependencies = [
"aho-corasick",
"memchr",
@@ -3769,9 +4126,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.8.5"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "remove-markdown-links"
@@ -3788,15 +4145,15 @@ version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
- "base64 0.21.7",
+ "base64 0.21.2",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
- "h2",
- "http 0.2.12",
- "http-body 0.4.6",
- "hyper 0.14.32",
+ "h2 0.3.20",
+ "http 0.2.9",
+ "http-body 0.4.5",
+ "hyper 0.14.27",
"hyper-tls 0.5.0",
"ipnet",
"js-sys",
@@ -3810,7 +4167,7 @@ dependencies = [
"serde",
"serde_json",
"serde_urlencoded",
- "sync_wrapper 0.1.2",
+ "sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
@@ -3824,19 +4181,24 @@ dependencies = [
[[package]]
name = "reqwest"
-version = "0.12.9"
+version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
+checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
dependencies = [
- "base64 0.22.1",
+ "base64 0.22.0",
"bytes",
+ "cookie",
+ "cookie_store",
+ "encoding_rs",
"futures-channel",
"futures-core",
"futures-util",
+ "h2 0.4.7",
"http 1.2.0",
- "http-body 1.0.1",
+ "http-body 1.0.0",
"http-body-util",
- "hyper 1.5.2",
+ "hyper 1.1.0",
+ "hyper-rustls",
"hyper-tls 0.6.0",
"hyper-util",
"ipnet",
@@ -3847,13 +4209,17 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
- "rustls-pemfile 2.2.0",
+ "rustls 0.22.2",
+ "rustls-pemfile 2.0.0",
+ "rustls-pki-types",
"serde",
"serde_json",
"serde_urlencoded",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
+ "system-configuration",
"tokio",
"tokio-native-tls",
+ "tokio-rustls",
"tokio-util",
"tower-service",
"url",
@@ -3861,35 +4227,73 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
- "windows-registry",
+ "webpki-roots 0.26.7",
+ "winreg 0.52.0",
+]
+
+[[package]]
+name = "rfd"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e"
+dependencies = [
+ "ashpd",
+ "block2",
+ "glib-sys",
+ "gobject-sys",
+ "gtk-sys",
+ "js-sys",
+ "log",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "raw-window-handle",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows-sys 0.48.0",
]
[[package]]
name = "ring"
-version = "0.17.8"
+version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
+checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
- "cfg-if",
- "getrandom 0.2.15",
"libc",
- "spin",
- "untrusted",
- "windows-sys 0.52.0",
+ "once_cell",
+ "spin 0.5.2",
+ "untrusted 0.7.1",
+ "web-sys",
+ "winapi",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+dependencies = [
+ "cc",
+ "getrandom 0.2.10",
+ "libc",
+ "spin 0.9.8",
+ "untrusted 0.9.0",
+ "windows-sys 0.48.0",
]
[[package]]
name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc_version"
-version = "0.4.1"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
@@ -3909,41 +4313,38 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.22.4"
+version = "0.21.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
+checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
dependencies = [
"log",
- "ring",
- "rustls-pki-types",
- "rustls-webpki",
- "subtle",
- "zeroize",
+ "ring 0.16.20",
+ "rustls-webpki 0.101.2",
+ "sct",
]
[[package]]
name = "rustls"
-version = "0.23.20"
+version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
+checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41"
dependencies = [
"log",
- "once_cell",
- "ring",
+ "ring 0.17.7",
"rustls-pki-types",
- "rustls-webpki",
+ "rustls-webpki 0.102.2",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-native-certs"
-version = "0.7.3"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
+checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792"
dependencies = [
"openssl-probe",
- "rustls-pemfile 2.2.0",
+ "rustls-pemfile 2.0.0",
"rustls-pki-types",
"schannel",
"security-framework",
@@ -3955,15 +4356,16 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [
- "base64 0.21.7",
+ "base64 0.21.2",
]
[[package]]
name = "rustls-pemfile"
-version = "2.2.0"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4"
dependencies = [
+ "base64 0.21.2",
"rustls-pki-types",
]
@@ -3975,20 +4377,46 @@ checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
[[package]]
name = "rustls-webpki"
-version = "0.102.8"
+version = "0.100.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
+dependencies = [
+ "ring 0.16.20",
+ "untrusted 0.7.1",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59"
dependencies = [
- "ring",
+ "ring 0.16.20",
+ "untrusted 0.7.1",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.102.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610"
+dependencies = [
+ "ring 0.17.7",
"rustls-pki-types",
- "untrusted",
+ "untrusted 0.9.0",
]
[[package]]
name = "ryu"
-version = "1.0.18"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+
+[[package]]
+name = "safemem"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
[[package]]
name = "same-file"
@@ -4001,11 +4429,11 @@ dependencies = [
[[package]]
name = "schannel"
-version = "0.1.27"
+version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -4032,16 +4460,32 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
+name = "scoped-tls"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
+
+[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
+name = "sct"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
+dependencies = [
+ "ring 0.16.20",
+ "untrusted 0.7.1",
+]
+
+[[package]]
name = "secrecy"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4052,11 +4496,11 @@ dependencies = [
[[package]]
name = "security-framework"
-version = "2.11.1"
+version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
- "bitflags 2.6.0",
+ "bitflags 1.3.2",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
@@ -4065,9 +4509,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.13.0"
+version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
@@ -4095,9 +4539,9 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.24"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
dependencies = [
"serde",
]
@@ -4110,7 +4554,7 @@ checksum = "00421ed8fa0c995f07cde48ba6c89e80f2b312f74ff637326f392fbfd23abe02"
dependencies = [
"httpdate",
"native-tls",
- "reqwest 0.12.9",
+ "reqwest 0.12.4",
"sentry-backtrace",
"sentry-contexts",
"sentry-core 0.32.3",
@@ -4226,7 +4670,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"serde_json",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"time",
"url",
"uuid",
@@ -4243,7 +4687,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"serde_json",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"time",
"url",
"uuid",
@@ -4251,9 +4695,9 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.216"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
@@ -4271,13 +4715,13 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.216"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -4288,16 +4732,16 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "serde_json"
-version = "1.0.134"
+version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
+checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
dependencies = [
- "itoa 1.0.14",
+ "itoa 1.0.9",
"memchr",
"ryu",
"serde",
@@ -4305,30 +4749,30 @@ dependencies = [
[[package]]
name = "serde_path_to_error"
-version = "0.1.16"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
+checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c"
dependencies = [
- "itoa 1.0.14",
+ "itoa 1.0.9",
"serde",
]
[[package]]
name = "serde_repr"
-version = "0.1.19"
+version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
+checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "serde_spanned"
-version = "0.6.8"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
dependencies = [
"serde",
]
@@ -4340,24 +4784,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
- "itoa 1.0.14",
+ "itoa 1.0.9",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
-version = "3.11.0"
+version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817"
+checksum = "21e47d95bc83ed33b2ecf84f4187ad1ab9685d18ff28db000c99deac8ce180e3"
dependencies = [
- "base64 0.22.1",
+ "base64 0.21.2",
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.7.0",
"serde",
- "serde_derive",
"serde_json",
"serde_with_macros",
"time",
@@ -4365,14 +4807,14 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.11.0"
+version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d"
+checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65"
dependencies = [
"darling",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -4409,9 +4851,9 @@ dependencies = [
[[package]]
name = "sha1"
-version = "0.10.6"
+version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -4420,9 +4862,9 @@ dependencies = [
[[package]]
name = "sha2"
-version = "0.10.8"
+version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -4430,16 +4872,20 @@ dependencies = [
]
[[package]]
-name = "shlex"
-version = "1.3.0"
+name = "shared_child"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
[[package]]
name = "signal-hook-registry"
-version = "1.4.2"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
@@ -4458,21 +4904,21 @@ checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
dependencies = [
"num-bigint",
"num-traits",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"time",
]
[[package]]
name = "siphasher"
-version = "0.3.11"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "slab"
-version = "0.4.9"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
dependencies = [
"autocfg",
]
@@ -4485,33 +4931,43 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "snafu"
-version = "0.8.5"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019"
+checksum = "5ed22871b3fe6eff9f1b48f6cbd54149ff8e9acd740dea9146092435f9c43bd3"
dependencies = [
"snafu-derive",
]
[[package]]
name = "snafu-derive"
-version = "0.8.5"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917"
+checksum = "4651148226ec36010993fcba6c3381552e8463e9f3e337b75af202b0688b5274"
dependencies = [
- "heck 0.5.0",
+ "heck 0.4.1",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "socket2"
-version = "0.5.8"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
dependencies = [
"libc",
- "windows-sys 0.52.0",
+ "winapi",
+]
+
+[[package]]
+name = "socket2"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -4522,7 +4978,7 @@ checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
dependencies = [
"bytemuck",
"cfg_aliases",
- "core-graphics",
+ "core-graphics 0.24.0",
"foreign-types 0.5.0",
"js-sys",
"log",
@@ -4530,7 +4986,7 @@ dependencies = [
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
- "redox_syscall",
+ "redox_syscall 0.5.8",
"wasm-bindgen",
"web-sys",
"windows-sys 0.59.0",
@@ -4564,6 +5020,12 @@ dependencies = [
[[package]]
name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
+name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
@@ -4582,16 +5044,16 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "steamlocate"
-version = "2.0.0"
+version = "2.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb96708f2e7cadc6c5bde3f3e12e3d6565bbd4d8b9e3da057035881c33136d9d"
+checksum = "c3b6a4810c4e7fecb0123a9a8ba99b335c17d92e636c265ef99108ee4734c812"
dependencies = [
"crc",
- "home",
+ "dirs",
"keyvalues-parser",
"keyvalues-serde",
"serde",
- "winreg 0.52.0",
+ "winreg 0.51.0",
]
[[package]]
@@ -4622,15 +5084,15 @@ dependencies = [
[[package]]
name = "strsim"
-version = "0.11.1"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
-version = "2.6.1"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "swift-rs"
@@ -4638,7 +5100,7 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7"
dependencies = [
- "base64 0.21.7",
+ "base64 0.21.2",
"serde",
"serde_json",
]
@@ -4656,9 +5118,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.91"
+version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
@@ -4672,15 +5134,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
-name = "sync_wrapper"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
-dependencies = [
- "futures-core",
-]
-
-[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4688,7 +5141,16 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "sys-locale"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
+dependencies = [
+ "libc",
]
[[package]]
@@ -4729,14 +5191,14 @@ dependencies = [
[[package]]
name = "system-deps"
-version = "6.2.2"
+version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
+checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3"
dependencies = [
"cfg-expr",
- "heck 0.5.0",
+ "heck 0.4.1",
"pkg-config",
- "toml 0.8.2",
+ "toml 0.7.6",
"version-compare",
]
@@ -4749,7 +5211,7 @@ dependencies = [
"bitflags 2.6.0",
"cocoa",
"core-foundation 0.10.0",
- "core-graphics",
+ "core-graphics 0.24.0",
"crossbeam-channel",
"dispatch",
"dlopen2",
@@ -4781,20 +5243,20 @@ dependencies = [
[[package]]
name = "tao-macros"
-version = "0.1.3"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd"
+checksum = "3b27a4bcc5eb524658234589bdffc7e7bfb996dbae6ce9393bfd39cb4159b445"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 1.0.109",
]
[[package]]
name = "tar"
-version = "0.4.43"
+version = "0.4.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6"
+checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96"
dependencies = [
"filetime",
"libc",
@@ -4803,15 +5265,15 @@ dependencies = [
[[package]]
name = "target-lexicon"
-version = "0.12.16"
+version = "0.12.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
+checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
[[package]]
name = "tauri"
-version = "2.1.1"
+version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e545de0a2dfe296fa67db208266cd397c5a55ae782da77973ef4c4fac90e9f2c"
+checksum = "d3889b392db6d32a105d3757230ea0220090b8f94c90d3e60b6c5eb91178ab1b"
dependencies = [
"anyhow",
"bytes",
@@ -4819,7 +5281,7 @@ dependencies = [
"dunce",
"embed_plist",
"futures-util",
- "getrandom 0.2.15",
+ "getrandom 0.2.10",
"glob",
"gtk",
"heck 0.5.0",
@@ -4835,7 +5297,7 @@ dependencies = [
"percent-encoding",
"plist",
"raw-window-handle",
- "reqwest 0.12.9",
+ "reqwest 0.12.4",
"serde",
"serde_json",
"serde_repr",
@@ -4846,7 +5308,7 @@ dependencies = [
"tauri-runtime",
"tauri-runtime-wry",
"tauri-utils",
- "thiserror 2.0.9",
+ "thiserror 1.0.58",
"tokio",
"tray-icon",
"url",
@@ -4885,7 +5347,7 @@ version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf79faeecf301d3e969b1fae977039edb77a4c1f25cc0a961be298b54bff97cf"
dependencies = [
- "base64 0.22.1",
+ "base64 0.22.0",
"brotli",
"ico",
"json-patch",
@@ -4897,7 +5359,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
- "syn 2.0.91",
+ "syn 2.0.90",
"tauri-utils",
"thiserror 2.0.9",
"time",
@@ -4915,7 +5377,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
"tauri-codegen",
"tauri-utils",
]
@@ -4938,25 +5400,210 @@ dependencies = [
]
[[package]]
-name = "tauri-plugin-opener"
-version = "2.2.2"
+name = "tauri-plugin-clipboard-manager"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be2c6f5d82396c1a86d5b16052cc97976a82e92244bf074dd6e2f6272d8619d"
+dependencies = [
+ "arboard",
+ "log",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-plugin",
+ "thiserror 2.0.9",
+]
+
+[[package]]
+name = "tauri-plugin-dialog"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b59fd750551b1066744ab956a1cd6b1ea3e1b3763b0b9153ac27a044d596426"
+dependencies = [
+ "log",
+ "raw-window-handle",
+ "rfd",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-plugin",
+ "tauri-plugin-fs",
+ "thiserror 2.0.9",
+ "url",
+]
+
+[[package]]
+name = "tauri-plugin-fs"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63ac39033ef1bb4d52da4878c3d8ab6d80b0a569d69208c884e6d4d54eb427b9"
+checksum = "a1a1edf18000f02903a7c2e5997fb89aca455ecbc0acc15c6535afbb883be223"
dependencies = [
+ "anyhow",
"dunce",
"glob",
- "objc2-app-kit",
- "objc2-foundation",
+ "percent-encoding",
+ "schemars",
+ "serde",
+ "serde_json",
+ "serde_repr",
+ "tauri",
+ "tauri-plugin",
+ "tauri-utils",
+ "thiserror 2.0.9",
+ "toml 0.8.2",
+ "url",
+ "uuid",
+]
+
+[[package]]
+name = "tauri-plugin-global-shortcut"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00f646a09511e8d283267dcdaa08c2ef27c4116bf271d9114849d9ca215606c3"
+dependencies = [
+ "global-hotkey",
+ "log",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-plugin",
+ "thiserror 2.0.9",
+]
+
+[[package]]
+name = "tauri-plugin-http"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e62a9bde54d6a0218b63f5a248f02056ad4316ba6ad81dfb9e4f73715df5deb1"
+dependencies = [
+ "data-url",
+ "http 1.2.0",
+ "regex",
+ "reqwest 0.12.4",
+ "schemars",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-plugin",
+ "tauri-plugin-fs",
+ "thiserror 2.0.9",
+ "tokio",
+ "url",
+ "urlpattern",
+]
+
+[[package]]
+name = "tauri-plugin-notification"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46ab803095f14ac6521fdb6477210a49e86fed6623c3c97d8e4b2b35e045e922"
+dependencies = [
+ "log",
+ "notify-rust",
+ "rand 0.8.5",
+ "serde",
+ "serde_json",
+ "serde_repr",
+ "tauri",
+ "tauri-plugin",
+ "thiserror 2.0.9",
+ "time",
+ "url",
+]
+
+[[package]]
+name = "tauri-plugin-os"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dda2d571a9baf0664c1f2088db227e3072f9028602fafa885deade7547c3b738"
+dependencies = [
+ "gethostname 0.5.0",
+ "log",
+ "os_info",
+ "serde",
+ "serde_json",
+ "serialize-to-javascript",
+ "sys-locale",
+ "tauri",
+ "tauri-plugin",
+ "thiserror 2.0.9",
+]
+
+[[package]]
+name = "tauri-plugin-process"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40cc553ab29581c8c43dfa5fb0c9d5aee8ba962ad3b42908eea26c79610441b7"
+dependencies = [
+ "tauri",
+ "tauri-plugin",
+]
+
+[[package]]
+name = "tauri-plugin-shell"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb2c50a63e60fb8925956cc5b7569f4b750ac197a4d39f13b8dd46ea8e2bad79"
+dependencies = [
+ "encoding_rs",
+ "log",
"open",
+ "os_pipe",
+ "regex",
"schemars",
"serde",
"serde_json",
+ "shared_child",
+ "tauri",
+ "tauri-plugin",
+ "thiserror 2.0.9",
+ "tokio",
+]
+
+[[package]]
+name = "tauri-plugin-store"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c0c08fae6995909f5e9a0da6038273b750221319f2c0f3b526d6de1cde21505"
+dependencies = [
+ "dunce",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-plugin",
+ "thiserror 2.0.9",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "tauri-plugin-updater"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7351014c140906bcfff59d96e04b1170c8f602557f40eb37f7de356d4e7067b"
+dependencies = [
+ "base64 0.22.0",
+ "dirs",
+ "flate2",
+ "futures-util",
+ "http 1.2.0",
+ "infer",
+ "minisign-verify",
+ "percent-encoding",
+ "reqwest 0.12.4",
+ "semver",
+ "serde",
+ "serde_json",
+ "tar",
"tauri",
"tauri-plugin",
+ "tempfile",
"thiserror 2.0.9",
+ "time",
+ "tokio",
"url",
- "windows 0.58.0",
- "zbus",
+ "windows-sys 0.59.0",
+ "zip 2.0.0",
]
[[package]]
@@ -4980,9 +5627,9 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
-version = "2.2.0"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f442a38863e10129ffe2cec7bd09c2dcf8a098a3a27801a476a304d5bb991d2"
+checksum = "62fa2068e8498ad007b54d5773d03d57c3ff6dd96f8c8ce58beff44d0d5e0d30"
dependencies = [
"gtk",
"http 1.2.0",
@@ -5048,20 +5695,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb"
dependencies = [
"embed-resource",
- "toml 0.7.8",
+ "toml 0.7.6",
+]
+
+[[package]]
+name = "tauri-winrt-notification"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f89f5fb70d6f62381f5d9b2ba9008196150b40b75f3068eb24faeddf1c686871"
+dependencies = [
+ "quick-xml 0.31.0",
+ "windows 0.56.0",
+ "windows-version",
]
[[package]]
name = "tempfile"
-version = "3.14.0"
+version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
+checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998"
dependencies = [
"cfg-if",
"fastrand",
- "once_cell",
+ "redox_syscall 0.3.5",
"rustix",
- "windows-sys 0.59.0",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -5077,9 +5735,9 @@ dependencies = [
[[package]]
name = "termcolor"
-version = "1.4.1"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
@@ -5092,11 +5750,11 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]]
name = "thiserror"
-version = "1.0.69"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
- "thiserror-impl 1.0.69",
+ "thiserror-impl 1.0.58",
]
[[package]]
@@ -5110,13 +5768,13 @@ dependencies = [
[[package]]
name = "thiserror-impl"
-version = "1.0.69"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -5127,17 +5785,28 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "tiff"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
+dependencies = [
+ "flate2",
+ "jpeg-decoder",
+ "weezl",
]
[[package]]
name = "time"
-version = "0.3.37"
+version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
- "itoa 1.0.14",
+ "itoa 1.0.9",
"num-conv",
"powerfmt",
"serde",
@@ -5153,9 +5822,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
-version = "0.2.19"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
@@ -5172,10 +5841,25 @@ dependencies = [
]
[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
name = "tokio"
-version = "1.42.0"
+version = "1.39.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
+checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
dependencies = [
"backtrace",
"bytes",
@@ -5184,8 +5868,9 @@ dependencies = [
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
- "socket2",
+ "socket2 0.5.5",
"tokio-macros",
+ "tracing",
"windows-sys 0.52.0",
]
@@ -5197,7 +5882,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -5216,34 +5901,35 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
dependencies = [
- "rustls 0.22.4",
+ "rustls 0.22.2",
"rustls-pki-types",
"tokio",
]
[[package]]
name = "tokio-util"
-version = "0.7.13"
+version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
+checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
+ "tracing",
]
[[package]]
name = "toml"
-version = "0.7.8"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
+checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "toml_edit 0.19.15",
+ "toml_edit 0.19.14",
]
[[package]]
@@ -5269,11 +5955,11 @@ dependencies = [
[[package]]
name = "toml_edit"
-version = "0.19.15"
+version = "0.19.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
dependencies = [
- "indexmap 2.7.0",
+ "indexmap 2.2.5",
"serde",
"serde_spanned",
"toml_datetime",
@@ -5286,7 +5972,7 @@ version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [
- "indexmap 2.7.0",
+ "indexmap 2.2.5",
"serde",
"serde_spanned",
"toml_datetime",
@@ -5312,15 +5998,15 @@ dependencies = [
[[package]]
name = "tower-http"
-version = "0.5.2"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
+checksum = "0da193277a4e2c33e59e09b5861580c33dd0a637c3883d0fa74ba40c0374af2e"
dependencies = [
"bitflags 2.6.0",
"bytes",
"futures-util",
"http 1.2.0",
- "http-body 1.0.1",
+ "http-body 1.0.0",
"http-body-util",
"iri-string",
"pin-project-lite",
@@ -5332,22 +6018,23 @@ dependencies = [
[[package]]
name = "tower-layer"
-version = "0.3.3"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
[[package]]
name = "tower-service"
-version = "0.3.3"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
-version = "0.1.41"
+version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
+ "cfg-if",
"log",
"pin-project-lite",
"tracing-attributes",
@@ -5356,20 +6043,20 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.28"
+version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
+checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
name = "tracing-core"
-version = "0.1.33"
+version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
dependencies = [
"once_cell",
"valuable",
@@ -5377,9 +6064,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
-version = "0.3.19"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
+checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
dependencies = [
"tracing-core",
]
@@ -5390,7 +6077,7 @@ version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d48a05076dd272615d03033bf04f480199f7d1b66a8ac64d75c625fc4a70c06b"
dependencies = [
- "core-graphics",
+ "core-graphics 0.24.0",
"crossbeam-channel",
"dirs",
"libappindicator",
@@ -5401,36 +6088,36 @@ dependencies = [
"once_cell",
"png",
"serde",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"windows-sys 0.59.0",
]
[[package]]
name = "try-lock"
-version = "0.2.5"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "ts-rs"
-version = "10.1.0"
+version = "10.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e640d9b0964e9d39df633548591090ab92f7a4567bc31d3891af23471a3365c6"
+checksum = "3a2f31991cee3dce1ca4f929a8a04fdd11fd8801aac0f2030b0fa8a0a3fef6b9"
dependencies = [
"lazy_static",
- "thiserror 2.0.9",
+ "thiserror 1.0.58",
"ts-rs-macros",
]
[[package]]
name = "ts-rs-macros"
-version = "10.1.0"
+version = "10.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e9d8656589772eeec2cf7a8264d9cda40fb28b9bc53118ceb9e8c07f8f38730"
+checksum = "0ea0b99e8ec44abd6f94a18f28f7934437809dd062820797c52401298116f70e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
"termcolor",
]
@@ -5442,15 +6129,15 @@ checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e"
[[package]]
name = "typenum"
-version = "1.17.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-trie"
-version = "0.1.7"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
[[package]]
name = "uds_windows"
@@ -5514,10 +6201,25 @@ dependencies = [
]
[[package]]
+name = "unicode-bidi"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+
+[[package]]
name = "unicode-ident"
-version = "1.0.14"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
[[package]]
name = "unicode-segmentation"
@@ -5527,9 +6229,15 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-xid"
-version = "0.2.6"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "untrusted"
@@ -5539,29 +6247,29 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
-version = "2.12.1"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
+checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9"
dependencies = [
- "base64 0.22.1",
+ "base64 0.21.2",
"flate2",
"log",
"native-tls",
"once_cell",
- "rustls 0.23.20",
- "rustls-pki-types",
+ "rustls 0.21.6",
+ "rustls-webpki 0.100.1",
"url",
- "webpki-roots",
+ "webpki-roots 0.23.1",
]
[[package]]
name = "url"
-version = "2.5.4"
+version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [
"form_urlencoded",
- "idna",
+ "idna 0.4.0",
"percent-encoding",
"serde",
]
@@ -5598,11 +6306,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "uuid"
-version = "1.11.0"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
+checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
dependencies = [
- "getrandom 0.2.15",
+ "getrandom 0.2.10",
"serde",
]
@@ -5620,15 +6328,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
-version = "0.2.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
+checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
[[package]]
name = "version_check"
-version = "0.9.5"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vswhom"
@@ -5652,9 +6360,9 @@ dependencies = [
[[package]]
name = "walkdir"
-version = "2.5.0"
+version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
dependencies = [
"same-file",
"winapi-util",
@@ -5683,47 +6391,46 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.99"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
- "once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.99"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
+ "once_cell",
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.49"
+version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
+checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [
"cfg-if",
"js-sys",
- "once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.99"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -5731,28 +6438,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.99"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.99"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "wasm-streams"
-version = "0.4.2"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
+checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",
@@ -5762,10 +6469,70 @@ dependencies = [
]
[[package]]
+name = "wayland-backend"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.31.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280"
+dependencies = [
+ "bitflags 2.6.0",
+ "rustix",
+ "wayland-backend",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.32.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e"
+dependencies = [
+ "bitflags 2.6.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.31.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3"
+dependencies = [
+ "proc-macro2",
+ "quick-xml 0.36.2",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09"
+dependencies = [
+ "dlib",
+ "log",
+ "pkg-config",
+]
+
+[[package]]
name = "web-sys"
-version = "0.3.76"
+version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -5817,6 +6584,15 @@ dependencies = [
[[package]]
name = "webpki-roots"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338"
+dependencies = [
+ "rustls-webpki 0.100.1",
+]
+
+[[package]]
+name = "webpki-roots"
version = "0.26.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e"
@@ -5834,8 +6610,8 @@ dependencies = [
"webview2-com-sys",
"windows 0.58.0",
"windows-core 0.58.0",
- "windows-implement",
- "windows-interface",
+ "windows-implement 0.58.0",
+ "windows-interface 0.58.0",
]
[[package]]
@@ -5846,7 +6622,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -5855,12 +6631,18 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886"
dependencies = [
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"windows 0.58.0",
"windows-core 0.58.0",
]
[[package]]
+name = "weezl"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
+
+[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5878,11 +6660,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
-version = "0.1.9"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
- "windows-sys 0.59.0",
+ "winapi",
]
[[package]]
@@ -5907,6 +6689,15 @@ dependencies = [
[[package]]
name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets 0.48.1",
+]
+
+[[package]]
+name = "windows"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
@@ -5917,6 +6708,16 @@ dependencies = [
[[package]]
name = "windows"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
+dependencies = [
+ "windows-core 0.56.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
@@ -5936,26 +6737,60 @@ dependencies = [
[[package]]
name = "windows-core"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
+dependencies = [
+ "windows-implement 0.56.0",
+ "windows-interface 0.56.0",
+ "windows-result 0.1.2",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-core"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
- "windows-implement",
- "windows-interface",
- "windows-result",
+ "windows-implement 0.58.0",
+ "windows-interface 0.58.0",
+ "windows-result 0.2.0",
"windows-strings",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-implement"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "windows-implement"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
]
[[package]]
@@ -5966,17 +6801,15 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
-name = "windows-registry"
-version = "0.2.0"
+name = "windows-result"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
- "windows-result",
- "windows-strings",
"windows-targets 0.52.6",
]
@@ -5995,7 +6828,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
- "windows-result",
+ "windows-result 0.2.0",
"windows-targets 0.52.6",
]
@@ -6014,7 +6847,7 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets 0.48.1",
]
[[package]]
@@ -6052,17 +6885,17 @@ dependencies = [
[[package]]
name = "windows-targets"
-version = "0.48.5"
+version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
+ "windows_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
]
[[package]]
@@ -6083,9 +6916,9 @@ dependencies = [
[[package]]
name = "windows-version"
-version = "0.1.1"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515"
+checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4"
dependencies = [
"windows-targets 0.52.6",
]
@@ -6098,9 +6931,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.48.5"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
@@ -6116,9 +6949,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.48.5"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
@@ -6134,9 +6967,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
-version = "0.48.5"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
@@ -6158,9 +6991,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
-version = "0.48.5"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
@@ -6176,9 +7009,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.48.5"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnu"
@@ -6194,9 +7027,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.48.5"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -6212,9 +7045,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.48.5"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "windows_x86_64_msvc"
@@ -6224,15 +7057,25 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
-version = "0.5.40"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a1a57ff50e9b408431e8f97d5456f2807f8eb2a2cd79b06068fc87f8ecf189"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
@@ -6243,6 +7086,16 @@ dependencies = [
[[package]]
name = "winreg"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "937f3df7948156640f46aacef17a70db0de5917bda9c92b0f751f3a955b588fc"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "winreg"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
@@ -6265,13 +7118,12 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]]
name = "wry"
-version = "0.47.2"
+version = "0.46.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61ce51277d65170f6379d8cda935c80e3c2d1f0ff712a123c8bddb11b31a4b73"
+checksum = "cd5cdf57c66813d97601181349c63b96994b3074fc3d7a31a8cce96e968e3bbd"
dependencies = [
- "base64 0.22.1",
+ "base64 0.22.0",
"block2",
- "cookie",
"crossbeam-channel",
"dpi",
"dunce",
@@ -6295,8 +7147,7 @@ dependencies = [
"sha2",
"soup3",
"tao-macros",
- "thiserror 1.0.69",
- "url",
+ "thiserror 1.0.58",
"webkit2gtk",
"webkit2gtk-sys",
"webview2-com",
@@ -6328,14 +7179,29 @@ dependencies = [
]
[[package]]
+name = "x11rb"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12"
+dependencies = [
+ "gethostname 0.4.3",
+ "rustix",
+ "x11rb-protocol",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
+
+[[package]]
name = "xattr"
-version = "1.3.1"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
+checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
dependencies = [
"libc",
- "linux-raw-sys",
- "rustix",
]
[[package]]
@@ -6368,7 +7234,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
"synstructure",
]
@@ -6402,6 +7268,7 @@ dependencies = [
"serde_repr",
"sha1",
"static_assertions",
+ "tokio",
"tracing",
"uds_windows",
"windows-sys 0.52.0",
@@ -6437,27 +7304,6 @@ dependencies = [
]
[[package]]
-name = "zerocopy"
-version = "0.7.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
-dependencies = [
- "byteorder",
- "zerocopy-derive",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.7.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.91",
-]
-
-[[package]]
name = "zerofrom"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6474,15 +7320,15 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
"synstructure",
]
[[package]]
name = "zeroize"
-version = "1.8.1"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
[[package]]
name = "zerovec"
@@ -6503,7 +7349,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.91",
+ "syn 2.0.90",
]
[[package]]
@@ -6528,19 +7374,16 @@ dependencies = [
[[package]]
name = "zip"
-version = "2.2.2"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45"
+checksum = "fccb210625924ecbbe92f9bb497d04b167b64fe5540cec75f10b16e0c51ee92b"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"displaydoc",
- "flate2",
- "indexmap 2.7.0",
- "memchr",
- "thiserror 2.0.9",
- "zopfli",
+ "indexmap 2.2.5",
+ "thiserror 1.0.58",
]
[[package]]
@@ -6550,25 +7393,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e109e5a291403b4c1e514d39f8a22d3f98d257e691a52bb1f16051bb1ffed63e"
dependencies = [
"log",
- "thiserror 1.0.69",
+ "thiserror 1.0.58",
"zip 0.6.6",
]
[[package]]
-name = "zopfli"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
-dependencies = [
- "bumpalo",
- "crc32fast",
- "lockfree-object-pool",
- "log",
- "once_cell",
- "simd-adler32",
-]
-
-[[package]]
name = "zstd"
version = "0.11.2+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6589,11 +7418,12 @@ dependencies = [
[[package]]
name = "zstd-sys"
-version = "2.0.13+zstd.1.5.6"
+version = "2.0.8+zstd.1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
+checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
dependencies = [
"cc",
+ "libc",
"pkg-config",
]
@@ -6607,6 +7437,7 @@ dependencies = [
"enumflags2",
"serde",
"static_assertions",
+ "url",
"zvariant_derive",
]
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index cf5f6bf9..7cfe80ff 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -5,6 +5,7 @@ description = "Mod-manager for Northstar"
authors = ["https://github.com/R2NorthstarTools/FlightCore/graphs/contributors"]
license = "MIT"
repository = "https://github.com/R2NorthstarTools/FlightCore"
+default-run = "flightcore"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -15,12 +16,12 @@ edition = "2021"
# This is done to see line numbers in stack trace on sentry.io
debug = 1
-[lib]
-# The `_lib` suffix may seem redundant but it is necessary
-# to make the lib name unique and wouldn't conflict with the bin name.
-# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
-name = "tauri_app_lib"
-crate-type = ["staticlib", "cdylib", "rlib"]
+# [lib]
+# # The `_lib` suffix may seem redundant but it is necessary
+# # to make the lib name unique and wouldn't conflict with the bin name.
+# # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
+# name = "tauri_app_lib"
+# crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
@@ -29,7 +30,6 @@ tauri-build = { version = "2", features = [] }
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "2", features = [] }
-tauri-plugin-opener = "2"
tokio = { version = "1", features = ["full"] }
# Sentry (crash) logging
sentry = "0.32"
@@ -48,6 +48,8 @@ regex = "1.10"
sysinfo = "0.30.13"
# HTTP requests
reqwest = { version = "0.11", features = ["blocking"] }
+# Persistent store for settings
+tauri-plugin-store = "2"
# JSON5 parsing support (allows comments in JSON)
json5 = "0.4.1"
# Async recursion for recursive mod install
@@ -76,9 +78,29 @@ rand = "0.8.5"
octocrab = "0.38.0"
# Library for removing markdown links
remove-markdown-links = "1.0.0"
+tauri-plugin-process = "2"
+tauri-plugin-notification = "2"
+tauri-plugin-http = "2"
+tauri-plugin-dialog = "2"
+tauri-plugin-shell = "2"
+tauri-plugin-clipboard-manager = "2.2.0"
+tauri-plugin-fs = "2"
+tauri-plugin-os = "2"
[target.'cfg(windows)'.dependencies]
# Windows API stuff
winapi = "0.3.9"
winreg = "0.52.0"
+
+[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
+tauri-plugin-global-shortcut = "2"
+tauri-plugin-updater = "2"
+
+[features]
+# 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
+default = ["custom-protocol"]
+# this feature is used used for production builds where `devPath` points to the filesystem
+# DO NOT remove this
+custom-protocol = ["tauri/custom-protocol"]
diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json
deleted file mode 100644
index 4cdbf49a..00000000
--- a/src-tauri/capabilities/default.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "$schema": "../gen/schemas/desktop-schema.json",
- "identifier": "default",
- "description": "Capability for the main window",
- "windows": ["main"],
- "permissions": [
- "core:default",
- "opener:default"
- ]
-}
diff --git a/src-tauri/capabilities/desktop.json b/src-tauri/capabilities/desktop.json
new file mode 100644
index 00000000..ddf38d00
--- /dev/null
+++ b/src-tauri/capabilities/desktop.json
@@ -0,0 +1,15 @@
+{
+ "identifier": "desktop-capability",
+ "platforms": [
+ "macOS",
+ "windows",
+ "linux"
+ ],
+ "windows": [
+ "main"
+ ],
+ "permissions": [
+ "global-shortcut:default",
+ "updater:default"
+ ]
+} \ No newline at end of file
diff --git a/src-tauri/capabilities/migrated.json b/src-tauri/capabilities/migrated.json
new file mode 100644
index 00000000..608d34ba
--- /dev/null
+++ b/src-tauri/capabilities/migrated.json
@@ -0,0 +1,82 @@
+{
+ "identifier": "migrated",
+ "description": "permissions that were migrated from v1",
+ "local": true,
+ "windows": [
+ "main"
+ ],
+ "permissions": [
+ "core:default",
+ "fs:allow-read-file",
+ "fs:allow-write-file",
+ "fs:allow-read-dir",
+ "fs:allow-copy-file",
+ "fs:allow-mkdir",
+ "fs:allow-remove",
+ "fs:allow-remove",
+ "fs:allow-rename",
+ "fs:allow-exists",
+ "core:window:allow-create",
+ "core:window:allow-center",
+ "core:window:allow-request-user-attention",
+ "core:window:allow-set-resizable",
+ "core:window:allow-set-maximizable",
+ "core:window:allow-set-minimizable",
+ "core:window:allow-set-closable",
+ "core:window:allow-set-title",
+ "core:window:allow-maximize",
+ "core:window:allow-unmaximize",
+ "core:window:allow-minimize",
+ "core:window:allow-unminimize",
+ "core:window:allow-show",
+ "core:window:allow-hide",
+ "core:window:allow-close",
+ "core:window:allow-set-decorations",
+ "core:window:allow-set-always-on-top",
+ "core:window:allow-set-content-protected",
+ "core:window:allow-set-size",
+ "core:window:allow-set-min-size",
+ "core:window:allow-set-max-size",
+ "core:window:allow-set-position",
+ "core:window:allow-set-fullscreen",
+ "core:window:allow-set-focus",
+ "core:window:allow-set-icon",
+ "core:window:allow-set-skip-taskbar",
+ "core:window:allow-set-cursor-grab",
+ "core:window:allow-set-cursor-visible",
+ "core:window:allow-set-cursor-icon",
+ "core:window:allow-set-cursor-position",
+ "core:window:allow-set-ignore-cursor-events",
+ "core:window:allow-start-dragging",
+ "core:webview:allow-print",
+ "shell:allow-execute",
+ "shell:allow-open",
+ "dialog:allow-open",
+ "dialog:allow-save",
+ "dialog:allow-message",
+ "dialog:allow-ask",
+ "dialog:allow-confirm",
+ "http:default",
+ "notification:default",
+ "global-shortcut:allow-is-registered",
+ "global-shortcut:allow-register",
+ "global-shortcut:allow-register-all",
+ "global-shortcut:allow-unregister",
+ "global-shortcut:allow-unregister-all",
+ "os:allow-platform",
+ "os:allow-version",
+ "os:allow-os-type",
+ "os:allow-family",
+ "os:allow-arch",
+ "os:allow-exe-extension",
+ "os:allow-locale",
+ "os:allow-hostname",
+ "process:allow-restart",
+ "process:allow-exit",
+ "clipboard-manager:allow-read-text",
+ "clipboard-manager:allow-write-text",
+ "core:app:allow-app-show",
+ "core:app:allow-app-hide",
+ "process:default"
+ ]
+} \ No newline at end of file
diff --git a/src-tauri/src/constants.rs b/src-tauri/src/constants.rs
new file mode 100644
index 00000000..3ad2d6e8
--- /dev/null
+++ b/src-tauri/src/constants.rs
@@ -0,0 +1,60 @@
+// This file stores various global constants values
+use const_format::concatcp;
+use std::time::Duration;
+
+/// FlightCore user agent for web requests
+pub const APP_USER_AGENT: &str = concatcp!("FlightCore/", env!("CARGO_PKG_VERSION"));
+
+/// URL of the Northstar masterserver
+pub const MASTER_SERVER_URL: &str = "https://northstar.tf";
+
+/// server list endpoint
+pub const SERVER_BROWSER_ENDPOINT: &str = "/client/servers";
+
+/// List of core Northstar mods
+pub const CORE_MODS: [&str; 3] = [
+ "Northstar.Client",
+ "Northstar.Custom",
+ "Northstar.CustomServers",
+];
+
+/// List of Thunderstoremods that shouldn't be installable
+/// as they behave different than common Squirrel mods
+pub const BLACKLISTED_MODS: [&str; 3] = [
+ "northstar-Northstar",
+ "northstar-NorthstarReleaseCandidate",
+ "ebkr-r2modman",
+];
+
+/// List of Thunderstoremods that have some specific install requirements that makes them different from standard mods
+pub const MODS_WITH_SPECIAL_REQUIREMENTS: [&str; 1] = ["NanohmProtogen-VanillaPlus"];
+
+/// Order in which the sections for release notes should be displayed
+pub const SECTION_ORDER: [&str; 11] = [
+ "feat", "fix", "docs", "style", "refactor", "build", "test", "i18n", "ci", "chore", "other",
+];
+
+/// Statistics (players and servers counts) refresh delay
+pub const REFRESH_DELAY: Duration = Duration::from_secs(5 * 60);
+
+/// Flightcore repo name and org name on GitHub
+pub const FLIGHTCORE_REPO_NAME: &str = "R2NorthstarTools/FlightCore";
+
+/// Northstar release repo name and org name on GitHub
+pub const NORTHSTAR_RELEASE_REPO_NAME: &str = "R2Northstar/Northstar";
+
+/// NorthstarLauncher repo name on GitHub
+pub const NORTHSTAR_LAUNCHER_REPO_NAME: &str = "NorthstarLauncher";
+
+/// NorthstarMods repo name on GitHub
+pub const NORTHSTAR_MODS_REPO_NAME: &str = "NorthstarMods";
+
+/// URL to launcher commits API URL
+pub const NS_LAUNCHER_COMMITS_API_URL: &str =
+ "https://api.github.com/repos/R2Northstar/NorthstarLauncher/commits";
+
+/// Filename of DLL that Northstar uses
+pub const NORTHSTAR_DLL: &str = "Northstar.dll";
+
+/// Profile that Northstar defaults to and ships with
+pub const NORTHSTAR_DEFAULT_PROFILE: &str = "R2Northstar";
diff --git a/src-tauri/src/development/mod.rs b/src-tauri/src/development/mod.rs
new file mode 100644
index 00000000..7184904c
--- /dev/null
+++ b/src-tauri/src/development/mod.rs
@@ -0,0 +1,84 @@
+use crate::constants::NS_LAUNCHER_COMMITS_API_URL;
+use crate::github::{
+ pull_requests::{check_github_api, download_zip_into_memory, get_launcher_download_link},
+ CommitInfo,
+};
+
+#[tauri::command]
+pub async fn install_git_main(game_install_path: &str) -> Result<String, String> {
+ // Get list of commits
+ let commits: Vec<CommitInfo> = serde_json::from_value(
+ check_github_api(NS_LAUNCHER_COMMITS_API_URL)
+ .await
+ .expect("Failed request"),
+ )
+ .unwrap();
+
+ // Get latest commit...
+ let latest_commit_sha = commits[0].sha.clone();
+ // ...and according artifact download URL
+ let download_url = get_launcher_download_link(latest_commit_sha.clone()).await?;
+
+ let archive = match download_zip_into_memory(download_url).await {
+ Ok(archive) => archive,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ let extract_directory = format!(
+ "{}/___flightcore-temp/download-dir/launcher-pr-{}",
+ game_install_path, latest_commit_sha
+ );
+ match std::fs::create_dir_all(extract_directory.clone()) {
+ Ok(_) => (),
+ Err(err) => {
+ return Err(format!(
+ "Failed creating temporary download directory: {}",
+ err
+ ))
+ }
+ };
+
+ let target_dir = std::path::PathBuf::from(extract_directory.clone()); // Doesn't need to exist
+ match zip_extract::extract(std::io::Cursor::new(archive), &target_dir, true) {
+ Ok(()) => (),
+ Err(err) => {
+ return Err(format!("Failed unzip: {}", err));
+ }
+ };
+
+ // Copy only necessary files from temp dir
+ // Copy:
+ // - NorthstarLauncher.exe
+ // - Northstar.dll
+ let files_to_copy = vec!["NorthstarLauncher.exe", "Northstar.dll"];
+ for file_name in files_to_copy {
+ let source_file_path = format!("{}/{}", extract_directory, file_name);
+ let destination_file_path = format!("{}/{}", game_install_path, file_name);
+ match std::fs::copy(source_file_path, destination_file_path) {
+ Ok(_result) => (),
+ Err(err) => {
+ return Err(format!(
+ "Failed to copy necessary file {} from temp dir: {}",
+ file_name, err
+ ))
+ }
+ };
+ }
+
+ // delete extract directory
+ match std::fs::remove_dir_all(&extract_directory) {
+ Ok(()) => (),
+ Err(err) => {
+ return Err(format!(
+ "Failed to delete temporary download directory: {}",
+ err
+ ))
+ }
+ }
+
+ log::info!(
+ "All done with installing launcher from {}",
+ latest_commit_sha
+ );
+ Ok(latest_commit_sha)
+}
diff --git a/src-tauri/src/github/mod.rs b/src-tauri/src/github/mod.rs
new file mode 100644
index 00000000..9bc3f834
--- /dev/null
+++ b/src-tauri/src/github/mod.rs
@@ -0,0 +1,312 @@
+pub mod pull_requests;
+pub mod release_notes;
+
+use crate::constants::{
+ APP_USER_AGENT, FLIGHTCORE_REPO_NAME, NORTHSTAR_RELEASE_REPO_NAME, SECTION_ORDER,
+};
+use regex::Regex;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use ts_rs::TS;
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct Tag {
+ name: String,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)]
+#[ts(export)]
+pub enum Project {
+ FlightCore,
+ Northstar,
+}
+
+/// Wrapper type needed for frontend
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct TagWrapper {
+ label: String,
+ value: Tag,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct CommitInfo {
+ pub sha: String,
+ commit: Commit,
+ author: Option<CommitAuthor>,
+}
+
+#[derive(Debug, Deserialize)]
+struct Commit {
+ message: String,
+}
+
+#[derive(Debug, Deserialize)]
+struct CommitAuthor {
+ login: String,
+}
+
+#[derive(Debug, Deserialize)]
+struct Comparison {
+ commits: Vec<CommitInfo>,
+}
+
+/// Get a list of tags on the FlightCore repo
+#[tauri::command]
+pub fn get_list_of_tags(project: Project) -> Result<Vec<TagWrapper>, String> {
+ // Set the repository name.
+
+ // Create a `reqwest` client with a user agent.
+ let client = reqwest::blocking::Client::builder()
+ .user_agent(APP_USER_AGENT)
+ .build()
+ .unwrap();
+
+ // Switch repo to fetch from based on project
+ let repo_name = match project {
+ Project::FlightCore => FLIGHTCORE_REPO_NAME,
+ Project::Northstar => NORTHSTAR_RELEASE_REPO_NAME,
+ };
+
+ // Fetch the list of tags for the repository as a `Vec<Tag>`.
+ let tags_url = format!("https://api.github.com/repos/{}/tags", repo_name);
+ let tags: Vec<Tag> = client.get(tags_url).send().unwrap().json().unwrap();
+
+ // Map each `Tag` element to a `TagWrapper` element with the desired label and `Tag` value.
+ let tag_wrappers: Vec<TagWrapper> = tags
+ .into_iter()
+ .map(|tag| TagWrapper {
+ label: tag.name.clone(),
+ value: tag,
+ })
+ .collect();
+
+ Ok(tag_wrappers)
+}
+
+/// Use GitHub API to compare two tags of the same repo against each other and get the resulting changes
+#[tauri::command]
+pub fn compare_tags(project: Project, first_tag: Tag, second_tag: Tag) -> Result<String, String> {
+ match project {
+ Project::FlightCore => compare_tags_flightcore(first_tag, second_tag),
+ Project::Northstar => compare_tags_northstar(first_tag, second_tag),
+ }
+}
+
+pub fn compare_tags_flightcore(first_tag: Tag, second_tag: Tag) -> Result<String, String> {
+ // Fetch the list of commits between the two tags.
+
+ // Create a `reqwest` client with a user agent.
+ let client = reqwest::blocking::Client::builder()
+ .user_agent(APP_USER_AGENT)
+ .build()
+ .unwrap();
+
+ let repo = "R2NorthstarTools/FlightCore";
+
+ let mut full_patch_notes = "".to_string();
+
+ let mut patch_notes: Vec<String> = [].to_vec();
+ println!("{}", repo);
+ // let repo = "R2Northstar/NorthstarLauncher";
+ let comparison_url = format!(
+ "https://api.github.com/repos/{}/compare/{}...{}",
+ repo, first_tag.name, second_tag.name
+ );
+
+ let comparison: Comparison = client.get(comparison_url).send().unwrap().json().unwrap();
+ let commits = comparison.commits;
+
+ // Display the list of commits.
+ println!(
+ "Commits between {} and {}:",
+ first_tag.name, second_tag.name
+ );
+
+ // Iterate over all commits in the diff
+ for commit in commits {
+ println!(
+ " * {} : {}",
+ commit.sha,
+ commit.commit.message.split('\n').next().unwrap()
+ );
+ patch_notes.push(
+ commit
+ .commit
+ .message
+ .split('\n')
+ .next()
+ .unwrap()
+ .to_string(),
+ );
+ }
+
+ full_patch_notes += &generate_flightcore_release_notes(patch_notes);
+
+ Ok(full_patch_notes.to_string())
+}
+
+/// Generate release notes in the format used for FlightCore
+fn generate_flightcore_release_notes(commits: Vec<String>) -> String {
+ let grouped_commits = group_commits_by_type(commits);
+ let mut release_notes = String::new();
+
+ // Go over commit types and generate notes
+ for commit_type in SECTION_ORDER {
+ if let Some(commit_list) = grouped_commits.get(commit_type) {
+ if !commit_list.is_empty() {
+ let section_title = match commit_type {
+ "feat" => "**Features:**",
+ "fix" => "**Bug Fixes:**",
+ "docs" => "**Documentation:**",
+ "style" => "**Code style changes:**",
+ "refactor" => "**Code Refactoring:**",
+ "build" => "**Build:**",
+ "ci" => "**Continuous integration changes:**",
+ "test" => "**Tests:**",
+ "chore" => "**Chores:**",
+ "i18n" => "**Translations:**",
+ _ => "**Other:**",
+ };
+
+ release_notes.push_str(&format!("{}\n", section_title));
+
+ for commit_message in commit_list {
+ release_notes.push_str(&format!("- {}\n", commit_message));
+ }
+
+ release_notes.push('\n');
+ }
+ }
+ }
+
+ let release_notes = release_notes.trim_end_matches('\n').to_string();
+ release_notes
+}
+
+/// Group semantic commit messages by type
+/// Commmit messages that are not formatted accordingly are marked as "other"
+fn group_commits_by_type(commits: Vec<String>) -> HashMap<String, Vec<String>> {
+ let mut grouped_commits: HashMap<String, Vec<String>> = HashMap::new();
+ let mut other_commits: Vec<String> = vec![];
+
+ for commit in commits {
+ let commit_parts: Vec<&str> = commit.splitn(2, ':').collect();
+ if commit_parts.len() == 2 {
+ let commit_type = commit_parts[0].to_lowercase();
+ let commit_description = commit_parts[1].trim().to_string();
+
+ // Check if known commit type
+ if SECTION_ORDER.contains(&commit_type.as_str()) {
+ let commit_list = grouped_commits.entry(commit_type.to_string()).or_default();
+ commit_list.push(commit_description);
+ } else {
+ // otherwise add to list of "other"
+ other_commits.push(commit.to_string());
+ }
+ } else {
+ other_commits.push(commit.to_string());
+ }
+ }
+ grouped_commits.insert("other".to_string(), other_commits);
+
+ grouped_commits
+}
+
+/// Compares two tags on Northstar repo and generates release notes over the diff in tags
+/// over the 3 major repos (Northstar, NorthstarLauncher, NorthstarMods)
+pub fn compare_tags_northstar(first_tag: Tag, second_tag: Tag) -> Result<String, String> {
+ // Fetch the list of commits between the two tags.
+
+ // Create a `reqwest` client with a user agent.
+ let client = reqwest::blocking::Client::builder()
+ .user_agent(APP_USER_AGENT)
+ .build()
+ .unwrap();
+
+ let repos = [
+ "R2Northstar/Northstar",
+ "R2Northstar/NorthstarLauncher",
+ "R2Northstar/NorthstarMods",
+ ];
+
+ let mut full_patch_notes = "".to_string();
+ let mut authors_set = std::collections::HashSet::new();
+
+ for repo in repos {
+ full_patch_notes += &format!("{}\n\n", repo);
+
+ let mut patch_notes: Vec<String> = [].to_vec();
+ println!("{}", repo);
+ // let repo = "R2Northstar/NorthstarLauncher";
+ let comparison_url = format!(
+ "https://api.github.com/repos/{}/compare/{}...{}",
+ repo, first_tag.name, second_tag.name
+ );
+
+ log::info!("Compare URL: {}", comparison_url.clone());
+ let comparison: Comparison = client.get(&comparison_url).send().unwrap().json().unwrap();
+ let commits = comparison.commits;
+
+ // Display the list of commits.
+ println!(
+ "Commits between {} and {}:",
+ first_tag.name, second_tag.name
+ );
+
+ //
+ for commit in commits {
+ println!(
+ " * {} : {}",
+ commit.sha,
+ turn_pr_number_into_link(commit.commit.message.split('\n').next().unwrap(), repo)
+ );
+ patch_notes.push(turn_pr_number_into_link(
+ commit.commit.message.split('\n').next().unwrap(),
+ repo,
+ ));
+
+ // Store authors in set
+ if commit.author.is_some() {
+ authors_set.insert(commit.author.unwrap().login);
+ }
+ }
+
+ full_patch_notes += &patch_notes.join("\n");
+ full_patch_notes += "\n\n\n";
+ }
+
+ // Convert the set to a sorted vector.
+ let mut sorted_vec: Vec<String> = authors_set.into_iter().collect();
+ sorted_vec.sort_by_key(|a| a.to_lowercase());
+
+ // Define a string to prepend to each element.
+ let prefix = "@";
+
+ // Create a new list with the prefix prepended to each element.
+ let prefixed_list: Vec<String> = sorted_vec.iter().map(|s| prefix.to_owned() + s).collect();
+
+ full_patch_notes += "**Contributors:**\n";
+ full_patch_notes += &prefixed_list.join(" ");
+
+ Ok(full_patch_notes.to_string())
+}
+
+/// Takes the commit title and repo slug and formats it as
+/// `[commit title(SHORTENED_REPO#NUMBER)](LINK)`
+fn turn_pr_number_into_link(input: &str, repo: &str) -> String {
+ // Extract `Mods/Launcher` from repo title
+ let last_line = repo
+ .split('/')
+ .next_back()
+ .unwrap()
+ .trim_start_matches("Northstar");
+ // Extract PR number
+ let re = Regex::new(r"#(\d+)").unwrap();
+
+ // Generate pull request link
+ let pull_link = format!("https://github.com/{}/pull/", repo);
+ re.replace_all(input, format!("[{}#$1]({}$1)", last_line, pull_link))
+ .to_string()
+}
diff --git a/src-tauri/src/github/pull_requests.rs b/src-tauri/src/github/pull_requests.rs
new file mode 100644
index 00000000..de733feb
--- /dev/null
+++ b/src-tauri/src/github/pull_requests.rs
@@ -0,0 +1,398 @@
+use crate::constants::{APP_USER_AGENT, NORTHSTAR_LAUNCHER_REPO_NAME, NORTHSTAR_MODS_REPO_NAME};
+use crate::repair_and_verify::check_is_valid_game_path;
+use crate::GameInstall;
+use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
+use std::fs::File;
+use std::io;
+use std::io::prelude::*;
+use std::path::Path;
+use ts_rs::TS;
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+struct Repo {
+ full_name: String,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+struct CommitHead {
+ sha: String,
+ #[serde(rename = "ref")]
+ gh_ref: String,
+ repo: Repo,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct PullsApiResponseElement {
+ number: u64,
+ title: String,
+ url: String,
+ head: CommitHead,
+ html_url: String,
+ labels: Vec<String>,
+}
+
+// GitHub API response JSON elements as structs
+#[derive(Debug, Deserialize, Clone)]
+struct WorkflowRun {
+ id: u64,
+ head_sha: String,
+}
+#[derive(Debug, Deserialize, Clone)]
+struct ActionsRunsResponse {
+ workflow_runs: Vec<WorkflowRun>,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+struct Artifact {
+ id: u64,
+ name: String,
+ workflow_run: WorkflowRun,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+struct ArtifactsResponse {
+ artifacts: Vec<Artifact>,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub enum PullRequestType {
+ Mods,
+ Launcher,
+}
+
+/// Parse pull requests from specified URL
+pub async fn get_pull_requests(
+ repo: PullRequestType,
+) -> Result<Vec<PullsApiResponseElement>, anyhow::Error> {
+ let repo = match repo {
+ PullRequestType::Mods => NORTHSTAR_MODS_REPO_NAME,
+ PullRequestType::Launcher => NORTHSTAR_LAUNCHER_REPO_NAME,
+ };
+
+ // Grab list of PRs
+ let octocrab = octocrab::instance();
+ let page = octocrab
+ .pulls("R2Northstar", repo)
+ .list()
+ .state(octocrab::params::State::Open)
+ .per_page(50) // Only grab 50 PRs
+ .page(1u32)
+ .send()
+ .await?;
+
+ // Iterate over pull request elements and insert into struct
+ let mut all_pull_requests: Vec<PullsApiResponseElement> = vec![];
+ for item in page.items {
+ let repo = Repo {
+ full_name: item
+ .head
+ .repo
+ .ok_or(anyhow!("repo not found"))?
+ .full_name
+ .ok_or(anyhow!("full_name not found"))?,
+ };
+
+ let head = CommitHead {
+ sha: item.head.sha,
+ gh_ref: item.head.ref_field,
+ repo,
+ };
+
+ // Get labels and their names and put the into vector
+ let label_names: Vec<String> = item
+ .labels
+ .unwrap_or_else(Vec::new)
+ .into_iter()
+ .map(|label| label.name)
+ .collect();
+
+ // TODO there's probably a way to automatically serialize into the struct but I don't know yet how to
+ let elem = PullsApiResponseElement {
+ number: item.number,
+ title: item.title.ok_or(anyhow!("title not found"))?,
+ url: item.url,
+ head,
+ html_url: item
+ .html_url
+ .ok_or(anyhow!("html_url not found"))?
+ .to_string(),
+ labels: label_names,
+ };
+
+ all_pull_requests.push(elem);
+ }
+
+ Ok(all_pull_requests)
+}
+
+/// Gets either launcher or mods PRs
+#[tauri::command]
+pub async fn get_pull_requests_wrapper(
+ install_type: PullRequestType,
+) -> Result<Vec<PullsApiResponseElement>, String> {
+ match get_pull_requests(install_type).await {
+ Ok(res) => Ok(res),
+ Err(err) => Err(err.to_string()),
+ }
+}
+
+pub async fn check_github_api(url: &str) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
+ let client = reqwest::Client::new();
+ let res = client
+ .get(url)
+ .header(reqwest::header::USER_AGENT, APP_USER_AGENT)
+ .send()
+ .await
+ .unwrap()
+ .text()
+ .await
+ .unwrap();
+
+ let json: serde_json::Value = serde_json::from_str(&res).expect("JSON was not well-formatted");
+
+ Ok(json)
+}
+
+/// Downloads a file from given URL into an array in memory
+pub async fn download_zip_into_memory(download_url: String) -> Result<Vec<u8>, anyhow::Error> {
+ let client = reqwest::Client::builder()
+ .user_agent(APP_USER_AGENT)
+ .build()?;
+
+ let response = client.get(download_url).send().await?;
+
+ if !response.status().is_success() {
+ return Err(anyhow!("Request unsuccessful: {}", response.status()));
+ }
+
+ let bytes = response.bytes().await?;
+ Ok(bytes.to_vec())
+}
+
+/// Gets GitHub download link of a mods PR
+fn get_mods_download_link(pull_request: PullsApiResponseElement) -> Result<String, anyhow::Error> {
+ // {pr object} -> number == pr_number
+ // -> head -> ref
+ // -> repo -> full_name
+
+ // Use repo and branch name to get download link
+ let download_url = format!(
+ "https://github.com/{}/archive/refs/heads/{}.zip",
+ pull_request.head.repo.full_name, // repo name
+ pull_request.head.gh_ref, // branch name
+ );
+
+ Ok(download_url)
+}
+
+/// Gets `nightly.link` artifact download link of a launcher commit
+#[tauri::command]
+pub async fn get_launcher_download_link(commit_sha: String) -> Result<String, String> {
+ // Iterate over the first 10 pages of
+ for i in 1..=10 {
+ // Crossreference with runs API
+ let runs_response: ActionsRunsResponse = match check_github_api(&format!(
+ "https://api.github.com/repos/R2Northstar/NorthstarLauncher/actions/runs?page={}",
+ i
+ ))
+ .await
+ {
+ Ok(result) => serde_json::from_value(result).unwrap(),
+ Err(err) => return Err(format!("{}", err)),
+ };
+
+ // Cross-reference commit sha against workflow runs
+ for workflow_run in &runs_response.workflow_runs {
+ // If head commit sha of CI run matches the one passed to this function, grab CI output
+ if workflow_run.head_sha == commit_sha {
+ // Check artifacts
+ let api_url = format!("https://api.github.com/repos/R2Northstar/NorthstarLauncher/actions/runs/{}/artifacts", workflow_run.id);
+ let artifacts_response: ArtifactsResponse = serde_json::from_value(
+ check_github_api(&api_url).await.expect("Failed request"),
+ )
+ .unwrap();
+
+ let multiple_artifacts = artifacts_response.artifacts.len() > 1;
+
+ // Iterate over artifacts
+ for artifact in artifacts_response.artifacts {
+ if multiple_artifacts && !artifact.name.starts_with("NorthstarLauncher-MSVC") {
+ continue;
+ }
+
+ // Make sure artifact and CI run commit head sha match
+ if artifact.workflow_run.head_sha == workflow_run.head_sha {
+ // Download artifact
+ return Ok(format!("https://nightly.link/R2Northstar/NorthstarLauncher/actions/artifacts/{}.zip", artifact.id));
+ }
+ }
+ }
+ }
+ }
+
+ Err(format!(
+ "Couldn't grab download link for \"{}\". Corresponding PR might be too old and therefore no CI build has been detected. Maybe ask author to update?",
+ commit_sha
+ ))
+}
+
+/// Adds a batch file that allows for launching Northstar with mods PR profile
+fn add_batch_file(game_install_path: &str) {
+ let batch_path = format!("{}/r2ns-launch-mod-pr-version.bat", game_install_path);
+ let path = Path::new(&batch_path);
+ let display = path.display();
+
+ // Open a file in write-only mode, returns `io::Result<File>`
+ let mut file = match File::create(path) {
+ Err(why) => panic!("couldn't create {}: {}", display, why),
+ Ok(file) => file,
+ };
+
+ // Write the string to `file`, returns `io::Result<()>`
+ let batch_file_content =
+ "NorthstarLauncher.exe -profile=R2Northstar-PR-test-managed-folder\r\n";
+
+ match file.write_all(batch_file_content.as_bytes()) {
+ Err(why) => panic!("couldn't write to {}: {}", display, why),
+ Ok(_) => log::info!("successfully wrote to {}", display),
+ }
+}
+
+/// Downloads selected launcher PR and extracts it into game install path
+#[tauri::command]
+pub async fn apply_launcher_pr(
+ pull_request: PullsApiResponseElement,
+ game_install: GameInstall,
+) -> Result<(), String> {
+ // Exit early if wrong game path
+ check_is_valid_game_path(&game_install.game_path)?;
+
+ // get download link
+ let download_url = match get_launcher_download_link(pull_request.head.sha.clone()).await {
+ Ok(res) => res,
+ Err(err) => {
+ return Err(format!(
+ "Couldn't grab download link for PR \"{}\". {}",
+ pull_request.number, err
+ ))
+ }
+ };
+
+ let archive = match download_zip_into_memory(download_url).await {
+ Ok(archive) => archive,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ let extract_directory = format!(
+ "{}/___flightcore-temp/download-dir/launcher-pr-{}",
+ game_install.game_path, pull_request.number
+ );
+ match std::fs::create_dir_all(extract_directory.clone()) {
+ Ok(_) => (),
+ Err(err) => {
+ return Err(format!(
+ "Failed creating temporary download directory: {}",
+ err
+ ))
+ }
+ };
+
+ let target_dir = std::path::PathBuf::from(extract_directory.clone()); // Doesn't need to exist
+ match zip_extract::extract(io::Cursor::new(archive), &target_dir, true) {
+ Ok(()) => (),
+ Err(err) => {
+ return Err(format!("Failed unzip: {}", err));
+ }
+ };
+
+ // Copy only necessary files from temp dir
+ // Copy:
+ // - NorthstarLauncher.exe
+ // - Northstar.dll
+ let files_to_copy = vec!["NorthstarLauncher.exe", "Northstar.dll"];
+ for file_name in files_to_copy {
+ let source_file_path = format!("{}/{}", extract_directory, file_name);
+ let destination_file_path = format!("{}/{}", game_install.game_path, file_name);
+ match std::fs::copy(source_file_path, destination_file_path) {
+ Ok(_result) => (),
+ Err(err) => {
+ return Err(format!(
+ "Failed to copy necessary file {} from temp dir: {}",
+ file_name, err
+ ))
+ }
+ };
+ }
+
+ // delete extract directory
+ match std::fs::remove_dir_all(&extract_directory) {
+ Ok(()) => (),
+ Err(err) => {
+ return Err(format!(
+ "Failed to delete temporary download directory: {}",
+ err
+ ))
+ }
+ }
+
+ log::info!("All done with installing launcher PR");
+ Ok(())
+}
+
+/// Downloads selected mods PR and extracts it into profile in game install path
+#[tauri::command]
+pub async fn apply_mods_pr(
+ pull_request: PullsApiResponseElement,
+ game_install: GameInstall,
+) -> Result<(), String> {
+ // Exit early if wrong game path
+ check_is_valid_game_path(&game_install.game_path)?;
+
+ let download_url = match get_mods_download_link(pull_request) {
+ Ok(url) => url,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ let archive = match download_zip_into_memory(download_url).await {
+ Ok(archive) => archive,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ let profile_folder = format!(
+ "{}/R2Northstar-PR-test-managed-folder",
+ game_install.game_path
+ );
+
+ // Delete previously managed folder
+ if std::fs::remove_dir_all(profile_folder.clone()).is_err() {
+ if std::path::Path::new(&profile_folder).exists() {
+ log::error!("Failed removing previous dir");
+ } else {
+ log::warn!("Failed removing folder that doesn't exist. Probably cause first run");
+ }
+ };
+
+ // Create profile folder
+ match std::fs::create_dir_all(profile_folder.clone()) {
+ Ok(()) => (),
+ Err(err) => return Err(err.to_string()),
+ }
+
+ let target_dir = std::path::PathBuf::from(format!("{}/mods", profile_folder)); // Doesn't need to exist
+ match zip_extract::extract(io::Cursor::new(archive), &target_dir, true) {
+ Ok(()) => (),
+ Err(err) => {
+ return Err(format!("Failed unzip: {}", err));
+ }
+ };
+ // Add batch file to launch right profile
+ add_batch_file(&game_install.game_path);
+
+ log::info!("All done with installing mods PR");
+ Ok(())
+}
diff --git a/src-tauri/src/github/release_notes.rs b/src-tauri/src/github/release_notes.rs
new file mode 100644
index 00000000..4adfb24b
--- /dev/null
+++ b/src-tauri/src/github/release_notes.rs
@@ -0,0 +1,244 @@
+use rand::prelude::SliceRandom;
+use serde::{Deserialize, Serialize};
+use std::vec::Vec;
+use ts_rs::TS;
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct ReleaseInfo {
+ pub name: String,
+ pub published_at: String,
+ pub body: String,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct FlightCoreVersion {
+ tag_name: String,
+ published_at: String,
+}
+
+/// Gets newest FlighCore version from GitHub
+#[tauri::command]
+pub async fn get_newest_flightcore_version() -> Result<FlightCoreVersion, String> {
+ // Get newest version number from GitHub API
+ log::info!("Checking GitHub API");
+ let octocrab = octocrab::instance();
+ let page = octocrab
+ .repos("R2NorthstarTools", "FlightCore")
+ .releases()
+ .list()
+ // Optional Parameters
+ .per_page(1)
+ .page(1u32)
+ // Send the request
+ .send()
+ .await
+ .map_err(|err| err.to_string())?;
+
+ // Get newest element
+ let latest_release_item = &page.items[0];
+
+ let flightcore_version = FlightCoreVersion {
+ tag_name: latest_release_item.tag_name.clone(),
+ published_at: latest_release_item.published_at.unwrap().to_rfc3339(),
+ };
+ log::info!("Done checking GitHub API");
+
+ Ok(flightcore_version)
+}
+
+/// Checks if installed FlightCore version is up-to-date
+/// false -> FlightCore install is up-to-date
+/// true -> FlightCore install is outdated
+#[tauri::command]
+pub async fn check_is_flightcore_outdated() -> Result<bool, String> {
+ let newest_flightcore_release = get_newest_flightcore_version().await?;
+ // Parse version number excluding leading `v`
+ let newest_version = semver::Version::parse(&newest_flightcore_release.tag_name[1..]).unwrap();
+
+ // Get version of installed FlightCore
+ let current_version = env!("CARGO_PKG_VERSION");
+ let current_version = semver::Version::parse(current_version).unwrap();
+
+ #[cfg(debug_assertions)]
+ let is_outdated = current_version < newest_version;
+ #[cfg(not(debug_assertions))]
+ let is_outdated = current_version != newest_version;
+
+ // If outdated, check how new the update is
+ if is_outdated {
+ // Time to wait (2h) h * m * s
+ let threshold_seconds = 2 * 60 * 60;
+
+ // Get current time
+ let current_time = chrono::Utc::now();
+
+ // Get latest release time from GitHub API response
+ let result = chrono::DateTime::parse_from_rfc3339(&newest_flightcore_release.published_at)
+ .unwrap()
+ .with_timezone(&chrono::Utc);
+
+ // Check if current time is outside of threshold
+ let diff = current_time - result;
+ if diff.num_seconds() < threshold_seconds {
+ // User would be outdated but the newest release is recent
+ // therefore we do not wanna show outdated warning.
+ return Ok(false);
+ }
+ return Ok(true);
+ }
+
+ Ok(is_outdated)
+}
+
+#[tauri::command]
+pub async fn get_northstar_release_notes() -> Result<Vec<ReleaseInfo>, String> {
+ let octocrab = octocrab::instance();
+ let page = octocrab
+ .repos("R2Northstar", "Northstar")
+ .releases()
+ .list()
+ // Optional Parameters
+ .per_page(25)
+ .page(1u32)
+ // Send the request
+ .send()
+ .await
+ .map_err(|err| err.to_string())?;
+
+ // TODO there's probably a way to automatically serialize into the struct but I don't know yet how to
+ let mut release_info_vector: Vec<ReleaseInfo> = vec![];
+ for item in page.items {
+ let release_info = ReleaseInfo {
+ name: item.name.ok_or(String::from("Release name not found"))?,
+ published_at: item
+ .published_at
+ .ok_or(String::from("Release date not found"))?
+ .to_rfc3339(),
+ body: item.body.ok_or(String::from("Release body not found"))?,
+ };
+ release_info_vector.push(release_info);
+ }
+
+ log::info!("Done checking GitHub API");
+
+ Ok(release_info_vector)
+}
+
+/// Checks latest GitHub release and generates a announcement message for Discord based on it
+#[tauri::command]
+pub async fn generate_release_note_announcement() -> Result<String, String> {
+ let octocrab = octocrab::instance();
+ let page = octocrab
+ .repos("R2Northstar", "Northstar")
+ .releases()
+ .list()
+ // Optional Parameters
+ .per_page(1)
+ .page(1u32)
+ // Send the request
+ .send()
+ .await
+ .unwrap();
+
+ // Get newest element
+ let latest_release_item = &page.items[0];
+
+ // Extract the URL to the GitHub release note
+ let github_release_link = latest_release_item.html_url.clone();
+
+ // Extract release version number
+ let current_ns_version = &latest_release_item.tag_name;
+
+ // Extract changelog and format it
+ let changelog = remove_markdown_links::remove_markdown_links(
+ latest_release_item
+ .body
+ .as_ref()
+ .unwrap()
+ .split("**Contributors:**")
+ .next()
+ .unwrap()
+ .trim(),
+ );
+
+ // Strings to insert for different sections
+ // Hardcoded for now
+ let general_info = "REPLACE ME";
+ let modders_info = "Mod compatibility should not be impacted";
+ let server_hosters_info = "REPLACE ME";
+
+ let mut rng = rand::thread_rng();
+ let attributes = vec![
+ "adorable",
+ "amazing",
+ "beautiful",
+ "blithsome",
+ "brilliant",
+ "compassionate",
+ "dazzling",
+ "delightful",
+ "distinguished",
+ "elegant",
+ "enigmatic",
+ "enthusiastic",
+ "fashionable",
+ "fortuitous",
+ "friendly",
+ "generous",
+ "gleeful",
+ "gorgeous",
+ "handsome",
+ "lively",
+ "lovely",
+ "lucky",
+ "lustrous",
+ "marvelous",
+ "merry",
+ "mirthful",
+ "phantasmagorical",
+ "pretty",
+ "propitious",
+ "ravishing",
+ "sincere",
+ "sophisticated fellow",
+ "stupendous",
+ "vivacious",
+ "wonderful",
+ "zestful",
+ ];
+
+ let selected_attribute = attributes.choose(&mut rng).unwrap();
+
+ // Build announcement string
+ let return_string = format!(
+ r"Hello {selected_attribute} people <3
+**Northstar `{current_ns_version}` is out!**
+
+{general_info}
+
+__**Modders:**__
+
+{modders_info}
+
+__**Server hosters:**__
+
+{server_hosters_info}
+
+__**Changelog:**__
+```
+{changelog}
+```
+{github_release_link}
+
+Checkout #installation on how to install/update Northstar
+(the process is the same for both, using a Northstar installer like FlightCore, Viper, or VTOL is recommended over manual installation)
+
+If you do notice any bugs, please open an issue on Github or drop a message in the thread below
+"
+ );
+
+ // Return built announcement message
+ Ok(return_string.to_string())
+}
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 4a277ef3..8ef645f1 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -1,14 +1,233 @@
-// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
-#[tauri::command]
-fn greet(name: &str) -> String {
- format!("Hello, {}! You've been greeted from Rust!", name)
+#![cfg_attr(
+ all(not(debug_assertions), target_os = "windows"),
+ windows_subsystem = "windows"
+)]
+
+use std::{env, time::Duration};
+
+mod constants;
+mod development;
+mod github;
+mod mod_management;
+mod northstar;
+mod platform_specific;
+mod repair_and_verify;
+mod thunderstore;
+mod util;
+
+use serde::{Deserialize, Serialize};
+#[cfg(target_os = "windows")]
+use tauri::api::dialog::blocking::MessageDialogBuilder;
+#[cfg(target_os = "windows")]
+use tauri::api::dialog::{MessageDialogButtons, MessageDialogKind};
+use tauri::Manager;
+use tokio::time::sleep;
+use ts_rs::TS;
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+struct NorthstarThunderstoreRelease {
+ package: String,
+ version: String,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct NorthstarThunderstoreReleaseWrapper {
+ label: String,
+ value: NorthstarThunderstoreRelease,
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
- tauri::Builder::default()
- .plugin(tauri_plugin_opener::init())
- .invoke_handler(tauri::generate_handler![greet])
- .run(tauri::generate_context!())
- .expect("error while running tauri application");
+ // Setup logger
+ let mut log_builder = pretty_env_logger::formatted_builder();
+ log_builder.parse_filters("info");
+ let logger = sentry_log::SentryLogger::with_dest(log_builder.build());
+
+ log::set_boxed_logger(Box::new(logger)).unwrap();
+ log::set_max_level(log::LevelFilter::Info);
+
+ // Only enable Sentry crash logs on release
+ #[cfg(not(debug_assertions))]
+ let _guard = sentry::init((
+ "https://f833732deb2240b0b2dc4abce97d0f1d@o1374052.ingest.sentry.io/6692177",
+ sentry::ClientOptions {
+ release: sentry::release_name!(),
+ attach_stacktrace: true,
+ ..Default::default()
+ },
+ ));
+
+ let tauri_builder_res = tauri::Builder::default()
+ .plugin(tauri_plugin_os::init())
+ .plugin(tauri_plugin_fs::init())
+ .plugin(tauri_plugin_clipboard_manager::init())
+ .plugin(tauri_plugin_shell::init())
+ .plugin(tauri_plugin_dialog::init())
+ .plugin(tauri_plugin_http::init())
+ .plugin(tauri_plugin_notification::init())
+ .plugin(tauri_plugin_store::Builder::new().build())
+ .plugin(tauri_plugin_updater::Builder::new().build())
+ .plugin(tauri_plugin_global_shortcut::Builder::new().build())
+ .plugin(tauri_plugin_process::init())
+ .plugin(tauri_plugin_store::Builder::default().build())
+ .setup(|app| {
+ let app_handle = app.app_handle();
+ tauri::async_runtime::spawn(async move {
+ loop {
+ sleep(Duration::from_millis(2000)).await;
+ // println!("sending backend ping");
+ app_handle.emit_all("backend-ping", "ping").unwrap();
+ }
+ });
+ let app_handle = app.app_handle();
+ tauri::async_runtime::spawn(async move {
+ loop {
+ sleep(Duration::from_millis(2000)).await;
+ app_handle
+ .emit_all(
+ "ea-app-running-ping",
+ util::check_ea_app_or_origin_running(),
+ )
+ .unwrap();
+ }
+ });
+ let app_handle = app.app_handle();
+ tauri::async_runtime::spawn(async move {
+ loop {
+ sleep(Duration::from_millis(2000)).await;
+ app_handle
+ .emit_all("northstar-running-ping", util::check_northstar_running())
+ .unwrap();
+ }
+ });
+
+ // Emit updated player and server count to GUI
+ let app_handle = app.app_handle();
+ tauri::async_runtime::spawn(async move {
+ loop {
+ sleep(constants::REFRESH_DELAY).await;
+ app_handle
+ .emit_all(
+ "northstar-statistics",
+ util::get_server_player_count().await,
+ )
+ .unwrap();
+ }
+ });
+
+ Ok(())
+ })
+ .manage(())
+ .invoke_handler(tauri::generate_handler![
+ development::install_git_main,
+ github::compare_tags,
+ github::get_list_of_tags,
+ github::pull_requests::apply_launcher_pr,
+ github::pull_requests::apply_mods_pr,
+ github::pull_requests::get_launcher_download_link,
+ github::pull_requests::get_pull_requests_wrapper,
+ github::release_notes::check_is_flightcore_outdated,
+ github::release_notes::generate_release_note_announcement,
+ github::release_notes::get_newest_flightcore_version,
+ github::release_notes::get_northstar_release_notes,
+ mod_management::delete_northstar_mod,
+ mod_management::delete_thunderstore_mod,
+ mod_management::get_installed_mods_and_properties,
+ mod_management::install_mod_wrapper,
+ mod_management::set_mod_enabled_status,
+ northstar::check_is_northstar_outdated,
+ northstar::get_available_northstar_versions,
+ northstar::get_northstar_version_number,
+ northstar::install::find_game_install_location,
+ northstar::install::install_northstar_wrapper,
+ northstar::install::update_northstar,
+ northstar::launch_northstar,
+ northstar::profile::clone_profile,
+ northstar::profile::delete_profile,
+ northstar::profile::fetch_profiles,
+ northstar::profile::validate_profile,
+ platform_specific::check_cgnat,
+ platform_specific::get_host_os,
+ platform_specific::get_local_northstar_proton_wrapper_version,
+ platform_specific::install_northstar_proton_wrapper,
+ platform_specific::uninstall_northstar_proton_wrapper,
+ repair_and_verify::clean_up_download_folder_wrapper,
+ repair_and_verify::disable_all_but_core,
+ repair_and_verify::get_log_list,
+ repair_and_verify::verify_game_files,
+ repair_and_verify::verify_install_location,
+ thunderstore::query_thunderstore_packages_api,
+ util::close_application,
+ util::force_panic,
+ util::get_flightcore_version_number,
+ util::get_server_player_count,
+ util::is_debug_mode,
+ util::kill_northstar,
+ util::open_repair_window,
+ ])
+ .run(tauri::generate_context!());
+
+ match tauri_builder_res {
+ Ok(()) => (),
+ Err(err) => {
+ // Failed to launch system native web view
+
+ // Log error on Linux
+ #[cfg(not(target_os = "windows"))]
+ {
+ log::error!("{err}");
+ }
+
+ // On Windows we can show an error window using Windows API to show how to install WebView2
+ #[cfg(target_os = "windows")]
+ {
+ log::error!("WebView2 not installed: {err}");
+ let dialog = MessageDialogBuilder::new(
+ "WebView2 not found",
+ "FlightCore requires WebView2 to run.\n\nClick OK to open installation instructions."
+ )
+ .kind(MessageDialogKind::Error)
+ .buttons(MessageDialogButtons::Ok);
+
+ if dialog.show() {
+ // Open the installation instructions URL in the user's default web browser
+ open::that("https://github.com/R2NorthstarTools/FlightCore/blob/main/docs/TROUBLESHOOTING.md#flightcore-wont-launch").unwrap();
+ }
+ }
+ }
+ };
+}
+
+/// Defines how Titanfall2 was installed (Steam, Origin, ...)
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub enum InstallType {
+ STEAM,
+ ORIGIN,
+ EAPLAY,
+ UNKNOWN,
+}
+
+/// Object holding information of the Titanfall2 install, including
+/// - Install path
+/// - Active profile
+/// - Type of installation (Steam, Origin, ...)
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct GameInstall {
+ pub game_path: String,
+ pub profile: String,
+ pub install_type: InstallType,
+}
+
+/// Object holding various information about a Northstar mod
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct NorthstarMod {
+ pub name: String,
+ pub version: Option<String>,
+ pub thunderstore_mod_string: Option<String>,
+ pub enabled: bool,
+ pub directory: String,
}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 2abccd9e..c3623a9d 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -1,6 +1,5 @@
-// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
- tauri_app_lib::run()
+ app_lib::run();
}
diff --git a/src-tauri/src/mod_management/legacy.rs b/src-tauri/src/mod_management/legacy.rs
new file mode 100644
index 00000000..1e9f90f5
--- /dev/null
+++ b/src-tauri/src/mod_management/legacy.rs
@@ -0,0 +1,213 @@
+use crate::constants::BLACKLISTED_MODS;
+use crate::mod_management::{
+ delete_mod_folder, get_installed_mods_and_properties, ParsedThunderstoreModString,
+};
+use crate::GameInstall;
+use crate::NorthstarMod;
+use anyhow::{anyhow, Result};
+use serde::{Deserialize, Serialize};
+use std::{io::Read, path::PathBuf};
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct ModJson {
+ #[serde(rename = "Name")]
+ name: String,
+ #[serde(rename = "ThunderstoreModString")]
+ thunderstore_mod_string: Option<String>,
+ #[serde(rename = "Version")]
+ version: Option<String>,
+}
+
+/// Parses `manifest.json` for Thunderstore mod string
+fn parse_for_thunderstore_mod_string(nsmod_path: &str) -> Result<String, anyhow::Error> {
+ let manifest_json_path = format!("{}/manifest.json", nsmod_path);
+ let ts_author_txt_path = format!("{}/thunderstore_author.txt", nsmod_path);
+
+ // Check if `manifest.json` exists and parse
+ let data = std::fs::read_to_string(manifest_json_path)?;
+ let thunderstore_manifest: super::ThunderstoreManifest = json5::from_str(&data)?;
+
+ // Check if `thunderstore_author.txt` exists and parse
+ let mut file = std::fs::File::open(ts_author_txt_path)?;
+ let mut thunderstore_author = String::new();
+ file.read_to_string(&mut thunderstore_author)?;
+
+ // Build mod string
+ let thunderstore_mod_string = format!(
+ "{}-{}-{}",
+ thunderstore_author, thunderstore_manifest.name, thunderstore_manifest.version_number
+ );
+
+ Ok(thunderstore_mod_string)
+}
+
+/// Parse `mods` folder for installed mods.
+pub fn parse_installed_mods(
+ game_install: &GameInstall,
+) -> Result<Vec<NorthstarMod>, anyhow::Error> {
+ let ns_mods_folder = format!("{}/{}/mods/", game_install.game_path, game_install.profile);
+
+ let paths = match std::fs::read_dir(ns_mods_folder) {
+ Ok(paths) => paths,
+ Err(_err) => return Err(anyhow!("No mods folder found")),
+ };
+
+ let mut directories: Vec<PathBuf> = Vec::new();
+ let mut mods: Vec<NorthstarMod> = Vec::new();
+
+ // Get list of folders in `mods` directory
+ for path in paths {
+ log::info!("{path:?}");
+ let my_path = path.unwrap().path();
+ log::info!("{my_path:?}");
+
+ let md = std::fs::metadata(my_path.clone()).unwrap();
+ if md.is_dir() {
+ directories.push(my_path);
+ }
+ }
+
+ // Iterate over folders and check if they are Northstar mods
+ for directory in directories {
+ let directory_str = directory.to_str().unwrap().to_string();
+ // Check if mod.json exists
+ let mod_json_path = format!("{}/mod.json", directory_str);
+ if !std::path::Path::new(&mod_json_path).exists() {
+ continue;
+ }
+
+ // Parse mod.json and get mod name
+
+ // Read file into string and parse it
+ let data = std::fs::read_to_string(mod_json_path.clone())?;
+ let parsed_mod_json: ModJson = match json5::from_str(&data) {
+ Ok(parsed_json) => parsed_json,
+ Err(err) => {
+ log::warn!("Failed parsing {} with {}", mod_json_path, err.to_string());
+ continue;
+ }
+ };
+ // Get Thunderstore mod string if it exists
+ let thunderstore_mod_string = match parsed_mod_json.thunderstore_mod_string {
+ // Attempt legacy method for getting Thunderstore string first
+ Some(ts_mod_string) => Some(ts_mod_string),
+ // Legacy method failed
+ None => match parse_for_thunderstore_mod_string(&directory_str) {
+ Ok(thunderstore_mod_string) => Some(thunderstore_mod_string),
+ Err(_err) => None,
+ },
+ };
+ // Get directory path
+ let mod_directory = directory.to_str().unwrap().to_string();
+
+ let ns_mod = NorthstarMod {
+ name: parsed_mod_json.name,
+ version: parsed_mod_json.version,
+ thunderstore_mod_string,
+ enabled: false, // Placeholder
+ directory: mod_directory,
+ };
+
+ mods.push(ns_mod);
+ }
+
+ // Return found mod names
+ Ok(mods)
+}
+
+/// Deletes all legacy packages that match in author and mod name
+/// regardless of version
+///
+/// "legacy package" refers to a Thunderstore package installed into the `mods` folder
+/// by extracting Northstar mods contained inside and then adding `manifest.json` and `thunderstore_author.txt`
+/// to indicate which Thunderstore package they are part of
+pub fn delete_legacy_package_install(
+ thunderstore_mod_string: &str,
+ game_install: &GameInstall,
+) -> Result<(), String> {
+ let thunderstore_mod_string: ParsedThunderstoreModString =
+ thunderstore_mod_string.parse().unwrap();
+ let found_installed_legacy_mods = match parse_installed_mods(game_install) {
+ Ok(res) => res,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ for legacy_mod in found_installed_legacy_mods {
+ if legacy_mod.thunderstore_mod_string.is_none() {
+ continue; // Not a thunderstore mod
+ }
+
+ let current_mod_ts_string: ParsedThunderstoreModString = legacy_mod
+ .clone()
+ .thunderstore_mod_string
+ .unwrap()
+ .parse()
+ .unwrap();
+
+ if thunderstore_mod_string.author_name == current_mod_ts_string.author_name
+ && thunderstore_mod_string.mod_name == current_mod_ts_string.mod_name
+ {
+ // They match, delete
+ delete_mod_folder(&legacy_mod.directory)?;
+ }
+ }
+
+ Ok(())
+}
+
+/// Deletes all NorthstarMods related to a Thunderstore mod
+pub fn delete_thunderstore_mod(
+ game_install: GameInstall,
+ thunderstore_mod_string: String,
+) -> Result<(), String> {
+ // Prevent deleting core mod
+ for core_ts_mod in BLACKLISTED_MODS {
+ if thunderstore_mod_string == core_ts_mod {
+ return Err(format!("Cannot remove core mod {thunderstore_mod_string}"));
+ }
+ }
+
+ let parsed_ts_mod_string: ParsedThunderstoreModString =
+ thunderstore_mod_string.parse().unwrap();
+
+ // Get installed mods
+ let installed_ns_mods = get_installed_mods_and_properties(game_install)?;
+
+ // List of mod folders to remove
+ let mut mod_folders_to_remove: Vec<String> = Vec::new();
+
+ // Get folder name based on Thundestore mod string
+ for installed_ns_mod in installed_ns_mods {
+ if installed_ns_mod.thunderstore_mod_string.is_none() {
+ // Not a Thunderstore mod
+ continue;
+ }
+
+ let installed_ns_mod_ts_string: ParsedThunderstoreModString = installed_ns_mod
+ .thunderstore_mod_string
+ .unwrap()
+ .parse()
+ .unwrap();
+
+ // Installed mod matches specified Thunderstore mod string
+ if parsed_ts_mod_string.author_name == installed_ns_mod_ts_string.author_name
+ && parsed_ts_mod_string.mod_name == installed_ns_mod_ts_string.mod_name
+ {
+ // Add folder to list of folder to remove
+ mod_folders_to_remove.push(installed_ns_mod.directory);
+ }
+ }
+
+ if mod_folders_to_remove.is_empty() {
+ return Err(format!(
+ "No mods removed as no Northstar mods matching {thunderstore_mod_string} were found to be installed."
+ ));
+ }
+
+ // Delete given folders
+ for mod_folder in mod_folders_to_remove {
+ delete_mod_folder(&mod_folder)?;
+ }
+
+ Ok(())
+}
diff --git a/src-tauri/src/mod_management/mod.rs b/src-tauri/src/mod_management/mod.rs
new file mode 100644
index 00000000..52ef1180
--- /dev/null
+++ b/src-tauri/src/mod_management/mod.rs
@@ -0,0 +1,797 @@
+// This file contains various mod management functions
+
+use crate::constants::{BLACKLISTED_MODS, CORE_MODS, MODS_WITH_SPECIAL_REQUIREMENTS};
+use async_recursion::async_recursion;
+use thermite::prelude::ThermiteError;
+
+use crate::NorthstarMod;
+use anyhow::{anyhow, Result};
+use serde::{Deserialize, Serialize};
+use std::error::Error;
+use std::str::FromStr;
+use std::string::ToString;
+use std::{fs, path::PathBuf};
+
+mod legacy;
+mod plugins;
+use crate::GameInstall;
+
+#[derive(Debug, Clone)]
+pub struct ParsedThunderstoreModString {
+ author_name: String,
+ mod_name: String,
+ version: String,
+}
+
+impl std::str::FromStr for ParsedThunderstoreModString {
+ type Err = &'static str; // todo use an better error management
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ // Check whether Thunderstore string passes regex
+ let re = regex::Regex::new(r"^[a-zA-Z0-9_]+-[a-zA-Z0-9_]+-\d+\.\d+\.\d++$").unwrap();
+ if !re.is_match(s) {
+ return Err("Incorrect format");
+ }
+
+ let mut parts = s.split('-');
+
+ let author_name = parts.next().ok_or("None value on author_name")?.to_string();
+ let mod_name = parts.next().ok_or("None value on mod_name")?.to_string();
+ let version = parts.next().ok_or("None value on version")?.to_string();
+
+ Ok(ParsedThunderstoreModString {
+ author_name,
+ mod_name,
+ version,
+ })
+ }
+}
+
+impl std::fmt::Display for ParsedThunderstoreModString {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}-{}-{}", self.author_name, self.mod_name, self.version)
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct ThunderstoreManifest {
+ name: String,
+ version_number: String,
+}
+
+/// A wrapper around a temporary file handle and its path.
+///
+/// This struct is designed to be used for temporary files that should be automatically deleted
+/// when the `TempFile` instance goes out of scope.
+#[derive(Debug)]
+pub struct TempFile(fs::File, PathBuf);
+
+impl TempFile {
+ pub fn new(file: fs::File, path: PathBuf) -> Self {
+ Self(file, path)
+ }
+
+ pub fn file(&self) -> &fs::File {
+ &self.0
+ }
+}
+
+impl Drop for TempFile {
+ fn drop(&mut self) {
+ _ = fs::remove_file(&self.1)
+ }
+}
+
+impl std::ops::Deref for TempFile {
+ type Target = fs::File;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+/// Installs the specified mod
+#[tauri::command]
+pub async fn install_mod_wrapper(
+ game_install: GameInstall,
+ thunderstore_mod_string: String,
+) -> Result<(), String> {
+ match fc_download_mod_and_install(&game_install, &thunderstore_mod_string).await {
+ Ok(()) => (),
+ Err(err) => {
+ log::warn!("{err}");
+ return Err(err);
+ }
+ };
+ match crate::repair_and_verify::clean_up_download_folder(&game_install, false) {
+ Ok(()) => Ok(()),
+ Err(err) => {
+ log::info!("Failed to delete download folder due to {}", err);
+ // Failure to delete download folder is not an error in mod install
+ // As such ignore. User can still force delete if need be
+ Ok(())
+ }
+ }
+}
+
+/// Returns a serde json object of the parsed `enabledmods.json` file
+pub fn get_enabled_mods(game_install: &GameInstall) -> Result<serde_json::value::Value, String> {
+ let enabledmods_json_path = format!(
+ "{}/{}/enabledmods.json",
+ game_install.game_path, game_install.profile
+ );
+
+ // Check for JSON file
+ if !std::path::Path::new(&enabledmods_json_path).exists() {
+ return Err("enabledmods.json not found".to_string());
+ }
+
+ // Read file
+ let data = match std::fs::read_to_string(enabledmods_json_path) {
+ Ok(data) => data,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ // Parse JSON
+ let res: serde_json::Value = match serde_json::from_str(&data) {
+ Ok(result) => result,
+ Err(err) => return Err(format!("Failed to read JSON due to: {}", err)),
+ };
+
+ // Return parsed data
+ Ok(res)
+}
+
+/// Gets all currently installed and enabled/disabled mods to rebuild `enabledmods.json`
+pub fn rebuild_enabled_mods_json(game_install: &GameInstall) -> Result<(), String> {
+ let enabledmods_json_path = format!(
+ "{}/{}/enabledmods.json",
+ game_install.game_path, game_install.profile
+ );
+ let mods_and_properties = get_installed_mods_and_properties(game_install.clone())?;
+
+ // Create new mapping
+ let mut my_map = serde_json::Map::new();
+
+ // Build mapping
+ for ns_mod in mods_and_properties.into_iter() {
+ my_map.insert(ns_mod.name, serde_json::Value::Bool(ns_mod.enabled));
+ }
+
+ // Turn into serde object
+ let obj = serde_json::Value::Object(my_map);
+
+ // Write to file
+ std::fs::write(
+ enabledmods_json_path,
+ serde_json::to_string_pretty(&obj).unwrap(),
+ )
+ .unwrap();
+
+ Ok(())
+}
+
+/// Set the status of a passed mod to enabled/disabled
+#[tauri::command]
+pub fn set_mod_enabled_status(
+ game_install: GameInstall,
+ mod_name: String,
+ is_enabled: bool,
+) -> Result<(), String> {
+ let enabledmods_json_path = format!(
+ "{}/{}/enabledmods.json",
+ game_install.game_path, game_install.profile
+ );
+
+ // Parse JSON
+ let mut res: serde_json::Value = match get_enabled_mods(&game_install) {
+ Ok(res) => res,
+ Err(err) => {
+ log::warn!("Couldn't parse `enabledmod.json`: {}", err);
+ log::warn!("Rebuilding file.");
+
+ rebuild_enabled_mods_json(&game_install)?;
+
+ // Then try again
+ get_enabled_mods(&game_install)?
+ }
+ };
+
+ // Check if key exists
+ if res.get(mod_name.clone()).is_none() {
+ // If it doesn't exist, rebuild `enabledmod.json`
+ log::info!("Value not found in `enabledmod.json`. Rebuilding file");
+ rebuild_enabled_mods_json(&game_install)?;
+
+ // Then try again
+ res = get_enabled_mods(&game_install)?;
+ }
+
+ // Update value
+ res[mod_name] = serde_json::Value::Bool(is_enabled);
+
+ // Save the JSON structure into the output file
+ std::fs::write(
+ enabledmods_json_path,
+ serde_json::to_string_pretty(&res).unwrap(),
+ )
+ .unwrap();
+
+ Ok(())
+}
+
+/// Resembles the bare minimum keys in Northstar `mods.json`
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct ModJson {
+ #[serde(rename = "Name")]
+ name: String,
+ #[serde(rename = "Version")]
+ version: Option<String>,
+}
+
+/// Parse `mods` folder for installed mods.
+pub fn parse_mods_in_package(
+ package_mods_path: PathBuf,
+ thunderstore_mod_string: ParsedThunderstoreModString,
+) -> Result<Vec<NorthstarMod>, anyhow::Error> {
+ let paths = match std::fs::read_dir(package_mods_path) {
+ Ok(paths) => paths,
+ Err(_err) => return Err(anyhow!("No mods folder found")),
+ };
+
+ let mut directories: Vec<PathBuf> = Vec::new();
+ let mut mods: Vec<NorthstarMod> = Vec::new();
+
+ // Get list of folders in `mods` directory
+ for path in paths {
+ let my_path = path?.path();
+ let md = std::fs::metadata(my_path.clone())?;
+ if md.is_dir() {
+ directories.push(my_path);
+ }
+ }
+
+ // Iterate over folders and check if they are Northstar mods
+ for directory in directories {
+ let directory_str = directory.to_str().unwrap().to_string();
+ // Check if mod.json exists
+ let mod_json_path = format!("{}/mod.json", directory_str);
+ if !std::path::Path::new(&mod_json_path).exists() {
+ continue;
+ }
+
+ // Read file into string and parse it
+ let data = std::fs::read_to_string(mod_json_path.clone())?;
+ let parsed_mod_json: ModJson = match json5::from_str(&data) {
+ Ok(parsed_json) => parsed_json,
+ Err(err) => {
+ log::warn!("Failed parsing {} with {}", mod_json_path, err.to_string());
+ continue;
+ }
+ };
+
+ // Get directory path
+ let mod_directory = directory.to_str().unwrap().to_string();
+
+ let ns_mod = NorthstarMod {
+ name: parsed_mod_json.name,
+ version: parsed_mod_json.version,
+ thunderstore_mod_string: Some(thunderstore_mod_string.to_string()),
+ enabled: false, // Placeholder
+ directory: mod_directory,
+ };
+
+ mods.push(ns_mod);
+ }
+
+ // Return found mod names
+ Ok(mods)
+}
+
+/// Parse `packages` folder for installed mods.
+pub fn parse_installed_package_mods(
+ game_install: &GameInstall,
+) -> Result<Vec<NorthstarMod>, anyhow::Error> {
+ let mut collected_mods: Vec<NorthstarMod> = Vec::new();
+
+ let packages_folder = format!(
+ "{}/{}/packages/",
+ game_install.game_path, game_install.profile
+ );
+
+ let packages_dir = match fs::read_dir(packages_folder) {
+ Ok(res) => res,
+ Err(err) => {
+ // We couldn't read directory, probably cause it doesn't exist yet.
+ // In that case we just say no package mods installed.
+ log::warn!("{err}");
+ return Ok(vec![]);
+ }
+ };
+
+ // Iteratore over folders in `packages` dir
+ for entry in packages_dir {
+ let entry_path = entry?.path();
+ let entry_str = entry_path.file_name().unwrap().to_str().unwrap();
+
+ // Use the struct's from_str function to verify format
+ if entry_path.is_dir() {
+ let package_thunderstore_string = match ParsedThunderstoreModString::from_str(entry_str)
+ {
+ Ok(res) => res,
+ Err(err) => {
+ log::warn!(
+ "Not a Thunderstore mod string \"{}\" cause: {}",
+ entry_path.display(),
+ err
+ );
+ continue;
+ }
+ };
+ let manifest_path = entry_path.join("manifest.json");
+ let mods_path = entry_path.join("mods");
+
+ // Ensure `manifest.json` and `mods/` dir exist
+ if manifest_path.exists() && mods_path.is_dir() {
+ let mods =
+ match parse_mods_in_package(mods_path, package_thunderstore_string.clone()) {
+ Ok(res) => res,
+ Err(err) => {
+ log::warn!("Failed parsing cause: {err}");
+ continue;
+ }
+ };
+ collected_mods.extend(mods);
+ }
+ }
+ }
+
+ Ok(collected_mods)
+}
+
+/// Gets list of installed mods and their properties
+/// - name
+/// - is enabled?
+#[tauri::command]
+pub fn get_installed_mods_and_properties(
+ game_install: GameInstall,
+) -> Result<Vec<NorthstarMod>, String> {
+ // Get installed mods from packages
+ let mut found_installed_mods = match parse_installed_package_mods(&game_install) {
+ Ok(res) => res,
+ Err(err) => return Err(err.to_string()),
+ };
+ // Get installed legacy mods
+ let found_installed_legacy_mods = match legacy::parse_installed_mods(&game_install) {
+ Ok(res) => res,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ // Combine list of package and legacy mods
+ found_installed_mods.extend(found_installed_legacy_mods);
+
+ // Get enabled mods as JSON
+ let enabled_mods: serde_json::Value = match get_enabled_mods(&game_install) {
+ Ok(enabled_mods) => enabled_mods,
+ Err(_) => serde_json::from_str("{}").unwrap(), // `enabledmods.json` not found, create empty object
+ };
+
+ let mut installed_mods = Vec::new();
+ let binding = serde_json::Map::new(); // Empty map in case treating as object fails
+ let mapping = enabled_mods.as_object().unwrap_or(&binding);
+
+ // Use list of installed mods and set enabled based on `enabledmods.json`
+ for mut current_mod in found_installed_mods {
+ let current_mod_enabled = match mapping.get(&current_mod.name) {
+ Some(enabled) => enabled.as_bool().unwrap(),
+ None => true, // Northstar considers mods not in mapping as enabled.
+ };
+ current_mod.enabled = current_mod_enabled;
+ installed_mods.push(current_mod);
+ }
+
+ Ok(installed_mods)
+}
+
+async fn get_ns_mod_download_url(thunderstore_mod_string: &str) -> Result<String, String> {
+ // TODO: This will crash the thread if not internet connection exist. `match` should be used instead
+ let index = thermite::api::get_package_index().unwrap().to_vec();
+
+ // Parse mod string
+ let parsed_ts_mod_string: ParsedThunderstoreModString = match thunderstore_mod_string.parse() {
+ Ok(res) => res,
+ Err(_) => return Err("Failed to parse mod string".to_string()),
+ };
+
+ // Encode as URL
+ let ts_mod_string_url = format!(
+ "{}/{}/{}",
+ parsed_ts_mod_string.author_name,
+ parsed_ts_mod_string.mod_name,
+ parsed_ts_mod_string.version
+ );
+
+ for ns_mod in index {
+ // Iterate over all versions of a given mod
+ for ns_mod in ns_mod.versions.values() {
+ if ns_mod.url.contains(&ts_mod_string_url) {
+ return Ok(ns_mod.url.clone());
+ }
+ }
+ }
+
+ Err("Could not find mod on Thunderstore".to_string())
+}
+
+/// Returns a vector of modstrings containing the dependencies of a given mod
+async fn get_mod_dependencies(thunderstore_mod_string: &str) -> Result<Vec<String>, anyhow::Error> {
+ log::info!("Attempting to get dependencies for: {thunderstore_mod_string}");
+
+ let index = thermite::api::get_package_index()?.to_vec();
+
+ // String replace works but more care should be taken in the future
+ let ts_mod_string_url = thunderstore_mod_string.replace('-', "/");
+
+ // Iterate over index
+ for ns_mod in index {
+ // Iterate over all versions of a given mod
+ for ns_mod in ns_mod.versions.values() {
+ if ns_mod.url.contains(&ts_mod_string_url) {
+ return Ok(ns_mod.deps.clone());
+ }
+ }
+ }
+ Ok(Vec::<String>::new())
+}
+
+/// Deletes all versions of Thunderstore package except the specified one
+fn delete_older_versions(
+ thunderstore_mod_string: &str,
+ game_install: &GameInstall,
+) -> Result<(), String> {
+ let thunderstore_mod_string: ParsedThunderstoreModString =
+ thunderstore_mod_string.parse().unwrap();
+ log::info!(
+ "Deleting other versions of {}",
+ thunderstore_mod_string.to_string()
+ );
+ let packages_folder = format!(
+ "{}/{}/packages",
+ game_install.game_path, game_install.profile
+ );
+
+ // Get folders in packages dir
+ let paths = match std::fs::read_dir(&packages_folder) {
+ Ok(paths) => paths,
+ Err(_err) => return Err(format!("Failed to read directory {}", &packages_folder)),
+ };
+
+ let mut directories: Vec<PathBuf> = Vec::new();
+
+ // Get list of folders in `mods` directory
+ for path in paths {
+ let my_path = path.unwrap().path();
+
+ let md = std::fs::metadata(my_path.clone()).unwrap();
+ if md.is_dir() {
+ directories.push(my_path);
+ }
+ }
+
+ for directory in directories {
+ let folder_name = directory.file_name().unwrap().to_str().unwrap();
+ let ts_mod_string_from_folder: ParsedThunderstoreModString = match folder_name.parse() {
+ Ok(res) => res,
+ Err(err) => {
+ // Failed parsing folder name as Thunderstore mod string
+ // This means it doesn't follow the `AUTHOR-MOD-VERSION` naming structure
+ // This folder could've been manually created by the user or another application
+ // As parsing failed we cannot determine the Thunderstore package it is part of hence we skip it
+ log::warn!("{err}");
+ continue;
+ }
+ };
+ // Check which match `AUTHOR-MOD` and do NOT match `AUTHOR-MOD-VERSION`
+ if ts_mod_string_from_folder.author_name == thunderstore_mod_string.author_name
+ && ts_mod_string_from_folder.mod_name == thunderstore_mod_string.mod_name
+ && ts_mod_string_from_folder.version != thunderstore_mod_string.version
+ {
+ delete_package_folder(&directory.display().to_string())?;
+ }
+ }
+
+ Ok(())
+}
+
+/// Checks whether some mod is correctly formatted
+/// Currently checks whether
+/// - Some `mod.json` exists under `mods/*/mod.json`
+fn fc_sanity_check(input: &&fs::File) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ let mut archive = match zip::read::ZipArchive::new(*input) {
+ Ok(archive) => archive,
+ Err(_) => {
+ return Err(Box::new(ThermiteError::UnknownError(
+ "Failed reading zip file".into(),
+ )))
+ }
+ };
+
+ let mut has_mods = false;
+ let mut mod_json_exists = false;
+
+ // Checks for `mods/*/mod.json`
+ for i in 0..archive.len() {
+ let file = match archive.by_index(i) {
+ Ok(file) => file,
+ Err(_) => continue,
+ };
+ let file_path = file.mangled_name();
+ if file_path.starts_with("mods/") {
+ has_mods = true;
+ if let Some(name) = file_path.file_name() {
+ if name == "mod.json" {
+ let parent_path = file_path.parent().unwrap();
+ if parent_path.parent().unwrap().to_str().unwrap() == "mods" {
+ mod_json_exists = true;
+ }
+ }
+ }
+ }
+
+ if file_path.starts_with("plugins/") {
+ if let Some(name) = file_path.file_name() {
+ if name.to_str().unwrap().contains(".dll") {
+ log::warn!("Plugin detected, prompting user");
+ if !plugins::plugin_prompt() {
+ return Err(Box::new(ThermiteError::UnknownError(
+ "Plugin detected and install denied".into(),
+ )));
+ }
+ }
+ }
+ }
+ }
+
+ if has_mods && mod_json_exists {
+ Ok(())
+ } else {
+ Err(Box::new(ThermiteError::UnknownError(
+ "Mod not correctly formatted".into(),
+ )))
+ }
+}
+
+// Copied from `libtermite` source code and modified
+// Should be replaced with a library call to libthermite in the future
+/// Download and install mod to the specified target.
+#[async_recursion]
+pub async fn fc_download_mod_and_install(
+ game_install: &GameInstall,
+ thunderstore_mod_string: &str,
+) -> Result<(), String> {
+ log::info!("Attempting to install \"{thunderstore_mod_string}\" to {game_install:?}");
+ // Get mods and download directories
+ let download_directory = format!(
+ "{}/___flightcore-temp/download-dir/",
+ game_install.game_path
+ );
+
+ // Early return on empty string
+ if thunderstore_mod_string.is_empty() {
+ return Err("Passed empty string".to_string());
+ }
+
+ let deps = match get_mod_dependencies(thunderstore_mod_string).await {
+ Ok(deps) => deps,
+ Err(err) => return Err(err.to_string()),
+ };
+ log::info!("Mod dependencies: {deps:?}");
+
+ // Recursively install dependencies
+ for dep in deps {
+ match fc_download_mod_and_install(game_install, &dep).await {
+ Ok(()) => (),
+ Err(err) => {
+ if err == "Cannot install Northstar as a mod!" {
+ continue; // For Northstar as a dependency, we just skip it
+ } else {
+ return Err(err);
+ }
+ }
+ };
+ }
+
+ // Prevent installing Northstar as a mod
+ // While it would fail during install anyway, having explicit error message is nicer
+ for blacklisted_mod in BLACKLISTED_MODS {
+ if thunderstore_mod_string.contains(blacklisted_mod) {
+ return Err("Cannot install Northstar as a mod!".to_string());
+ }
+ }
+
+ // Prevent installing mods that have specific install requirements
+ for special_mod in MODS_WITH_SPECIAL_REQUIREMENTS {
+ if thunderstore_mod_string.contains(special_mod) {
+ return Err(format!(
+ "{} has special install requirements and cannot be installed with FlightCore",
+ thunderstore_mod_string
+ ));
+ }
+ }
+
+ // Get download URL for the specified mod
+ let download_url = get_ns_mod_download_url(thunderstore_mod_string).await?;
+
+ // Create download directory
+ match std::fs::create_dir_all(download_directory.clone()) {
+ Ok(()) => (),
+ Err(err) => return Err(err.to_string()),
+ };
+
+ let path = format!(
+ "{}/___flightcore-temp/download-dir/{thunderstore_mod_string}.zip",
+ game_install.game_path
+ );
+
+ // Download the mod
+ let temp_file = TempFile::new(
+ std::fs::File::options()
+ .read(true)
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(&path)
+ .map_err(|e| e.to_string())?,
+ (&path).into(),
+ );
+ match thermite::core::manage::download(temp_file.file(), download_url) {
+ Ok(_written_bytes) => (),
+ Err(err) => return Err(err.to_string()),
+ };
+
+ // Get directory to install to made up of packages directory and Thunderstore mod string
+ let install_directory = format!(
+ "{}/{}/packages/",
+ game_install.game_path, game_install.profile
+ );
+
+ // Extract the mod to the mods directory
+ match thermite::core::manage::install_with_sanity(
+ thunderstore_mod_string,
+ temp_file.file(),
+ std::path::Path::new(&install_directory),
+ fc_sanity_check,
+ ) {
+ Ok(_) => (),
+ Err(err) => {
+ log::warn!("libthermite couldn't install mod {thunderstore_mod_string} due to {err:?}",);
+ return match err {
+ ThermiteError::SanityError(e) => Err(
+ format!("Mod failed sanity check during install. It's probably not correctly formatted. {}", e)
+ ),
+ _ => Err(err.to_string()),
+ };
+ }
+ };
+
+ // Successful package install
+ match legacy::delete_legacy_package_install(thunderstore_mod_string, game_install) {
+ Ok(()) => (),
+ Err(err) => {
+ // Catch error but ignore
+ log::warn!("Failed deleting legacy versions due to: {}", err);
+ }
+ };
+
+ match delete_older_versions(thunderstore_mod_string, game_install) {
+ Ok(()) => (),
+ Err(err) => {
+ // Catch error but ignore
+ log::warn!("Failed deleting older versions due to: {}", err);
+ }
+ };
+
+ Ok(())
+}
+
+/// Deletes a given Northstar mod folder
+fn delete_mod_folder(ns_mod_directory: &str) -> Result<(), String> {
+ let ns_mod_dir_path = std::path::Path::new(&ns_mod_directory);
+
+ // Safety check: Check whether `mod.json` exists and exit early if not
+ // If it does not exist, we might not be dealing with a Northstar mod
+ let mod_json_path = ns_mod_dir_path.join("mod.json");
+ if !mod_json_path.exists() {
+ // If it doesn't exist, return an error
+ return Err(format!("mod.json does not exist in {}", ns_mod_directory));
+ }
+
+ match std::fs::remove_dir_all(ns_mod_directory) {
+ Ok(()) => Ok(()),
+ Err(err) => Err(format!("Failed deleting mod: {err}")),
+ }
+}
+
+/// Deletes a Northstar mod based on its name
+#[tauri::command]
+pub fn delete_northstar_mod(game_install: GameInstall, nsmod_name: String) -> Result<(), String> {
+ // Prevent deleting core mod
+ for core_mod in CORE_MODS {
+ if nsmod_name == core_mod {
+ return Err(format!("Cannot remove core mod {nsmod_name}"));
+ }
+ }
+
+ // Get installed mods
+ let installed_ns_mods = get_installed_mods_and_properties(game_install)?;
+
+ // Get folder name based on northstarmods
+ for installed_ns_mod in installed_ns_mods {
+ // Installed mod matches specified mod
+ if installed_ns_mod.name == nsmod_name {
+ // Delete folder
+ return delete_mod_folder(&installed_ns_mod.directory);
+ }
+ }
+
+ Err(format!("Mod {nsmod_name} not found to be installed"))
+}
+
+/// Deletes a given Thunderstore package
+fn delete_package_folder(ts_package_directory: &str) -> Result<(), String> {
+ let ns_mod_dir_path = std::path::Path::new(&ts_package_directory);
+
+ // Safety check: Check whether `manifest.json` exists and exit early if not
+ // If it does not exist, we might not be dealing with a Thunderstore package
+ let mod_json_path = ns_mod_dir_path.join("manifest.json");
+ if !mod_json_path.exists() {
+ // If it doesn't exist, return an error
+ return Err(format!(
+ "manifest.json does not exist in {}",
+ ts_package_directory
+ ));
+ }
+
+ match std::fs::remove_dir_all(ts_package_directory) {
+ Ok(()) => Ok(()),
+ Err(err) => Err(format!("Failed deleting package: {err}")),
+ }
+}
+
+/// Deletes all NorthstarMods related to a Thunderstore mod
+#[tauri::command]
+pub fn delete_thunderstore_mod(
+ game_install: GameInstall,
+ thunderstore_mod_string: String,
+) -> Result<(), String> {
+ // Check packages
+ let packages_folder = format!(
+ "{}/{}/packages",
+ game_install.game_path, game_install.profile
+ );
+ if std::path::Path::new(&packages_folder).exists() {
+ for entry in fs::read_dir(packages_folder).unwrap() {
+ let entry = entry.unwrap();
+
+ // Check if it's a folder and skip if otherwise
+ if !entry.file_type().unwrap().is_dir() {
+ log::warn!("Skipping \"{}\", not a file", entry.path().display());
+ continue;
+ }
+
+ let entry_path = entry.path();
+ let package_folder_ts_string = entry_path.file_name().unwrap().to_string_lossy();
+
+ if package_folder_ts_string != thunderstore_mod_string {
+ // Not the mod folder we are looking for, try the next one\
+ continue;
+ }
+
+ // All checks passed, this is the matching mod
+ return delete_package_folder(&entry.path().display().to_string());
+ }
+ }
+
+ // Try legacy mod installs as fallback
+ legacy::delete_thunderstore_mod(game_install, thunderstore_mod_string)
+}
diff --git a/src-tauri/src/mod_management/plugins.rs b/src-tauri/src/mod_management/plugins.rs
new file mode 100644
index 00000000..e2427a16
--- /dev/null
+++ b/src-tauri/src/mod_management/plugins.rs
@@ -0,0 +1,26 @@
+use tauri::api::dialog::blocking::MessageDialogBuilder;
+use tauri::api::dialog::{MessageDialogButtons, MessageDialogKind};
+
+/// Prompt on plugin
+/// Returns:
+/// - true: user accepted plugin install
+/// - false: user denied plugin install
+pub fn plugin_prompt() -> bool {
+ let dialog = MessageDialogBuilder::new(
+ "Plugin in package detected",
+ "This mod contains a plugin. Plugins have unrestricted access to your computer!
+ \nMake sure you trust the author!
+ \n
+ \nPress 'Ok' to continue or 'Cancel' to abort mod installation",
+ )
+ .kind(MessageDialogKind::Warning)
+ .buttons(MessageDialogButtons::OkCancel);
+
+ if dialog.show() {
+ log::info!("Accepted plugin install");
+ true
+ } else {
+ log::warn!("Plugin install cancelled");
+ false
+ }
+}
diff --git a/src-tauri/src/northstar/install.rs b/src-tauri/src/northstar/install.rs
new file mode 100644
index 00000000..0953fa38
--- /dev/null
+++ b/src-tauri/src/northstar/install.rs
@@ -0,0 +1,358 @@
+use anyhow::Result;
+use serde::{Deserialize, Serialize};
+use std::time::Duration;
+use std::{cell::RefCell, time::Instant};
+use ts_rs::TS;
+
+use crate::constants::{CORE_MODS, NORTHSTAR_DEFAULT_PROFILE, NORTHSTAR_DLL};
+use crate::{
+ util::{extract, move_dir_all},
+ GameInstall, InstallType,
+};
+
+#[cfg(target_os = "windows")]
+use crate::platform_specific::windows;
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+enum InstallState {
+ Downloading,
+ Extracting,
+ Done,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+struct InstallProgress {
+ current_downloaded: u64,
+ total_size: u64,
+ state: InstallState,
+}
+
+/// Installs Northstar to the given path
+#[tauri::command]
+pub async fn install_northstar_wrapper(
+ window: tauri::Window,
+ game_install: GameInstall,
+ northstar_package_name: Option<String>,
+ version_number: Option<String>,
+) -> Result<bool, String> {
+ log::info!("Running Northstar install");
+
+ // Get Northstar package name (`Northstar` vs `NorthstarReleaseCandidate`)
+ let northstar_package_name = northstar_package_name
+ .map(|name| {
+ if name.len() <= 1 {
+ "Northstar".to_string()
+ } else {
+ name
+ }
+ })
+ .unwrap_or("Northstar".to_string());
+
+ match install_northstar(window, game_install, northstar_package_name, version_number).await {
+ Ok(_) => Ok(true),
+ Err(err) => {
+ log::error!("{}", err);
+ Err(err)
+ }
+ }
+}
+
+/// Update Northstar install in the given path
+#[tauri::command]
+pub async fn update_northstar(
+ window: tauri::Window,
+ game_install: GameInstall,
+ northstar_package_name: Option<String>,
+) -> Result<bool, String> {
+ log::info!("Updating Northstar");
+
+ // Simply re-run install with up-to-date version for upate
+ install_northstar_wrapper(window, game_install, northstar_package_name, None).await
+}
+
+/// Copied from `papa` source code and modified
+///Install N* from the provided mod
+///
+///Checks cache, else downloads the latest version
+async fn do_install(
+ window: tauri::Window,
+ nmod: &thermite::model::ModVersion,
+ game_install: GameInstall,
+) -> Result<()> {
+ let filename = format!("northstar-{}.zip", nmod.version);
+ let temp_dir = format!("{}/___flightcore-temp", game_install.game_path);
+ let download_directory = format!("{}/download-dir", temp_dir);
+ let extract_directory = format!("{}/extract-dir", temp_dir);
+
+ log::info!("Attempting to create temporary directory {}", temp_dir);
+ std::fs::create_dir_all(download_directory.clone())?;
+ std::fs::create_dir_all(extract_directory.clone())?;
+
+ let download_path = format!("{}/{}", download_directory, filename);
+ log::info!("Download path: {download_path}");
+
+ let last_emit = RefCell::new(Instant::now()); // Keep track of the last time a signal was emitted
+ let mut nfile = std::fs::File::options()
+ .read(true)
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(download_path)?;
+ thermite::core::manage::download_with_progress(
+ &mut nfile,
+ &nmod.url,
+ |delta, current, total| {
+ if delta != 0 {
+ // Only emit a signal once every 100ms
+ // This way we don't bombard the frontend with events on fast download speeds
+ let time_since_last_emit = Instant::now().duration_since(*last_emit.borrow());
+ if time_since_last_emit >= Duration::from_millis(100) {
+ window
+ .emit(
+ "northstar-install-download-progress",
+ InstallProgress {
+ current_downloaded: current,
+ total_size: total,
+ state: InstallState::Downloading,
+ },
+ )
+ .unwrap();
+ *last_emit.borrow_mut() = Instant::now();
+ }
+ }
+ },
+ )?;
+
+ window
+ .emit(
+ "northstar-install-download-progress",
+ InstallProgress {
+ current_downloaded: 0,
+ total_size: 0,
+ state: InstallState::Extracting,
+ },
+ )
+ .unwrap();
+
+ log::info!("Extracting Northstar...");
+ extract(nfile, std::path::Path::new(&extract_directory))?;
+
+ // Prepare Northstar for Installation
+ log::info!("Preparing Northstar...");
+ if game_install.profile != NORTHSTAR_DEFAULT_PROFILE {
+ // We are using a non standard Profile, we must:
+ // - move the DLL
+ // - rename the Profile
+
+ // Move DLL into the default R2Northstar Profile
+ let old_dll_path = format!("{}/{}", extract_directory, NORTHSTAR_DLL);
+ let new_dll_path = format!(
+ "{}/{}/{}",
+ extract_directory, NORTHSTAR_DEFAULT_PROFILE, NORTHSTAR_DLL
+ );
+ std::fs::rename(old_dll_path, new_dll_path)?;
+
+ // rename default R2Northstar Profile to the profile we want to use
+ let old_profile_path = format!("{}/{}/", extract_directory, NORTHSTAR_DEFAULT_PROFILE);
+ let new_profile_path = format!("{}/{}/", extract_directory, game_install.profile);
+ std::fs::rename(old_profile_path, new_profile_path)?;
+ }
+
+ log::info!("Installing Northstar...");
+
+ // Delete previous version here
+ for core_mod in CORE_MODS {
+ let path_to_delete_string = format!(
+ "{}/{}/mods/{}/",
+ game_install.game_path, game_install.profile, core_mod
+ );
+ log::info!("Preparing to remove {}", path_to_delete_string);
+
+ // Check if folder exists
+ let path_to_delete = std::path::Path::new(&path_to_delete_string);
+
+ // Check if path even exists before we attempt to remove
+ if !path_to_delete.exists() {
+ log::info!("{} does not exist. Skipping", path_to_delete_string);
+ continue;
+ }
+
+ if !path_to_delete.is_dir() {
+ log::error!(
+ "{} exists but is a file? This should never happen",
+ path_to_delete_string
+ );
+ continue;
+ }
+
+ // Safety check for mod.json
+ // Just so that we won't ever have a https://github.com/ValveSoftware/steam-for-linux/issues/3671 moment
+ let mod_json_path = format!("{}/mod.json", path_to_delete_string);
+ let mod_json_path = std::path::Path::new(&mod_json_path);
+
+ if !mod_json_path.exists() {
+ log::error!("Missing mod.json for {path_to_delete_string} this shouldn't happen");
+ continue;
+ }
+
+ // Finally delete file
+ match std::fs::remove_dir_all(path_to_delete) {
+ Ok(()) => {
+ log::info!("Succesfully removed")
+ }
+ Err(err) => {
+ log::error!("Failed removing {} due to {}", path_to_delete_string, err)
+ }
+ };
+ }
+
+ for entry in std::fs::read_dir(extract_directory).unwrap() {
+ let entry = entry.unwrap();
+ let destination = format!(
+ "{}/{}",
+ game_install.game_path,
+ entry.path().file_name().unwrap().to_str().unwrap()
+ );
+
+ log::info!("Installing {}", entry.path().display());
+ if !entry.file_type().unwrap().is_dir() {
+ std::fs::rename(entry.path(), destination)?;
+ } else {
+ move_dir_all(entry.path(), destination)?;
+ }
+ }
+
+ // Delete old copy
+ log::info!("Delete temporary directory");
+ std::fs::remove_dir_all(temp_dir).unwrap();
+
+ log::info!("Done installing Northstar!");
+ window
+ .emit(
+ "northstar-install-download-progress",
+ InstallProgress {
+ current_downloaded: 0,
+ total_size: 0,
+ state: InstallState::Done,
+ },
+ )
+ .unwrap();
+
+ Ok(())
+}
+
+pub async fn install_northstar(
+ window: tauri::Window,
+ game_install: GameInstall,
+ northstar_package_name: String,
+ version_number: Option<String>,
+) -> Result<String, String> {
+ let index = match thermite::api::get_package_index() {
+ Ok(res) => res.to_vec(),
+ Err(err) => {
+ log::warn!("Failed fetching package index due to: {err}");
+ return Err("Failed to connect to Thunderstore.".to_string());
+ }
+ };
+ let nmod = index
+ .iter()
+ .find(|f| f.name.to_lowercase() == northstar_package_name.to_lowercase())
+ .ok_or_else(|| panic!("Couldn't find Northstar on thunderstore???"))
+ .unwrap();
+
+ // Use passed version or latest if no version was passed
+ let version = version_number.as_ref().unwrap_or(&nmod.latest);
+
+ let game_path = game_install.game_path.clone();
+ log::info!("Install path \"{}\"", game_path);
+
+ match do_install(window, nmod.versions.get(version).unwrap(), game_install).await {
+ Ok(_) => (),
+ Err(err) => {
+ if game_path
+ .to_lowercase()
+ .contains(&r"C:\Program Files\".to_lowercase())
+ // default is `C:\Program Files\EA Games\Titanfall2`
+ {
+ return Err(
+ "Cannot install to default EA App install path, please move Titanfall2 to a different install location.".to_string(),
+ );
+ } else {
+ return Err(err.to_string());
+ }
+ }
+ }
+
+ Ok(nmod.latest.clone())
+}
+
+/// Attempts to find the game install location
+#[tauri::command]
+pub fn find_game_install_location() -> Result<GameInstall, String> {
+ // Attempt parsing Steam library directly
+ match steamlocate::SteamDir::locate() {
+ Ok(steamdir) => {
+ #[cfg(target_os = "linux")]
+ {
+ let snap_dir = match std::env::var("SNAP_USER_DATA") {
+ Ok(snap_dir) => std::path::PathBuf::from(snap_dir),
+ Err(_) => match dirs::home_dir() {
+ Some(path) => path,
+ None => std::path::PathBuf::new(),
+ }
+ .join("snap"),
+ };
+
+ if steamdir.path().starts_with(snap_dir) {
+ log::warn!("Found Steam installed via Snap, you may encounter issues");
+ }
+ }
+
+ match steamdir.find_app(thermite::TITANFALL2_STEAM_ID) {
+ Ok(Some((app, library))) => {
+ let app_path = library
+ .path()
+ .join("steamapps")
+ .join("common")
+ .join(app.install_dir)
+ .into_os_string()
+ .into_string()
+ .unwrap();
+
+ let game_install = GameInstall {
+ game_path: app_path,
+ profile: "R2Northstar".to_string(),
+ install_type: InstallType::STEAM,
+ };
+ return Ok(game_install);
+ }
+ Ok(None) => log::info!("Couldn't locate your Titanfall 2 Steam install."),
+ Err(err) => log::info!(
+ "Something went wrong while trying to find Titanfall 2 {}",
+ err
+ ),
+ }
+ }
+ Err(err) => log::info!("Couldn't locate Steam on this computer! {}", err),
+ }
+
+ // (On Windows only) try parsing Windows registry for Origin install path
+ #[cfg(target_os = "windows")]
+ match windows::origin_install_location_detection() {
+ Ok(game_path) => {
+ let game_install = GameInstall {
+ game_path,
+ profile: "R2Northstar".to_string(),
+ install_type: InstallType::ORIGIN,
+ };
+ return Ok(game_install);
+ }
+ Err(err) => {
+ log::info!("{}", err);
+ }
+ };
+
+ Err("Could not auto-detect game install location! Please enter it manually.".to_string())
+}
diff --git a/src-tauri/src/northstar/mod.rs b/src-tauri/src/northstar/mod.rs
new file mode 100644
index 00000000..9953d742
--- /dev/null
+++ b/src-tauri/src/northstar/mod.rs
@@ -0,0 +1,276 @@
+//! This module deals with handling things around Northstar such as
+//! - getting version number
+pub mod install;
+pub mod profile;
+
+use crate::util::check_ea_app_or_origin_running;
+use crate::{constants::CORE_MODS, platform_specific::get_host_os, GameInstall, InstallType};
+use crate::{NorthstarThunderstoreRelease, NorthstarThunderstoreReleaseWrapper};
+use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
+use ts_rs::TS;
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct NorthstarLaunchOptions {
+ launch_via_steam: bool,
+ bypass_checks: bool,
+}
+
+/// Gets list of available Northstar versions from Thunderstore
+#[tauri::command]
+pub async fn get_available_northstar_versions(
+) -> Result<Vec<NorthstarThunderstoreReleaseWrapper>, ()> {
+ let northstar_package_name = "Northstar";
+ let index = thermite::api::get_package_index().unwrap().to_vec();
+ let nsmod = index
+ .iter()
+ .find(|f| f.name.to_lowercase() == northstar_package_name.to_lowercase())
+ .ok_or_else(|| panic!("Couldn't find Northstar on thunderstore???"))
+ .unwrap();
+
+ let mut releases: Vec<NorthstarThunderstoreReleaseWrapper> = vec![];
+ for (_version_string, nsmod_version_obj) in nsmod.versions.iter() {
+ let current_elem = NorthstarThunderstoreRelease {
+ package: nsmod_version_obj.name.clone(),
+ version: nsmod_version_obj.version.clone(),
+ };
+ let current_elem_wrapped = NorthstarThunderstoreReleaseWrapper {
+ label: format!(
+ "{} v{}",
+ nsmod_version_obj.name.clone(),
+ nsmod_version_obj.version.clone()
+ ),
+ value: current_elem,
+ };
+
+ releases.push(current_elem_wrapped);
+ }
+
+ releases.sort_by(|a, b| {
+ // Parse version number
+ let a_ver = semver::Version::parse(&a.value.version).unwrap();
+ let b_ver = semver::Version::parse(&b.value.version).unwrap();
+ b_ver.partial_cmp(&a_ver).unwrap() // Sort newest first
+ });
+
+ Ok(releases)
+}
+
+/// Checks if installed Northstar version is up-to-date
+/// false -> Northstar install is up-to-date
+/// true -> Northstar install is outdated
+#[tauri::command]
+pub async fn check_is_northstar_outdated(
+ game_install: GameInstall,
+ northstar_package_name: Option<String>,
+) -> Result<bool, String> {
+ let northstar_package_name = match northstar_package_name {
+ Some(northstar_package_name) => {
+ if northstar_package_name.len() <= 1 {
+ "Northstar".to_string()
+ } else {
+ northstar_package_name
+ }
+ }
+ None => "Northstar".to_string(),
+ };
+
+ let index = match thermite::api::get_package_index() {
+ Ok(res) => res.to_vec(),
+ Err(err) => return Err(format!("Couldn't check if Northstar up-to-date: {err}")),
+ };
+ let nmod = index
+ .iter()
+ .find(|f| f.name.to_lowercase() == northstar_package_name.to_lowercase())
+ .expect("Couldn't find Northstar on thunderstore???");
+ // .ok_or_else(|| anyhow!("Couldn't find Northstar on thunderstore???"))?;
+
+ let version_number = match get_northstar_version_number(game_install) {
+ Ok(version_number) => version_number,
+ Err(err) => {
+ log::warn!("{}", err);
+ // If we fail to get new version just assume we are up-to-date
+ return Err(err);
+ }
+ };
+
+ // Release candidate version numbers are different between `mods.json` and Thunderstore
+ let version_number = crate::util::convert_release_candidate_number(version_number);
+
+ if version_number != nmod.latest {
+ log::info!("Installed Northstar version outdated");
+ Ok(true)
+ } else {
+ log::info!("Installed Northstar version up-to-date");
+ Ok(false)
+ }
+}
+
+/// Check version number of a mod
+pub fn check_mod_version_number(path_to_mod_folder: &str) -> Result<String, anyhow::Error> {
+ let data = std::fs::read_to_string(format!("{path_to_mod_folder}/mod.json"))?;
+ let parsed_json: serde_json::Value = serde_json::from_str(&data)?;
+
+ let mod_version_number = match parsed_json.get("Version").and_then(|value| value.as_str()) {
+ Some(version_number) => version_number,
+ None => return Err(anyhow!("No version number found")),
+ };
+
+ log::info!("{}", mod_version_number);
+
+ Ok(mod_version_number.to_string())
+}
+
+/// Returns the current Northstar version number as a string
+#[tauri::command]
+pub fn get_northstar_version_number(game_install: GameInstall) -> Result<String, String> {
+ log::info!("{}", game_install.game_path);
+
+ // TODO:
+ // Check if NorthstarLauncher.exe exists and check its version number
+ let initial_version_number = match check_mod_version_number(&format!(
+ "{}/{}/mods/{}",
+ game_install.game_path, game_install.profile, CORE_MODS[0]
+ )) {
+ Ok(version_number) => version_number,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ for core_mod in CORE_MODS {
+ let current_version_number = match check_mod_version_number(&format!(
+ "{}/{}/mods/{}",
+ game_install.game_path, game_install.profile, core_mod
+ )) {
+ Ok(version_number) => version_number,
+ Err(err) => return Err(err.to_string()),
+ };
+ if current_version_number != initial_version_number {
+ // We have a version number mismatch
+ return Err("Found version number mismatch".to_string());
+ }
+ }
+ log::info!("All mods same version");
+
+ Ok(initial_version_number)
+}
+
+/// Launches Northstar
+#[tauri::command]
+pub fn launch_northstar(
+ game_install: GameInstall,
+ launch_options: NorthstarLaunchOptions,
+) -> Result<String, String> {
+ dbg!(game_install.clone());
+
+ if launch_options.launch_via_steam {
+ return launch_northstar_steam(game_install);
+ }
+
+ let host_os = get_host_os();
+
+ // Explicitly fail early certain (currently) unsupported install setups
+ if host_os != "windows" {
+ if !matches!(game_install.install_type, InstallType::STEAM) {
+ return Err(format!(
+ "Not yet implemented for \"{}\" with Titanfall2 installed via \"{:?}\"",
+ get_host_os(),
+ game_install.install_type
+ ));
+ }
+
+ return launch_northstar_steam(game_install);
+ }
+
+ // Only check guards if bypassing checks is not enabled
+ if !launch_options.bypass_checks {
+ // Some safety checks before, should have more in the future
+ if get_northstar_version_number(game_install.clone()).is_err() {
+ return Err(anyhow!("Not all checks were met").to_string());
+ }
+
+ // Require EA App or Origin to be running to launch Northstar
+ let ea_app_is_running = check_ea_app_or_origin_running();
+ if !ea_app_is_running {
+ return Err(
+ anyhow!("EA App not running, start EA App before launching Northstar").to_string(),
+ );
+ }
+ }
+
+ // Switch to Titanfall2 directory for launching
+ // NorthstarLauncher.exe expects to be run from that folder
+ if std::env::set_current_dir(game_install.game_path.clone()).is_err() {
+ // We failed to get to Titanfall2 directory
+ return Err(anyhow!("Couldn't access Titanfall2 directory").to_string());
+ }
+
+ // Only Windows with Steam or Origin are supported at the moment
+ if host_os == "windows"
+ && (matches!(game_install.install_type, InstallType::STEAM)
+ || matches!(game_install.install_type, InstallType::ORIGIN)
+ || matches!(game_install.install_type, InstallType::UNKNOWN))
+ {
+ let ns_exe_path = format!("{}/NorthstarLauncher.exe", game_install.game_path);
+ let ns_profile_arg = format!("-profile={}", game_install.profile);
+
+ let mut output = std::process::Command::new("C:\\Windows\\System32\\cmd.exe")
+ .args(["/C", "start", "", &ns_exe_path, &ns_profile_arg])
+ .spawn()
+ .expect("failed to execute process");
+ output.wait().expect("failed waiting on child process");
+ return Ok("Launched game".to_string());
+ }
+
+ Err(format!(
+ "Not yet implemented for {:?} on {}",
+ game_install.install_type,
+ get_host_os()
+ ))
+}
+
+/// Prepare Northstar and Launch through Steam using the Browser Protocol
+pub fn launch_northstar_steam(game_install: GameInstall) -> Result<String, String> {
+ if !matches!(game_install.install_type, InstallType::STEAM) {
+ return Err("Titanfall2 was not installed via Steam".to_string());
+ }
+
+ match steamlocate::SteamDir::locate() {
+ Ok(steamdir) => {
+ if get_host_os() != "windows" {
+ match steamdir.compat_tool_mapping() {
+ Ok(map) => match map.get(&thermite::TITANFALL2_STEAM_ID) {
+ Some(_) => {}
+ None => {
+ return Err(
+ "Titanfall2 was not configured to use a compatibility tool"
+ .to_string(),
+ );
+ }
+ },
+ Err(_) => {
+ return Err("Could not get compatibility tool mapping".to_string());
+ }
+ }
+ }
+ }
+ Err(_) => {
+ return Err("Couldn't access Titanfall2 directory".to_string());
+ }
+ }
+
+ // Switch to Titanfall2 directory to set everything up
+ if std::env::set_current_dir(game_install.game_path).is_err() {
+ // We failed to get to Titanfall2 directory
+ return Err("Couldn't access Titanfall2 directory".to_string());
+ }
+
+ match open::that(format!(
+ "steam://run/{}//-profile={} --northstar/",
+ thermite::TITANFALL2_STEAM_ID,
+ game_install.profile
+ )) {
+ Ok(()) => Ok("Started game".to_string()),
+ Err(_err) => Err("Failed to launch Titanfall 2 via Steam".to_string()),
+ }
+}
diff --git a/src-tauri/src/northstar/profile.rs b/src-tauri/src/northstar/profile.rs
new file mode 100644
index 00000000..26a32d6b
--- /dev/null
+++ b/src-tauri/src/northstar/profile.rs
@@ -0,0 +1,121 @@
+use crate::util::copy_dir_all;
+use crate::GameInstall;
+
+// These folders are part of Titanfall 2 and
+// should NEVER be used as a Profile
+const SKIP_PATHS: [&str; 8] = [
+ "___flightcore-temp",
+ "__overlay",
+ "bin",
+ "Core",
+ "r2",
+ "vpk",
+ "platform",
+ "Support",
+];
+
+// A profile may have one of these to be detected
+const MAY_CONTAIN: [&str; 10] = [
+ "mods/",
+ "plugins/",
+ "packages/",
+ "logs/",
+ "runtime/",
+ "save_data/",
+ "Northstar.dll",
+ "enabledmods.json",
+ "placeholder.playerdata.pdata",
+ "LEGAL.txt",
+];
+
+/// Returns a list of Profile names
+/// All the returned Profiles can be found relative to the game path
+#[tauri::command]
+pub fn fetch_profiles(game_install: GameInstall) -> Result<Vec<String>, String> {
+ let mut profiles: Vec<String> = Vec::new();
+
+ for content in MAY_CONTAIN {
+ let pattern = format!("{}/*/{}", game_install.game_path, content);
+ for e in glob::glob(&pattern).expect("Failed to read glob pattern") {
+ let path = e.unwrap();
+ let mut ancestors = path.ancestors();
+
+ ancestors.next();
+
+ let profile_path = std::path::Path::new(ancestors.next().unwrap());
+ let profile_name = profile_path
+ .file_name()
+ .unwrap()
+ .to_os_string()
+ .into_string()
+ .unwrap();
+
+ if !profiles.contains(&profile_name) {
+ profiles.push(profile_name);
+ }
+ }
+ }
+
+ Ok(profiles)
+}
+
+/// Validates if a given profile is actually a valid profile
+#[tauri::command]
+pub fn validate_profile(game_install: GameInstall, profile: String) -> bool {
+ // Game files are never a valid profile
+ // Prevent users with messed up installs from making it even worse
+ if SKIP_PATHS.contains(&profile.as_str()) {
+ return false;
+ }
+
+ log::info!("Validating Profile {}", profile);
+
+ let profile_path = format!("{}/{}", game_install.game_path, profile);
+ let profile_dir = std::path::Path::new(profile_path.as_str());
+
+ profile_dir.is_dir()
+}
+
+#[tauri::command]
+pub fn delete_profile(game_install: GameInstall, profile: String) -> Result<(), String> {
+ // Check if the Profile actually exists
+ if !validate_profile(game_install.clone(), profile.clone()) {
+ return Err(format!("{} is not a valid Profile", profile));
+ }
+
+ log::info!("Deleting Profile {}", profile);
+
+ let profile_path = format!("{}/{}", game_install.game_path, profile);
+
+ match std::fs::remove_dir_all(profile_path) {
+ Ok(()) => Ok(()),
+ Err(err) => Err(format!("Failed to delete Profile: {}", err)),
+ }
+}
+
+/// Clones a profile by simply duplicating the folder under a new name
+#[tauri::command]
+pub fn clone_profile(
+ game_install: GameInstall,
+ old_profile: String,
+ new_profile: String,
+) -> Result<(), String> {
+ // Check if the old Profile already exists
+ if !validate_profile(game_install.clone(), old_profile.clone()) {
+ return Err(format!("{} is not a valid Profile", old_profile));
+ }
+
+ // Check that new Profile does not already exist
+ if validate_profile(game_install.clone(), new_profile.clone()) {
+ return Err(format!("{} already exists", new_profile));
+ }
+
+ log::info!("Cloning Profile {} to {}", old_profile, new_profile);
+
+ let old_profile_path = format!("{}/{}", game_install.game_path, old_profile);
+ let new_profile_path = format!("{}/{}", game_install.game_path, new_profile);
+
+ copy_dir_all(old_profile_path, new_profile_path).unwrap();
+
+ Ok(())
+}
diff --git a/src-tauri/src/platform_specific/linux.rs b/src-tauri/src/platform_specific/linux.rs
new file mode 100644
index 00000000..fcac5b67
--- /dev/null
+++ b/src-tauri/src/platform_specific/linux.rs
@@ -0,0 +1,98 @@
+// Linux specific code
+
+fn get_proton_dir() -> Result<String, String> {
+ let steam_dir = match steamlocate::SteamDir::locate() {
+ Ok(result) => result,
+ Err(_) => return Err("Unable to find Steam directory".to_string()),
+ };
+ let compat_dir = format!("{}/compatibilitytools.d", steam_dir.path().display());
+
+ Ok(compat_dir)
+}
+
+/// Downloads and installs NS proton
+/// Assumes Steam install
+pub fn install_ns_proton() -> Result<(), String> {
+ // Get latest NorthstarProton release
+ let latest = match thermite::core::latest_release() {
+ Ok(result) => result,
+ Err(_) => return Err("Failed to fetch latest NorthstarProton release".to_string()),
+ };
+
+ let temp_dir = std::env::temp_dir();
+ let path = format!("{}/nsproton-{}.tar.gz", temp_dir.display(), latest);
+ let archive = match std::fs::File::create(path.clone()) {
+ Ok(result) => result,
+ Err(_) => return Err("Failed to allocate NorthstarProton archive on disk".to_string()),
+ };
+
+ // Download the latest Proton release
+ log::info!("Downloading NorthstarProton to {}", path);
+ match thermite::core::download_ns_proton(latest, archive) {
+ Ok(_) => {}
+ Err(_) => return Err("Failed to download NorthstarProton".to_string()),
+ }
+
+ log::info!("Finished Download");
+
+ let compat_dir = get_proton_dir()?;
+
+ match std::fs::create_dir_all(compat_dir.clone()) {
+ Ok(_) => {}
+ Err(_) => return Err("Failed to create compatibilitytools directory".to_string()),
+ }
+
+ let finished = match std::fs::File::open(path.clone()) {
+ Ok(result) => result,
+ Err(_) => return Err("Failed to open NorthstarProton archive".to_string()),
+ };
+
+ // Extract to Proton dir
+ log::info!("Installing NorthstarProton to {}", compat_dir);
+ match thermite::core::install_ns_proton(&finished, compat_dir) {
+ Ok(_) => {}
+ Err(_) => return Err("Failed to create install NorthstarProton".to_string()),
+ }
+ log::info!("Finished Installation");
+ drop(finished);
+
+ // We installed NSProton, lets ignore this if it fails
+ let _ = std::fs::remove_file(path);
+
+ Ok(())
+}
+
+/// Remove NS Proton
+pub fn uninstall_ns_proton() -> Result<(), String> {
+ let compat_dir = get_proton_dir()?;
+ let pattern = format!("{}/NorthstarProton*", compat_dir);
+ for e in glob::glob(&pattern).expect("Failed to read glob pattern") {
+ match e {
+ Ok(path) => match std::fs::remove_dir_all(path.clone()) {
+ Ok(_) => {}
+ Err(_) => return Err(format!("Failed to remove {}", path.display())),
+ },
+ Err(e) => return Err(format!("Found unprocessable entry {}", e)),
+ }
+ }
+
+ Ok(())
+}
+
+/// Get the latest installed NS Proton version
+pub fn get_local_ns_proton_version() -> Result<String, String> {
+ let compat_dir = get_proton_dir().unwrap();
+ let pattern = format!("{}/NorthstarProton*/version", compat_dir);
+
+ if let Some(e) = glob::glob(&pattern)
+ .expect("Failed to read glob pattern")
+ .next()
+ {
+ let version_content = std::fs::read_to_string(e.unwrap()).unwrap();
+ let version = version_content.split(' ').nth(1).unwrap().to_string();
+
+ return Ok(version);
+ }
+
+ Err("Northstar Proton is not installed".to_string())
+}
diff --git a/src-tauri/src/platform_specific/mod.rs b/src-tauri/src/platform_specific/mod.rs
new file mode 100644
index 00000000..4e0514d4
--- /dev/null
+++ b/src-tauri/src/platform_specific/mod.rs
@@ -0,0 +1,50 @@
+#[cfg(target_os = "windows")]
+pub mod windows;
+
+#[cfg(target_os = "linux")]
+pub mod linux;
+
+/// Returns identifier of host OS FlightCore is running on
+#[tauri::command]
+pub fn get_host_os() -> String {
+ std::env::consts::OS.to_string()
+}
+
+/// On Linux attempts to install NorthstarProton
+/// On Windows simply returns an error message
+#[tauri::command]
+pub async fn install_northstar_proton_wrapper() -> Result<(), String> {
+ #[cfg(target_os = "linux")]
+ return linux::install_ns_proton().map_err(|err| err.to_string());
+
+ #[cfg(target_os = "windows")]
+ Err("Not supported on Windows".to_string())
+}
+
+#[tauri::command]
+pub async fn uninstall_northstar_proton_wrapper() -> Result<(), String> {
+ #[cfg(target_os = "linux")]
+ return linux::uninstall_ns_proton();
+
+ #[cfg(target_os = "windows")]
+ Err("Not supported on Windows".to_string())
+}
+
+#[tauri::command]
+pub async fn get_local_northstar_proton_wrapper_version() -> Result<String, String> {
+ #[cfg(target_os = "linux")]
+ return linux::get_local_ns_proton_version();
+
+ #[cfg(target_os = "windows")]
+ Err("Not supported on Windows".to_string())
+}
+
+/// Check whether the current device might be behind a CGNAT
+#[tauri::command]
+pub async fn check_cgnat() -> Result<String, String> {
+ #[cfg(target_os = "linux")]
+ return Err("Not supported on Linux".to_string());
+
+ #[cfg(target_os = "windows")]
+ windows::check_cgnat().await
+}
diff --git a/src-tauri/src/platform_specific/windows.rs b/src-tauri/src/platform_specific/windows.rs
new file mode 100644
index 00000000..fc6aab5d
--- /dev/null
+++ b/src-tauri/src/platform_specific/windows.rs
@@ -0,0 +1,104 @@
+/// Windows specific code
+use anyhow::{anyhow, Result};
+use std::net::Ipv4Addr;
+
+#[cfg(target_os = "windows")]
+use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey};
+
+use crate::repair_and_verify::check_is_valid_game_path;
+
+/// Gets Titanfall2 install location on Origin
+pub fn origin_install_location_detection() -> Result<String, anyhow::Error> {
+ #[cfg(target_os = "windows")]
+ {
+ let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ match hklm.open_subkey("SOFTWARE\\Respawn\\Titanfall2") {
+ Ok(tf) => {
+ let game_path_str: String = tf.get_value("Install Dir")?;
+
+ match check_is_valid_game_path(&game_path_str) {
+ Ok(()) => {
+ return Ok(game_path_str.to_string());
+ }
+ Err(err) => {
+ log::warn!("{err}");
+ }
+ }
+ }
+ Err(err) => {
+ log::warn!("{err}");
+ }
+ }
+ }
+
+ Err(anyhow!("No Origin / EA App install path found"))
+}
+
+/// Check whether the current device might be behind a CGNAT
+pub async fn check_cgnat() -> Result<String, String> {
+ // Use external service to grap IP
+ let url = "https://api.ipify.org";
+ let response = reqwest::get(url).await.unwrap().text().await.unwrap();
+
+ // Check if valid IPv4 address and return early if not
+ if response.parse::<Ipv4Addr>().is_err() {
+ return Err(format!("Not valid IPv4 address: {}", response));
+ }
+
+ let hops_count = run_tracert(&response)?;
+ Ok(format!("Counted {} hops to {}", hops_count, response))
+}
+
+/// Count number of hops in tracert output
+fn count_hops(output: &str) -> usize {
+ // Split the output into lines
+ let lines: Vec<&str> = output.lines().collect();
+
+ // Filter lines that appear to represent hops
+ let hop_lines: Vec<&str> = lines
+ .iter()
+ .filter(|&line| line.contains("ms") || line.contains("*")) // TODO check if it contains just the `ms` surrounded by whitespace, otherwise it might falsely pick up some domain names as well
+ .cloned()
+ .collect();
+
+ // Return the number of hops
+ hop_lines.len()
+}
+
+/// Run `tracert`
+fn run_tracert(target_ip: &str) -> Result<usize, String> {
+ // Ensure valid IPv4 address to avoid prevent command injection
+ assert!(target_ip.parse::<Ipv4Addr>().is_ok());
+
+ // Execute the `tracert` command
+ let output = match std::process::Command::new("tracert")
+ .arg("-4") // Force IPv4
+ .arg("-d") // Prevent resolving intermediate IP addresses
+ .arg("-w") // Set timeout to 1 second
+ .arg("1000")
+ .arg("-h") // Set max hop count
+ .arg("5")
+ .arg(target_ip)
+ .output()
+ {
+ Ok(res) => res,
+ Err(err) => return Err(format!("Failed running tracert: {}", err)),
+ };
+
+ // Check if the command was successful
+ if output.status.success() {
+ // Convert the output to a string
+ let stdout =
+ std::str::from_utf8(&output.stdout).expect("Invalid UTF-8 sequence in command output");
+ println!("{}", stdout);
+
+ // Count the number of hops
+ let hop_count = count_hops(stdout);
+ Ok(hop_count)
+ } else {
+ let stderr = std::str::from_utf8(&output.stderr)
+ .expect("Invalid UTF-8 sequence in command error output");
+ println!("{}", stderr);
+ Err(format!("Failed collecting tracert output: {}", stderr))
+ }
+}
diff --git a/src-tauri/src/repair_and_verify/mod.rs b/src-tauri/src/repair_and_verify/mod.rs
new file mode 100644
index 00000000..3c861609
--- /dev/null
+++ b/src-tauri/src/repair_and_verify/mod.rs
@@ -0,0 +1,137 @@
+use crate::mod_management::{get_enabled_mods, rebuild_enabled_mods_json, set_mod_enabled_status};
+/// Contains various functions to repair common issues and verifying installation
+use crate::{constants::CORE_MODS, GameInstall};
+
+/// Checks if is valid Titanfall2 install based on certain conditions
+#[tauri::command]
+pub async fn verify_install_location(game_path: String) -> bool {
+ match check_is_valid_game_path(&game_path) {
+ Ok(()) => true,
+ Err(err) => {
+ log::warn!("{}", err);
+ false
+ }
+ }
+}
+
+/// Checks whether the provided path is a valid Titanfall2 gamepath by checking against a certain set of criteria
+pub fn check_is_valid_game_path(game_install_path: &str) -> Result<(), String> {
+ let path_to_titanfall2_exe = format!("{game_install_path}/Titanfall2.exe");
+ let is_correct_game_path = std::path::Path::new(&path_to_titanfall2_exe).exists();
+ log::info!("Titanfall2.exe exists in path? {}", is_correct_game_path);
+
+ // Exit early if wrong game path
+ if !is_correct_game_path {
+ return Err(format!("Incorrect game path \"{game_install_path}\"")); // Return error cause wrong game path
+ }
+ Ok(())
+}
+
+/// Verifies Titanfall2 game files
+#[tauri::command]
+pub fn verify_game_files(game_install: GameInstall) -> Result<String, String> {
+ dbg!(game_install);
+ Err("TODO, not yet implemented".to_string())
+}
+
+/// Disables all mods except core ones
+/// Enables core mods if disabled
+#[tauri::command]
+pub fn disable_all_but_core(game_install: GameInstall) -> Result<(), String> {
+ // Rebuild `enabledmods.json` first to ensure all mods are added
+ rebuild_enabled_mods_json(&game_install)?;
+
+ let current_mods = get_enabled_mods(&game_install)?;
+
+ // Disable all mods, set core mods to enabled
+ for (key, _value) in current_mods.as_object().unwrap() {
+ if CORE_MODS.contains(&key.as_str()) {
+ // This is a core mod, we do not want to disable it
+ set_mod_enabled_status(game_install.clone(), key.to_string(), true)?;
+ } else {
+ // Not a core mod
+ set_mod_enabled_status(game_install.clone(), key.to_string(), false)?;
+ }
+ }
+
+ Ok(())
+}
+
+/// Installs the specified mod
+#[tauri::command]
+pub async fn clean_up_download_folder_wrapper(
+ game_install: GameInstall,
+ force: bool,
+) -> Result<(), String> {
+ match clean_up_download_folder(&game_install, force) {
+ Ok(()) => Ok(()),
+ Err(err) => Err(err.to_string()),
+ }
+}
+
+/// Deletes download folder
+/// If `force` is FALSE, bails on non-empty folder
+/// If `force` is TRUE, deletes folder even if non-empty
+pub fn clean_up_download_folder(
+ game_install: &GameInstall,
+ force: bool,
+) -> Result<(), anyhow::Error> {
+ const TEMPORARY_DIRECTORIES: [&str; 4] = [
+ "___flightcore-temp-download-dir",
+ "___flightcore-temp/download-dir",
+ "___flightcore-temp/extract-dir",
+ "___flightcore-temp",
+ ];
+
+ for directory in TEMPORARY_DIRECTORIES {
+ // Get download directory
+ let download_directory = format!("{}/{}/", game_install.game_path, directory);
+
+ // Check if files in folder
+ let download_dir_contents = match std::fs::read_dir(download_directory.clone()) {
+ Ok(contents) => contents,
+ Err(_) => continue,
+ };
+
+ let mut count = 0;
+ download_dir_contents.for_each(|_| count += 1);
+
+ if count > 0 && !force {
+ // Skip folder if not empty
+ log::warn!("Folder not empty, not deleting: {directory}");
+ continue;
+ }
+
+ // Delete folder
+ std::fs::remove_dir_all(download_directory)?;
+ }
+ Ok(())
+}
+
+/// Get list of Northstar logs
+#[tauri::command]
+pub fn get_log_list(game_install: GameInstall) -> Result<Vec<std::path::PathBuf>, String> {
+ let ns_log_folder = format!("{}/{}/logs", game_install.game_path, game_install.profile);
+
+ // List files in logs folder
+ let paths = match std::fs::read_dir(ns_log_folder) {
+ Ok(paths) => paths,
+ Err(_err) => return Err("No logs folder found".to_string()),
+ };
+
+ // Stores paths of log files
+ let mut log_files: Vec<std::path::PathBuf> = Vec::new();
+
+ for path in paths {
+ let path = path.unwrap().path();
+ if path.display().to_string().contains("nslog") {
+ log_files.push(path);
+ }
+ }
+
+ if !log_files.is_empty() {
+ Ok(log_files)
+ } else {
+ Err("No logs found".to_string())
+ }
+}
diff --git a/src-tauri/src/thunderstore/mod.rs b/src-tauri/src/thunderstore/mod.rs
new file mode 100644
index 00000000..fc2acb02
--- /dev/null
+++ b/src-tauri/src/thunderstore/mod.rs
@@ -0,0 +1,86 @@
+//! For interacting with Thunderstore API
+use crate::constants::{APP_USER_AGENT, BLACKLISTED_MODS};
+use serde::{Deserialize, Serialize};
+use std::collections::HashSet;
+use ts_rs::TS;
+
+#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
+#[ts(export)]
+pub struct ThunderstoreMod {
+ pub name: String,
+ pub full_name: String,
+ pub owner: String,
+ pub package_url: String,
+ pub date_created: String,
+ pub date_updated: String,
+ pub uuid4: String,
+ pub rating_score: i32,
+ pub is_pinned: bool,
+ pub is_deprecated: bool,
+ pub has_nsfw_content: bool,
+ pub categories: Vec<String>,
+ pub versions: Vec<ThunderstoreModVersion>,
+}
+
+#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
+#[ts(export)]
+pub struct ThunderstoreModVersion {
+ pub name: String,
+ pub full_name: String,
+ pub description: String,
+ pub icon: String,
+ pub version_number: String,
+ pub dependencies: Vec<String>,
+ pub download_url: String,
+ pub downloads: i32,
+ pub date_created: String,
+ pub website_url: String,
+ pub is_active: bool,
+ pub uuid4: String,
+ pub file_size: i64,
+}
+
+/// Performs actual fetch from Thunderstore and returns response
+async fn fetch_thunderstore_packages() -> Result<String, reqwest::Error> {
+ log::info!("Fetching Thunderstore API");
+
+ // Fetches
+ let url = "https://northstar.thunderstore.io/api/v1/package/";
+
+ let client = reqwest::Client::new();
+ client
+ .get(url)
+ .header(reqwest::header::USER_AGENT, APP_USER_AGENT)
+ .send()
+ .await?
+ .text()
+ .await
+}
+
+/// Queries Thunderstore packages API
+#[tauri::command]
+pub async fn query_thunderstore_packages_api() -> Result<Vec<ThunderstoreMod>, String> {
+ let res = match fetch_thunderstore_packages().await {
+ Ok(res) => res,
+ Err(err) => {
+ let warn_response = format!("Couldn't fetch from Thunderstore: {err}");
+ log::warn!("{warn_response}");
+ return Err(warn_response);
+ }
+ };
+
+ // Parse response
+ let parsed_json: Vec<ThunderstoreMod> = match serde_json::from_str(&res) {
+ Ok(res) => res,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ // Remove some mods from listing
+ let to_remove_set: HashSet<&str> = BLACKLISTED_MODS.iter().copied().collect();
+ let filtered_packages = parsed_json
+ .into_iter()
+ .filter(|package| !to_remove_set.contains(&package.full_name.as_ref()))
+ .collect::<Vec<ThunderstoreMod>>();
+
+ Ok(filtered_packages)
+}
diff --git a/src-tauri/src/util.rs b/src-tauri/src/util.rs
new file mode 100644
index 00000000..1d355997
--- /dev/null
+++ b/src-tauri/src/util.rs
@@ -0,0 +1,324 @@
+//! This module contains various utility/helper functions that do not fit into any other module
+
+use anyhow::{Context, Result};
+use serde::{Deserialize, Serialize};
+use zip::ZipArchive;
+
+use crate::constants::{APP_USER_AGENT, MASTER_SERVER_URL, SERVER_BROWSER_ENDPOINT};
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct NorthstarServer {
+ #[serde(rename = "playerCount")]
+ pub player_count: i32,
+}
+
+/// This function's only use is to force a `panic!()`
+// This must NOT be async to ensure crashing whole application.
+#[tauri::command]
+pub fn force_panic() {
+ panic!("Force panicked!");
+}
+
+/// Returns true if built in debug mode
+#[tauri::command]
+pub async fn is_debug_mode() -> bool {
+ cfg!(debug_assertions)
+}
+
+/// Returns the current version number as a string
+#[tauri::command]
+pub async fn get_flightcore_version_number() -> String {
+ let version = env!("CARGO_PKG_VERSION");
+ if cfg!(debug_assertions) {
+ // Debugging enabled
+ format!("v{} (debug mode)", version)
+ } else {
+ // Debugging disabled
+ format!("v{}", version)
+ }
+}
+
+/// Spawns repair window
+#[tauri::command]
+pub async fn open_repair_window(handle: tauri::AppHandle) -> Result<(), String> {
+ // Spawn new window
+ let repair_window = match tauri::WindowBuilder::new(
+ &handle,
+ "RepairWindow",
+ tauri::WindowUrl::App("/#/repair".into()),
+ )
+ .build()
+ {
+ Ok(res) => res,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ // Set window title
+ match repair_window.set_title("FlightCore Repair Window") {
+ Ok(()) => (),
+ Err(err) => return Err(err.to_string()),
+ };
+ Ok(())
+}
+
+/// Closes all windows and exits application
+#[tauri::command]
+pub async fn close_application<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> Result<(), String> {
+ app.exit(0); // Close application
+ Ok(())
+}
+
+/// Fetches `/client/servers` endpoint from master server
+async fn fetch_server_list() -> Result<String, anyhow::Error> {
+ let url = format!("{MASTER_SERVER_URL}{SERVER_BROWSER_ENDPOINT}");
+ let client = reqwest::Client::new();
+ let res = client
+ .get(url)
+ .header(reqwest::header::USER_AGENT, APP_USER_AGENT)
+ .send()
+ .await?
+ .text()
+ .await?;
+
+ Ok(res)
+}
+
+/// Gets server and playercount from master server API
+#[tauri::command]
+pub async fn get_server_player_count() -> Result<(i32, usize), String> {
+ let res = match fetch_server_list().await {
+ Ok(res) => res,
+ Err(err) => return Err(err.to_string()),
+ };
+
+ let ns_servers: Vec<NorthstarServer> =
+ serde_json::from_str(&res).expect("JSON was not well-formatted");
+
+ // Get server count
+ let server_count = ns_servers.len();
+
+ // Sum up player count
+ let total_player_count: i32 = ns_servers.iter().map(|server| server.player_count).sum();
+
+ log::info!("total_player_count: {}", total_player_count);
+ log::info!("server_count: {}", server_count);
+
+ Ok((total_player_count, server_count))
+}
+
+#[tauri::command]
+pub async fn kill_northstar() -> Result<(), String> {
+ if !check_northstar_running() {
+ return Err("Northstar is not running".to_string());
+ }
+
+ let s = sysinfo::System::new_all();
+
+ for process in s.processes_by_exact_name("Titanfall2.exe") {
+ log::info!("Killing Process {}", process.pid());
+ process.kill();
+ }
+
+ for process in s.processes_by_exact_name("NorthstarLauncher.exe") {
+ log::info!("Killing Process {}", process.pid());
+ process.kill();
+ }
+
+ Ok(())
+}
+
+/// Copied from `papa` source code and modified
+///Extract N* zip file to target game path
+// fn extract(ctx: &Ctx, zip_file: File, target: &Path) -> Result<()> {
+pub fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> {
+ let mut archive = ZipArchive::new(&zip_file).context("Unable to open zip archive")?;
+ for i in 0..archive.len() {
+ let mut f = archive.by_index(i).unwrap();
+
+ //This should work fine for N* because the dir structure *should* always be the same
+ if f.enclosed_name().unwrap().starts_with("Northstar") {
+ let out = target.join(
+ f.enclosed_name()
+ .unwrap()
+ .strip_prefix("Northstar")
+ .unwrap(),
+ );
+
+ if (*f.name()).ends_with('/') {
+ log::info!("Create directory {}", f.name());
+ std::fs::create_dir_all(target.join(f.name()))
+ .context("Unable to create directory")?;
+ continue;
+ } else if let Some(p) = out.parent() {
+ std::fs::create_dir_all(p).context("Unable to create directory")?;
+ }
+
+ let mut outfile = std::fs::OpenOptions::new()
+ .create(true)
+ .write(true)
+ .truncate(true)
+ .open(&out)?;
+
+ log::info!("Write file {}", out.display());
+
+ std::io::copy(&mut f, &mut outfile).context("Unable to write to file")?;
+ }
+ }
+
+ Ok(())
+}
+
+pub fn check_ea_app_or_origin_running() -> bool {
+ let s = sysinfo::System::new_all();
+ let x = s.processes_by_name("Origin.exe").next().is_some()
+ || s.processes_by_name("EADesktop.exe").next().is_some();
+ x
+}
+
+/// Checks if Northstar process is running
+pub fn check_northstar_running() -> bool {
+ let s = sysinfo::System::new_all();
+ let x = s
+ .processes_by_name("NorthstarLauncher.exe")
+ .next()
+ .is_some()
+ || s.processes_by_name("Titanfall2.exe").next().is_some();
+ x
+}
+
+/// Copies a folder and all its contents to a new location
+pub fn copy_dir_all(
+ src: impl AsRef<std::path::Path>,
+ dst: impl AsRef<std::path::Path>,
+) -> std::io::Result<()> {
+ std::fs::create_dir_all(&dst)?;
+ for entry in std::fs::read_dir(src)? {
+ let entry = entry?;
+ let ty = entry.file_type()?;
+ if ty.is_dir() {
+ copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
+ } else {
+ std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
+ }
+ }
+ Ok(())
+}
+
+/// Moves a folders file structure to a new location
+/// Old folders are not removed
+pub fn move_dir_all(
+ src: impl AsRef<std::path::Path>,
+ dst: impl AsRef<std::path::Path>,
+) -> std::io::Result<()> {
+ std::fs::create_dir_all(&dst)?;
+ for entry in std::fs::read_dir(src)? {
+ let entry = entry?;
+ let ty = entry.file_type()?;
+ if ty.is_dir() {
+ move_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
+ std::fs::remove_dir(entry.path())?;
+ } else {
+ std::fs::rename(entry.path(), dst.as_ref().join(entry.file_name()))?;
+ }
+ }
+ Ok(())
+}
+
+/// Helps with converting release candidate numbers which are different on Thunderstore
+/// due to restrictions imposed by the platform
+pub fn convert_release_candidate_number(version_number: String) -> String {
+ let release_candidate_suffix = "-rc";
+
+ if !version_number.contains(release_candidate_suffix) {
+ // Not an release-candidate version number, nothing to do, return early
+ return version_number;
+ }
+
+ // Version number is guaranteed to contain `-rc`
+ let re = regex::Regex::new(r"(\d+)\.(\d+)\.(\d+)-rc(\d+)").unwrap();
+ if let Some(captures) = re.captures(&version_number) {
+ // Extract versions
+ let major_version: u32 = captures[1].parse().unwrap();
+ let minor_version: u32 = captures[2].parse().unwrap();
+ let patch_version: u32 = captures[3].parse().unwrap();
+ let release_candidate: u32 = captures[4].parse().unwrap();
+
+ // Zero pad
+ let padded_release_candidate = format!("{:02}", release_candidate);
+
+ // Combine
+ let combined_patch_version = format!("{}{}", patch_version, padded_release_candidate);
+
+ // Strip leading zeroes
+ let trimmed_combined_patch_version = combined_patch_version.trim_start_matches('0');
+
+ // Combine all
+ let version_number = format!(
+ "{}.{}.{}",
+ major_version, minor_version, trimmed_combined_patch_version
+ );
+ return version_number;
+ }
+
+ // We should never end up here
+ panic!();
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_not_release_candidate() {
+ let input = "1.2.3".to_string();
+ let output = convert_release_candidate_number(input.clone());
+ let expected_output = input;
+ assert_eq!(output, expected_output);
+ }
+
+ #[test]
+ fn test_basic_release_candidate_number_conversion() {
+ let input = "1.2.3-rc4".to_string();
+ let output = convert_release_candidate_number(input);
+ let expected_output = "1.2.304";
+ assert_eq!(output, expected_output);
+ }
+
+ #[test]
+ fn test_leading_zero_release_candidate_number_conversion() {
+ let input = "1.2.0-rc3".to_string();
+ let output = convert_release_candidate_number(input);
+ let expected_output = "1.2.3";
+ assert_eq!(output, expected_output);
+ }
+
+ #[test]
+ fn test_double_patch_digit_release_candidate_number_conversion() {
+ // let input = "v1.2.34-rc5".to_string();
+ // let output = convert_release_candidate_number(input);
+ // let expected_output = "v1.2.3405";
+ let input = "1.19.10-rc1".to_string();
+ let output = convert_release_candidate_number(input);
+ let expected_output = "1.19.1001";
+
+ assert_eq!(output, expected_output);
+ }
+
+ #[test]
+ fn test_double_digit_release_candidate_number_conversion() {
+ let input = "1.2.3-rc45".to_string();
+ let output = convert_release_candidate_number(input);
+ let expected_output = "1.2.345";
+
+ assert_eq!(output, expected_output);
+ }
+
+ #[test]
+ fn test_double_digit_patch_and_rc_number_conversion() {
+ let input = "1.2.34-rc56".to_string();
+ let output = convert_release_candidate_number(input);
+ let expected_output = "1.2.3456";
+
+ assert_eq!(output, expected_output);
+ }
+}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 9c914c0e..3c5c40a6 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -3,33 +3,72 @@
"build": {
"beforeBuildCommand": "cd src-vue && npm run build",
"beforeDevCommand": "cd src-vue && npm run dev",
- "devUrl": "http://localhost:1420/",
+ "devUrl": "http://localhost:5173/",
"frontendDist": "../src-vue/dist"
},
+ "bundle": {
+ "active": true,
+ "category": "DeveloperTool",
+ "copyright": "",
+ "targets": "all",
+ "externalBin": [],
+ "icon": [
+ "icons/32x32.png",
+ "icons/128x128.png",
+ "icons/128x128@2x.png",
+ "icons/icon.icns",
+ "icons/icon.ico"
+ ],
+ "windows": {
+ "certificateThumbprint": null,
+ "digestAlgorithm": "sha256",
+ "timestampUrl": ""
+ },
+ "longDescription": "",
+ "macOS": {
+ "entitlements": null,
+ "exceptionDomain": "",
+ "frameworks": [],
+ "providerShortName": null,
+ "signingIdentity": null
+ },
+ "resources": [],
+ "shortDescription": "",
+ "linux": {
+ "deb": {
+ "depends": []
+ }
+ },
+ "createUpdaterArtifacts": "v1Compatible"
+ },
"productName": "FlightCore",
+ "mainBinaryName": "FlightCore",
"version": "2.26.2",
"identifier": "com.github.r2northstartools.flightcore",
+ "plugins": {
+ "updater": {
+ "endpoints": [
+ "https://github.com/R2NorthstarTools/FlightCore/releases/latest/download/latest-release.json"
+ ],
+ "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEVBNjM3NzJGRDgxMTU4NUUKUldSZVdCSFlMM2RqNmdhK3pIZjhEYWg2WnZGSFJqdkhLSHNOSjNhaW5VQVFLaHV3YWFDTnFKWWQK"
+ }
+ },
"app": {
"windows": [
{
+ "fullscreen": false,
+ "resizable": true,
+ "decorations": false,
"title": "FlightCore",
+ "height": 600,
+ "minHeight": 300,
"width": 1010,
- "height": 600
+ "minWidth": 600,
+ "useHttpsScheme": true
}
],
"security": {
"csp": null
}
- },
- "bundle": {
- "active": true,
- "targets": "all",
- "icon": [
- "icons/32x32.png",
- "icons/128x128.png",
- "icons/128x128@2x.png",
- "icons/icon.icns",
- "icons/icon.ico"
- ]
}
}