diff options
| author | GeckoEidechse <gecko.eidechse+git@pm.me> | 2024-12-23 19:59:25 +0100 |
|---|---|---|
| committer | GeckoEidechse <gecko.eidechse+git@pm.me> | 2024-12-23 19:59:25 +0100 |
| commit | ea58d42e2530fddcae3731bd7e84798627e0f9ed (patch) | |
| tree | cf2421da1795439152c952b0f5123e6e5c46495e /src-tauri | |
| parent | f44d60eac04aba3e5a229370f3ce87cade07f4b5 (diff) | |
| download | FlightCore-temp/tauri-2-auto-migrated.tar.gz FlightCore-temp/tauri-2-auto-migrated.zip | |
temp: Auto-migrate main branchtemp/tauri-2-auto-migrated
Diffstat (limited to 'src-tauri')
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(¤t_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" - ] } } |
