diff options
Diffstat (limited to 'src-tauri')
-rw-r--r-- | src-tauri/Cargo.lock | 219 | ||||
-rw-r--r-- | src-tauri/Cargo.toml | 16 | ||||
-rw-r--r-- | src-tauri/bindings/InstallProgress.ts | 4 | ||||
-rw-r--r-- | src-tauri/bindings/InstallState.ts | 3 | ||||
-rw-r--r-- | src-tauri/bindings/PullRequestType.ts | 2 | ||||
-rw-r--r-- | src-tauri/bindings/Tag.ts | 3 | ||||
-rw-r--r-- | src-tauri/bindings/TagWrapper.ts | 4 | ||||
-rw-r--r-- | src-tauri/src/constants.rs | 16 | ||||
-rw-r--r-- | src-tauri/src/github/mod.rs | 181 | ||||
-rw-r--r-- | src-tauri/src/github/pull_requests.rs | 25 | ||||
-rw-r--r-- | src-tauri/src/github/release_notes.rs | 10 | ||||
-rw-r--r-- | src-tauri/src/lib.rs | 276 | ||||
-rw-r--r-- | src-tauri/src/main.rs | 87 | ||||
-rw-r--r-- | src-tauri/src/mod_management/mod.rs | 88 | ||||
-rw-r--r-- | src-tauri/src/northstar/mod.rs | 18 | ||||
-rw-r--r-- | src-tauri/src/platform_specific/linux.rs | 4 | ||||
-rw-r--r-- | src-tauri/src/platform_specific/windows.rs | 6 | ||||
-rw-r--r-- | src-tauri/src/repair_and_verify/mod.rs | 10 | ||||
-rw-r--r-- | src-tauri/src/thunderstore/mod.rs | 4 | ||||
-rw-r--r-- | src-tauri/tauri.conf.json | 2 |
20 files changed, 740 insertions, 238 deletions
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 70e50a8e..6c64bf7b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -87,7 +87,7 @@ checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "app" -version = "1.10.2" +version = "1.13.2" dependencies = [ "anyhow", "async-recursion", @@ -96,9 +96,13 @@ dependencies = [ "game-scanner", "json5", "libthermite", + "log", + "open", + "pretty_env_logger", "regex", "reqwest", "sentry", + "sentry-log", "serde", "serde_json", "steamlocate", @@ -164,6 +168,17 @@ dependencies = [ ] [[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -413,6 +428,15 @@ dependencies = [ ] [[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] name = "cocoa" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -786,16 +810,16 @@ version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" dependencies = [ - "dirs-sys", + "dirs-sys 0.3.7", ] [[package]] name = "dirs" -version = "3.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +checksum = "dece029acd3353e3a58ac2e3eb3c8d6c35827a892edc6cc4138ef9c33df46ecd" dependencies = [ - "dirs-sys", + "dirs-sys 0.4.0", ] [[package]] @@ -820,6 +844,17 @@ dependencies = [ ] [[package]] +name = "dirs-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04414300db88f70d74c5ff54e50f9e1d1737d9a5b90f53fcf2e95ca2a9ab554b" +dependencies = [ + "libc", + "redox_users", + "windows-sys 0.45.0", +] + +[[package]] name = "dirs-sys-next" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -879,6 +914,19 @@ dependencies = [ ] [[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] name = "errno" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1092,9 +1140,8 @@ dependencies = [ [[package]] name = "game-scanner" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff11681d503562e5ff8fbd362ec8dd18d72f1470119e82708a55c3158eeaa0c" +version = "1.2.0" +source = "git+https://github.com/EqualGames/game-scanner.git?rev=94dcbd086a5987361a2847988a060da9b5dd3908#94dcbd086a5987361a2847988a060da9b5dd3908" dependencies = [ "bytes", "case", @@ -1107,9 +1154,9 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "sysinfo 0.23.13", + "sysinfo 0.28.4", "url", - "winreg", + "winreg 0.10.1", ] [[package]] @@ -1416,26 +1463,20 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] [[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] name = "hashlink" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" dependencies = [ - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -1455,6 +1496,15 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" @@ -1543,6 +1593,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] name = "hyper" version = "0.14.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1667,7 +1726,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", ] [[package]] @@ -1820,6 +1879,20 @@ dependencies = [ ] [[package]] +name = "keyvalues-serde" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da419ac133bb3ddf0dbf9c12fcc0ce01d994fcb65f6f1713faf15cc689320b5f" +dependencies = [ + "keyvalues-parser", + "once_cell", + "paste", + "regex", + "serde", + "thiserror", +] + +[[package]] name = "kuchiki" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1854,9 +1927,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.24.2" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" +checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" dependencies = [ "cc", "pkg-config", @@ -2146,15 +2219,6 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] - -[[package]] -name = "ntapi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc" @@ -2208,7 +2272,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -2673,6 +2737,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + +[[package]] name = "proc-macro-crate" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2723,9 +2797,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" dependencies = [ "bytes", "prost-derive", @@ -2733,12 +2807,14 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" dependencies = [ "bytes", - "heck 0.3.3", + "cfg-if", + "cmake", + "heck 0.4.1", "itertools", "lazy_static", "log", @@ -2753,9 +2829,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" dependencies = [ "anyhow", "itertools", @@ -2766,15 +2842,21 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ "bytes", "prost", ] [[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] name = "quick-xml" version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2993,7 +3075,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "winreg 0.10.1", ] [[package]] @@ -3037,16 +3119,15 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" dependencies = [ "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", - "memchr", "smallvec", ] @@ -3303,6 +3384,16 @@ dependencies = [ ] [[package]] +name = "sentry-log" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa3a3f4477e77541c26eb84d0e355729dfa35c74c682eb8678f146db5126013" +dependencies = [ + "log", + "sentry-core", +] + +[[package]] name = "sentry-panic" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3581,14 +3672,16 @@ dependencies = [ [[package]] name = "steamlocate" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf364a9446f9f4423694ad8db5be8c478088970138e557ff2ddb3167fb0a2944" +checksum = "6b3962619891cd4c87dc0ae9332b97285eb59ab7cf65c9bec3fba62188390e74" dependencies = [ "dirs", "keyvalues-parser", + "keyvalues-serde", + "serde", "steamy-vdf", - "winreg", + "winreg 0.11.0", ] [[package]] @@ -3672,14 +3765,14 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.23.13" +version = "0.26.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3977ec2e0520829be45c8a2df70db2bf364714d8a748316a10c3c35d4d2b01c9" +checksum = "5c18a6156d1f27a9592ee18c1a846ca8dd5c258b7179fc193ae87c74ebb666f5" dependencies = [ "cfg-if", "core-foundation-sys", "libc", - "ntapi 0.3.7", + "ntapi", "once_cell", "rayon", "winapi", @@ -3687,14 +3780,14 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.26.9" +version = "0.28.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c18a6156d1f27a9592ee18c1a846ca8dd5c258b7179fc193ae87c74ebb666f5" +checksum = "b4c2f3ca6693feb29a89724516f016488e9aafc7f37264f898593ee4b942f31b" dependencies = [ "cfg-if", "core-foundation-sys", "libc", - "ntapi 0.4.0", + "ntapi", "once_cell", "rayon", "winapi", @@ -3898,8 +3991,8 @@ dependencies = [ [[package]] name = "tauri-plugin-store" -version = "0.0.0" -source = "git+https://github.com/tauri-apps/tauri-plugin-store?rev=9bd993aa67766596638bbfd91e79a1bf8f632014#9bd993aa67766596638bbfd91e79a1bf8f632014" +version = "0.1.0" +source = "git+https://github.com/tauri-apps/plugins-workspace?rev=5a6abd3203dc94c38f96d0c4bf7ecbef399f8c25#5a6abd3203dc94c38f96d0c4bf7ecbef399f8c25" dependencies = [ "log", "serde", @@ -4932,6 +5025,16 @@ dependencies = [ ] [[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 = "winres" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 0e972064..76315fae 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "app" -version = "1.10.2" +version = "1.13.2" description = "A Tauri App" authors = ["you"] license = "" @@ -25,9 +25,11 @@ serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.2", features = ["api-all", "updater"] } tokio = { version = "1", features = ["full"] } +# Sentry (crash) logging sentry = "0.30" +sentry-log = "0.30.0" # Find steam games -steamlocate = "1.0.2" +steamlocate = "1.2" # Error messages anyhow = "1.0" # libthermite for Northstar/mod install handling @@ -41,21 +43,27 @@ sysinfo = "0.26.2" # HTTP requests reqwest = { version = "0.11", features = ["blocking"] } # Persistent store for settings -tauri-plugin-store = { git = "https://github.com/tauri-apps/tauri-plugin-store", rev = "9bd993aa67766596638bbfd91e79a1bf8f632014" } +tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", rev = "5a6abd3203dc94c38f96d0c4bf7ecbef399f8c25" } # JSON5 parsing support (allows comments in JSON) json5 = "0.4.1" # Async recursion for recursive mod install async-recursion = "1.0.0" # Game scanner -game-scanner = "1.1.4" +# Use specific commit that updates deprecated library +game-scanner = { git = "https://github.com/EqualGames/game-scanner.git", rev = "94dcbd086a5987361a2847988a060da9b5dd3908" } # For parsing timestamps chrono = "0.4.23" # TypeScript bindings ts-rs = "6.1" # const formatting const_format = "0.2.30" +# Logging libraries +pretty_env_logger = "0.4.0" +log = "0.4.17" # Extracting zip files easily zip-extract = "0.1.2" +# open urls +open = "3.2.0" [features] # by default Tauri runs in production mode diff --git a/src-tauri/bindings/InstallProgress.ts b/src-tauri/bindings/InstallProgress.ts new file mode 100644 index 00000000..7bea9bb8 --- /dev/null +++ b/src-tauri/bindings/InstallProgress.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { InstallState } from "./InstallState"; + +export interface InstallProgress { current_downloaded: bigint, total_size: bigint, state: InstallState, }
\ No newline at end of file diff --git a/src-tauri/bindings/InstallState.ts b/src-tauri/bindings/InstallState.ts new file mode 100644 index 00000000..21dbc0c7 --- /dev/null +++ b/src-tauri/bindings/InstallState.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type InstallState = "DOWNLOADING" | "EXTRACTING" | "DONE";
\ No newline at end of file diff --git a/src-tauri/bindings/PullRequestType.ts b/src-tauri/bindings/PullRequestType.ts index 2d1fd0a8..582f831a 100644 --- a/src-tauri/bindings/PullRequestType.ts +++ b/src-tauri/bindings/PullRequestType.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type PullRequestType = "MODS" | "LAUNCHER";
\ No newline at end of file +export type PullRequestType = "Mods" | "Launcher";
\ No newline at end of file diff --git a/src-tauri/bindings/Tag.ts b/src-tauri/bindings/Tag.ts new file mode 100644 index 00000000..adbbff33 --- /dev/null +++ b/src-tauri/bindings/Tag.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export interface Tag { name: string, }
\ No newline at end of file diff --git a/src-tauri/bindings/TagWrapper.ts b/src-tauri/bindings/TagWrapper.ts new file mode 100644 index 00000000..f9f56a51 --- /dev/null +++ b/src-tauri/bindings/TagWrapper.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Tag } from "./Tag"; + +export interface TagWrapper { label: string, value: Tag, }
\ No newline at end of file diff --git a/src-tauri/src/constants.rs b/src-tauri/src/constants.rs index 57a10e02..8c88df1e 100644 --- a/src-tauri/src/constants.rs +++ b/src-tauri/src/constants.rs @@ -1,6 +1,6 @@ // 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")); @@ -29,8 +29,22 @@ pub const BLACKLISTED_MODS: [&str; 3] = [ // Titanfall2 game IDs on Origin/EA-App pub const TITANFALL2_ORIGIN_IDS: [&str; 2] = ["Origin.OFR.50.0001452", "Origin.OFR.50.0001456"]; +// Titanfall2 Steam App ID +pub const TITANFALL2_STEAM_ID: &str = "1237970"; + +// Order in which the sections for release notes should be displayed +pub const SECTION_ORDER: [&str; 9] = [ + "feat", "fix", "docs", "style", "refactor", "build", "test", "chore", "other", +]; + // GitHub API endpoints for launcher/mods PRs pub const PULLS_API_ENDPOINT_LAUNCHER: &str = "https://api.github.com/repos/R2Northstar/NorthstarLauncher/pulls"; pub const PULLS_API_ENDPOINT_MODS: &str = "https://api.github.com/repos/R2Northstar/NorthstarMods/pulls"; + +// 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"; diff --git a/src-tauri/src/github/mod.rs b/src-tauri/src/github/mod.rs index 942f0db2..b336ab5c 100644 --- a/src-tauri/src/github/mod.rs +++ b/src-tauri/src/github/mod.rs @@ -1,2 +1,183 @@ pub mod pull_requests; pub mod release_notes; + +use app::constants::{APP_USER_AGENT, FLIGHTCORE_REPO_NAME, SECTION_ORDER}; +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, +} + +/// Wrapper type needed for frontend +#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[ts(export)] +pub struct TagWrapper { + label: String, + value: Tag, +} + +#[derive(Debug, Deserialize)] +struct CommitInfo { + sha: String, + commit: Commit, +} + +#[derive(Debug, Deserialize)] +struct Commit { + message: 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() -> 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(); + + // Fetch the list of tags for the repository as a `Vec<Tag>`. + let tags_url = format!("https://api.github.com/repos/{}/tags", FLIGHTCORE_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(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" => "**Styles:**", + "refactor" => "**Code Refactoring:**", + "build" => "**Build:**", + "test" => "**Tests:**", + "chore" => "**Chores:**", + _ => "**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'); + } + } + } + + 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 +} diff --git a/src-tauri/src/github/pull_requests.rs b/src-tauri/src/github/pull_requests.rs index 586a4fb3..96ac623f 100644 --- a/src-tauri/src/github/pull_requests.rs +++ b/src-tauri/src/github/pull_requests.rs @@ -60,15 +60,15 @@ struct ArtifactsResponse { #[derive(Serialize, Deserialize, Debug, Clone, TS)] #[ts(export)] pub enum PullRequestType { - MODS, - LAUNCHER, + Mods, + Launcher, } /// Parse pull requests from specified URL pub async fn get_pull_requests(url: String) -> Result<Vec<PullsApiResponseElement>, String> { let json_response = match fetch_github_releases_api(&url).await { Ok(result) => result, - Err(err) => return Err(err.to_string()), + Err(err) => return Err(err), }; let pulls_response: Vec<PullsApiResponseElement> = match serde_json::from_str(&json_response) { @@ -85,8 +85,8 @@ pub async fn get_pull_requests_wrapper( install_type: PullRequestType, ) -> Result<Vec<PullsApiResponseElement>, String> { let api_pr_url = match install_type { - PullRequestType::MODS => PULLS_API_ENDPOINT_MODS, - PullRequestType::LAUNCHER => PULLS_API_ENDPOINT_LAUNCHER, + PullRequestType::Mods => PULLS_API_ENDPOINT_MODS, + PullRequestType::Launcher => PULLS_API_ENDPOINT_LAUNCHER, }; get_pull_requests(api_pr_url.to_string()).await @@ -142,7 +142,8 @@ fn get_mods_download_link(pull_request: PullsApiResponseElement) -> Result<Strin } /// Gets `nightly.link` artifact download link of a launcher PR -async fn get_launcher_download_link( +#[tauri::command] +pub async fn get_launcher_download_link( pull_request: PullsApiResponseElement, ) -> Result<String, String> { // Iterate over the first 10 pages of @@ -207,7 +208,7 @@ fn add_batch_file(game_install_path: &str) { match file.write_all(batch_file_content.as_bytes()) { Err(why) => panic!("couldn't write to {}: {}", display, why), - Ok(_) => println!("successfully wrote to {}", display), + Ok(_) => log::info!("successfully wrote to {}", display), } } @@ -258,7 +259,7 @@ pub async fn apply_launcher_pr( 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) { + match std::fs::copy(source_file_path, destination_file_path) { Ok(_result) => (), Err(err) => { return Err(format!( @@ -280,7 +281,7 @@ pub async fn apply_launcher_pr( } } - println!("All done with installing launcher PR"); + log::info!("All done with installing launcher PR"); Ok(()) } @@ -308,9 +309,9 @@ pub async fn apply_mods_pr( // Delete previously managed folder if std::fs::remove_dir_all(profile_folder.clone()).is_err() { if std::path::Path::new(&profile_folder).exists() { - println!("Failed removing previous dir"); + log::error!("Failed removing previous dir"); } else { - println!("Failed removing folder that doesn't exist. Probably cause first run"); + log::warn!("Failed removing folder that doesn't exist. Probably cause first run"); } }; @@ -330,6 +331,6 @@ pub async fn apply_mods_pr( // Add batch file to launch right profile add_batch_file(game_install_path); - println!("All done with installing mods PR"); + 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 index b59358ec..b45442e0 100644 --- a/src-tauri/src/github/release_notes.rs +++ b/src-tauri/src/github/release_notes.rs @@ -20,7 +20,7 @@ pub struct FlightCoreVersion { // Fetches repo release API and returns response as string pub async fn fetch_github_releases_api(url: &str) -> Result<String, String> { - println!("Fetching releases notes from GitHub API"); + log::info!("Fetching releases notes from GitHub API"); let client = reqwest::Client::new(); let res = client @@ -40,13 +40,13 @@ pub async fn fetch_github_releases_api(url: &str) -> Result<String, String> { #[tauri::command] pub async fn get_newest_flightcore_version() -> Result<FlightCoreVersion, String> { // Get newest version number from GitHub API - println!("Checking GitHub API"); + log::info!("Checking GitHub API"); let url = "https://api.github.com/repos/R2NorthstarTools/FlightCore/releases/latest"; let res = fetch_github_releases_api(url).await?; let flightcore_version: FlightCoreVersion = serde_json::from_str(&res).expect("JSON was not well-formatted"); - println!("Done checking GitHub API"); + log::info!("Done checking GitHub API"); Ok(flightcore_version) } @@ -98,7 +98,7 @@ pub async fn get_northstar_release_notes() -> Result<Vec<ReleaseInfo>, String> { let release_info_vector: Vec<ReleaseInfo> = serde_json::from_str(&res).expect("JSON was not well-formatted"); - println!("Done checking GitHub API"); + log::info!("Done checking GitHub API"); - return Ok(release_info_vector); + Ok(release_info_vector) } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 12c839fe..8ec7e4b1 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,7 +1,6 @@ -use std::env; +use std::{cell::RefCell, env, fs, path::Path, time::Duration, time::Instant}; use anyhow::{anyhow, Context, Result}; -use sentry::{add_breadcrumb, Breadcrumb, Level}; mod northstar; @@ -15,11 +14,14 @@ use platform_specific::linux; use serde::{Deserialize, Serialize}; use sysinfo::SystemExt; +use tokio::time::sleep; use ts_rs::TS; use zip::ZipArchive; use northstar::get_northstar_version_number; +use crate::constants::TITANFALL2_STEAM_ID; + #[derive(Serialize, Deserialize, Debug, Clone)] pub enum InstallType { STEAM, @@ -50,10 +52,26 @@ pub struct NorthstarServer { pub player_count: i32, } +#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[ts(export)] +pub enum InstallState { + DOWNLOADING, + EXTRACTING, + DONE, +} + +#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[ts(export)] +struct InstallProgress { + current_downloaded: u64, + total_size: u64, + state: InstallState, +} + /// Check version number of a mod -pub fn check_mod_version_number(path_to_mod_folder: String) -> Result<String, anyhow::Error> { +pub fn check_mod_version_number(path_to_mod_folder: &str) -> Result<String, anyhow::Error> { // println!("{}", format!("{}/mod.json", path_to_mod_folder)); - let data = std::fs::read_to_string(format!("{}/mod.json", path_to_mod_folder))?; + 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)?; // println!("{}", parsed_json); let mod_version_number = match parsed_json.get("Version").and_then(|value| value.as_str()) { @@ -61,7 +79,7 @@ pub fn check_mod_version_number(path_to_mod_folder: String) -> Result<String, an None => return Err(anyhow!("No version number found")), }; - println!("{}", mod_version_number); + log::info!("{}", mod_version_number); Ok(mod_version_number.to_string()) } @@ -81,8 +99,7 @@ pub fn linux_checks_librs() -> Result<(), String> { return Err(format!( "GLIBC is not version {} or greater", min_required_ldd_version - ) - .to_string()); + )); }; // All checks passed @@ -94,7 +111,7 @@ pub fn find_game_install_location() -> Result<GameInstall, String> { // Attempt parsing Steam library directly match steamlocate::SteamDir::locate() { Some(mut steamdir) => { - let titanfall2_steamid = 1237970; + let titanfall2_steamid = TITANFALL2_STEAM_ID.parse().unwrap(); match steamdir.app(&titanfall2_steamid) { Some(app) => { // println!("{:#?}", app); @@ -104,10 +121,10 @@ pub fn find_game_install_location() -> Result<GameInstall, String> { }; return Ok(game_install); } - None => println!("Couldn't locate Titanfall2"), + None => log::info!("Couldn't locate Titanfall2 Steam instal"), } } - None => println!("Couldn't locate Steam on this computer!"), + None => log::info!("Couldn't locate Steam on this computer!"), } // (On Windows only) try parsing Windows registry for Origin install path @@ -115,13 +132,13 @@ pub fn find_game_install_location() -> Result<GameInstall, String> { match windows::origin_install_location_detection() { Ok(game_path) => { let game_install = GameInstall { - game_path: game_path, + game_path, install_type: InstallType::ORIGIN, }; return Ok(game_install); } Err(err) => { - println!("{}", err); + log::info!("{}", err); } }; @@ -130,13 +147,13 @@ pub fn find_game_install_location() -> Result<GameInstall, String> { /// 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!("{}/Titanfall2.exe", game_install_path); + 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(); - println!("Titanfall2.exe exists in path? {}", is_correct_game_path); + 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 + return Err(format!("Incorrect game path \"{game_install_path}\"")); // Return error cause wrong game path } Ok(()) } @@ -159,12 +176,12 @@ fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> { ); if (*f.name()).ends_with('/') { - println!("Create directory {}", f.name()); + 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")?; + std::fs::create_dir_all(p).context("Unable to create directory")?; } let mut outfile = std::fs::OpenOptions::new() @@ -173,7 +190,7 @@ fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> { .truncate(true) .open(&out)?; - println!("Write file {}", out.display()); + log::info!("Write file {}", out.display()); std::io::copy(&mut f, &mut outfile).context("Unable to write to file")?; } @@ -186,33 +203,83 @@ fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> { ///Install N* from the provided mod /// ///Checks cache, else downloads the latest version -async fn do_install(nmod: &thermite::model::ModVersion, game_path: &std::path::Path) -> Result<()> { +async fn do_install( + window: tauri::Window, + nmod: &thermite::model::ModVersion, + game_path: &std::path::Path, +) -> Result<()> { let filename = format!("northstar-{}.zip", nmod.version); let download_directory = format!("{}/___flightcore-temp-download-dir/", game_path.display()); std::fs::create_dir_all(download_directory.clone())?; - let download_path = format!("{}/{}", download_directory.clone(), filename); - println!("{}", download_path); - - let nfile = match thermite::core::manage::download_file(&nmod.url, download_path) { + 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 nfile = match thermite::core::manage::download_file_with_progress( + &nmod.url, + download_path, + |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(); + } + } + }, + ) { Ok(res) => res, Err(err) => return Err(anyhow!("Failed downloading Northstar {}", err)), }; - println!("Extracting Northstar..."); + window + .emit( + "northstar-install-download-progress", + InstallProgress { + current_downloaded: 0, + total_size: 0, + state: InstallState::EXTRACTING, + }, + ) + .unwrap(); + + log::info!("Extracting Northstar..."); extract(nfile, game_path)?; // Delete old copy - println!("Delete temp folder again"); + log::info!("Delete temp folder again"); std::fs::remove_dir_all(download_directory).unwrap(); - println!("Done!"); + 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_path: &str, northstar_package_name: Option<String>, ) -> Result<String, String> { @@ -234,20 +301,30 @@ pub async fn install_northstar( .ok_or_else(|| panic!("Couldn't find Northstar on thunderstore???")) .unwrap(); - // Breadcrumb for sentry to debug crash - add_breadcrumb(Breadcrumb { - // category: Some("auth".into()), - message: Some(format!("Install path \"{}\"", game_path)), - level: Level::Info, - ..Default::default() - }); + log::info!("Install path \"{}\"", game_path); - do_install( + match do_install( + window, nmod.versions.get(&nmod.latest).unwrap(), std::path::Path::new(game_path), ) .await - .unwrap(); + { + 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()) } @@ -258,7 +335,7 @@ pub fn get_host_os() -> String { } pub fn launch_northstar( - game_install: GameInstall, + game_install: &GameInstall, bypass_checks: Option<bool>, ) -> Result<String, String> { dbg!(game_install.clone()); @@ -278,15 +355,12 @@ pub fn launch_northstar( )); } - let bypass_checks = match bypass_checks { - Some(bypass_checks) => bypass_checks, - None => false, - }; + let bypass_checks = bypass_checks.unwrap_or(false); // Only check guards if bypassing checks is not enabled if !bypass_checks { // Some safety checks before, should have more in the future - if get_northstar_version_number(game_install.game_path.clone()).is_err() { + if get_northstar_version_number(&game_install.game_path).is_err() { return Err(anyhow!("Not all checks were met").to_string()); } @@ -314,7 +388,7 @@ pub fn launch_northstar( { let ns_exe_path = format!("{}/NorthstarLauncher.exe", game_install.game_path); let _output = std::process::Command::new("C:\\Windows\\System32\\cmd.exe") - .args(&["/C", "start", "", &ns_exe_path]) + .args(["/C", "start", "", &ns_exe_path]) .spawn() .expect("failed to execute process"); return Ok("Launched game".to_string()); @@ -327,31 +401,109 @@ pub fn launch_northstar( )) } -pub fn check_origin_running() -> bool { - let s = sysinfo::System::new_all(); - for _process in s.processes_by_name("Origin.exe") { - // check here if this is your process - // dbg!(process); - // There's at least one Origin process, so we can launch - return true; +/// Prepare Northstar and Launch through Steam using the Browser Protocol +pub fn launch_northstar_steam( + game_install: &GameInstall, + _bypass_checks: Option<bool>, +) -> Result<String, String> { + if !matches!(game_install.install_type, InstallType::STEAM) { + return Err("Titanfall2 was not installed via Steam".to_string()); } - // Alternatively, check for EA Desktop - for _process in s.processes_by_name("EADesktop.exe") { - // There's at least one EADesktop process, so we can launch - return true; + + match steamlocate::SteamDir::locate() { + Some(mut steamdir) => { + if get_host_os() != "windows" { + let titanfall2_steamid: u32 = TITANFALL2_STEAM_ID.parse().unwrap(); + match steamdir.compat_tool(&titanfall2_steamid) { + Some(compat) => { + if !compat + .name + .clone() + .unwrap() + .to_ascii_lowercase() + .contains("northstarproton") + { + return Err( + "Titanfall2 was not configured to use NorthstarProton".to_string() + ); + } + } + None => { + return Err( + "Titanfall2 was not configured to use a compatibility tool".to_string() + ); + } + } + } + } + None => { + return Err("Couldn't access Titanfall2 directory".to_string()); + } } - false + + // Switch to Titanfall2 directory to set everything up + if std::env::set_current_dir(game_install.game_path.clone()).is_err() { + // We failed to get to Titanfall2 directory + return Err("Couldn't access Titanfall2 directory".to_string()); + } + + let run_northstar = "run_northstar.txt"; + let run_northstar_bak = "run_northstar.txt.bak"; + + if Path::new(run_northstar).exists() { + // rename should ovewrite existing files + fs::rename(run_northstar, run_northstar_bak).unwrap(); + } + + // Passing arguments gives users a prompt, so we use run_northstar.txt + fs::write(run_northstar, b"1").unwrap(); + + let retval = match open::that(format!("steam://run/{}/", TITANFALL2_STEAM_ID)) { + Ok(()) => Ok("Started game".to_string()), + Err(_err) => Err("Failed to launch Titanfall 2 via Steam".to_string()), + }; + + let is_err = retval.is_err(); + + // Handle the rest in the backround + tauri::async_runtime::spawn(async move { + // Starting the EA app and Titanfall might take a good minute or three + let mut wait_countdown = 60 * 3; + while wait_countdown > 0 && !check_northstar_running() && !is_err { + sleep(Duration::from_millis(1000)).await; + wait_countdown -= 1; + } + + // Northstar may be running, but it may not have loaded the file yet + sleep(Duration::from_millis(2000)).await; + + // intentionally ignore Result + let _ = fs::remove_file(run_northstar); + + if Path::new(run_northstar_bak).exists() { + fs::rename(run_northstar_bak, run_northstar).unwrap(); + } + }); + + retval +} + +pub fn check_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(); - for _process in s.processes_by_name("NorthstarLauncher.exe") { - // check here if this is your process - // dbg!(process); - return true; - } - false + let x = s + .processes_by_name("NorthstarLauncher.exe") + .next() + .is_some() + || s.processes_by_name("Titanfall2.exe").next().is_some(); + x } /// Helps with converting release candidate numbers which are different on Thunderstore @@ -364,7 +516,7 @@ pub fn convert_release_candidate_number(version_number: String) -> String { } /// 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> { +pub fn get_enabled_mods(game_install: &GameInstall) -> Result<serde_json::value::Value, String> { let enabledmods_json_path = format!("{}/R2Northstar/enabledmods.json", game_install.game_path); // Check for JSON file @@ -381,7 +533,7 @@ pub fn get_enabled_mods(game_install: GameInstall) -> Result<serde_json::value:: // 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.to_string())), + Err(err) => return Err(format!("Failed to read JSON due to: {}", err)), }; // Return parsed data diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 50e439c8..3aa17459 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -10,15 +10,18 @@ use std::{ }; use app::{ - constants::{APP_USER_AGENT, MASTER_SERVER_URL, SERVER_BROWSER_ENDPOINT}, + constants::{APP_USER_AGENT, MASTER_SERVER_URL, REFRESH_DELAY, SERVER_BROWSER_ENDPOINT}, *, }; mod github; -use github::pull_requests::{apply_launcher_pr, apply_mods_pr, get_pull_requests_wrapper}; +use github::pull_requests::{ + apply_launcher_pr, apply_mods_pr, get_launcher_download_link, get_pull_requests_wrapper, +}; use github::release_notes::{ check_is_flightcore_outdated, get_newest_flightcore_version, get_northstar_release_notes, }; +use github::{compare_tags, get_list_of_tags}; mod repair_and_verify; use repair_and_verify::{ @@ -38,13 +41,20 @@ mod thunderstore; use thunderstore::query_thunderstore_packages_api; use tauri::{Manager, Runtime}; -use tauri_plugin_store::PluginBuilder; use tokio::time::sleep; #[derive(Default)] struct Counter(Arc<Mutex<i32>>); fn main() { + // 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(( @@ -57,7 +67,7 @@ fn main() { )); tauri::Builder::default() - .plugin(PluginBuilder::default().build()) + .plugin(tauri_plugin_store::Builder::default().build()) .setup(|app| { let app_handle = app.app_handle(); tauri::async_runtime::spawn(async move { @@ -86,6 +96,17 @@ fn main() { } }); + // Emit updated player and server count to GUI + let app_handle = app.app_handle(); + tauri::async_runtime::spawn(async move { + loop { + sleep(REFRESH_DELAY).await; + app_handle + .emit_all("northstar-statistics", get_server_player_count().await) + .unwrap(); + } + }); + Ok(()) }) .manage(Counter(Default::default())) @@ -100,6 +121,7 @@ fn main() { install_northstar_caller, update_northstar_caller, launch_northstar_caller, + launch_northstar_steam_caller, check_is_flightcore_outdated_caller, get_log_list, verify_game_files, @@ -117,9 +139,12 @@ fn main() { delete_thunderstore_mod, open_repair_window, query_thunderstore_packages_api, + get_list_of_tags, + compare_tags, get_pull_requests_wrapper, apply_launcher_pr, apply_mods_pr, + get_launcher_download_link, close_application, ]) .run(tauri::generate_context!()) @@ -142,7 +167,7 @@ fn force_panic() { #[tauri::command] /// Returns true if built in debug mode async fn is_debug_mode() -> bool { - return cfg!(debug_assertions); + cfg!(debug_assertions) } #[tauri::command] @@ -177,7 +202,7 @@ async fn get_flightcore_version_number() -> String { #[tauri::command] async fn get_northstar_version_number_caller(game_path: String) -> Result<String, String> { - match get_northstar_version_number(game_path) { + match get_northstar_version_number(&game_path) { Ok(version_number) => Ok(version_number), Err(err) => Err(err.to_string()), } @@ -209,10 +234,10 @@ async fn check_is_northstar_outdated( .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_path) { + let version_number = match get_northstar_version_number(&game_path) { Ok(version_number) => version_number, Err(err) => { - println!("{}", err); + log::warn!("{}", err); // If we fail to get new version just assume we are up-to-date return Err(err.to_string()); } @@ -222,10 +247,10 @@ async fn check_is_northstar_outdated( let version_number = convert_release_candidate_number(version_number); if version_number != nmod.latest { - println!("Installed Northstar version outdated"); + log::info!("Installed Northstar version outdated"); Ok(true) } else { - println!("Installed Northstar version up-to-date"); + log::info!("Installed Northstar version up-to-date"); Ok(false) } } @@ -244,7 +269,7 @@ async fn verify_install_location(game_path: String) -> bool { match check_is_valid_game_path(&game_path) { Ok(()) => true, Err(err) => { - println!("{}", err); + log::warn!("{}", err); false } } @@ -259,15 +284,16 @@ async fn get_host_os_caller() -> String { #[tauri::command] /// Installs Northstar to the given path async fn install_northstar_caller( + window: tauri::Window, game_path: String, northstar_package_name: Option<String>, ) -> Result<bool, String> { - println!("Running"); - match install_northstar(&game_path, northstar_package_name).await { + log::info!("Running"); + match install_northstar(window, &game_path, northstar_package_name).await { Ok(_) => Ok(true), Err(err) => { - println!("{}", err); - Err(err.to_string()) + log::error!("{}", err); + Err(err) } } } @@ -275,17 +301,18 @@ async fn install_northstar_caller( #[tauri::command] /// Update Northstar install in the given path async fn update_northstar_caller( + window: tauri::Window, game_path: String, northstar_package_name: Option<String>, ) -> Result<bool, String> { - println!("Updating"); + log::info!("Updating Northstar"); // Simply re-run install with up-to-date version for upate - match install_northstar(&game_path, northstar_package_name).await { + match install_northstar(window, &game_path, northstar_package_name).await { Ok(_) => Ok(true), Err(err) => { - println!("{}", err); - Err(err.to_string()) + log::error!("{}", err); + Err(err) } } } @@ -296,7 +323,16 @@ async fn launch_northstar_caller( game_install: GameInstall, bypass_checks: Option<bool>, ) -> Result<String, String> { - launch_northstar(game_install, bypass_checks) + launch_northstar(&game_install, bypass_checks) +} + +#[tauri::command] +/// Launches Northstar +async fn launch_northstar_steam_caller( + game_install: GameInstall, + bypass_checks: Option<bool>, +) -> Result<String, String> { + launch_northstar_steam(&game_install, bypass_checks) } #[tauri::command] @@ -305,11 +341,11 @@ async fn install_mod_caller( game_install: GameInstall, thunderstore_mod_string: String, ) -> Result<(), String> { - fc_download_mod_and_install(game_install.clone(), thunderstore_mod_string).await?; - match clean_up_download_folder(game_install, false) { + fc_download_mod_and_install(&game_install, &thunderstore_mod_string).await?; + match clean_up_download_folder(&game_install, false) { Ok(()) => Ok(()), Err(err) => { - println!("Failed to delete download folder due to {}", 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(()) @@ -323,7 +359,7 @@ async fn clean_up_download_folder_caller( game_install: GameInstall, force: bool, ) -> Result<(), String> { - match clean_up_download_folder(game_install, force) { + match clean_up_download_folder(&game_install, force) { Ok(()) => Ok(()), Err(err) => Err(err.to_string()), } @@ -353,7 +389,8 @@ async fn get_server_player_count() -> Result<(i32, usize), String> { // Sum up player count let total_player_count: i32 = ns_servers.iter().map(|server| server.player_count).sum(); - dbg!((total_player_count, server_count)); + log::info!("total_player_count: {}", total_player_count); + log::info!("server_count: {}", server_count); Ok((total_player_count, server_count)) } diff --git a/src-tauri/src/mod_management/mod.rs b/src-tauri/src/mod_management/mod.rs index d2b5040b..728e72c0 100644 --- a/src-tauri/src/mod_management/mod.rs +++ b/src-tauri/src/mod_management/mod.rs @@ -12,8 +12,6 @@ use std::path::PathBuf; use app::get_enabled_mods; use app::GameInstall; -use json5; - #[derive(Debug, Clone)] struct ParsedThunderstoreModString { author_name: String, @@ -25,7 +23,7 @@ impl std::str::FromStr for ParsedThunderstoreModString { type Err = (); fn from_str(s: &str) -> Result<Self, Self::Err> { - let mut parts = s.split("-"); + let mut parts = s.split('-'); let author_name = parts.next().unwrap().to_string(); let mod_name = parts.next().unwrap().to_string(); @@ -56,9 +54,9 @@ pub struct ModJson { } /// Gets all currently installed and enabled/disabled mods to rebuild `enabledmods.json` -pub fn rebuild_enabled_mods_json(game_install: GameInstall) -> Result<(), String> { +pub fn rebuild_enabled_mods_json(game_install: &GameInstall) -> Result<(), String> { let enabledmods_json_path = format!("{}/R2Northstar/enabledmods.json", game_install.game_path); - let mods_and_properties = get_installed_mods_and_properties(game_install)?; + let mods_and_properties = get_installed_mods_and_properties(game_install.clone())?; // Create new mapping let mut my_map = serde_json::Map::new(); @@ -91,28 +89,27 @@ pub fn set_mod_enabled_status( let enabledmods_json_path = format!("{}/R2Northstar/enabledmods.json", game_install.game_path); // Parse JSON - let mut res: serde_json::Value = match get_enabled_mods(game_install.clone()) { + let mut res: serde_json::Value = match get_enabled_mods(&game_install) { Ok(res) => res, Err(err) => { - println!("Couldn't parse `enabledmod.json`: {}", err); - println!("Rebuilding file."); + log::warn!("Couldn't parse `enabledmod.json`: {}", err); + log::warn!("Rebuilding file."); - rebuild_enabled_mods_json(game_install.clone())?; + rebuild_enabled_mods_json(&game_install)?; // Then try again - let res = get_enabled_mods(game_install.clone())?; - res + 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` - println!("Value not found in `enabledmod.json`. Rebuilding file"); - rebuild_enabled_mods_json(game_install.clone())?; + 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)?; + res = get_enabled_mods(&game_install)?; } // Update value @@ -129,7 +126,7 @@ pub fn set_mod_enabled_status( } /// Parses `manifest.json` for Thunderstore mod string -fn parse_for_thunderstore_mod_string(nsmod_path: String) -> Result<String, anyhow::Error> { +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); @@ -152,7 +149,7 @@ fn parse_for_thunderstore_mod_string(nsmod_path: String) -> Result<String, anyho } /// Parse `mods` folder for installed mods. -fn parse_installed_mods(game_install: GameInstall) -> Result<Vec<NorthstarMod>, anyhow::Error> { +fn parse_installed_mods(game_install: &GameInstall) -> Result<Vec<NorthstarMod>, anyhow::Error> { let ns_mods_folder = format!("{}/R2Northstar/mods/", game_install.game_path); let paths = match std::fs::read_dir(ns_mods_folder) { @@ -189,7 +186,7 @@ fn parse_installed_mods(game_install: GameInstall) -> Result<Vec<NorthstarMod>, let parsed_mod_json: ModJson = match json5::from_str(&data) { Ok(parsed_json) => parsed_json, Err(err) => { - println!("Failed parsing {} with {}", mod_json_path, err.to_string()); + log::warn!("Failed parsing {} with {}", mod_json_path, err.to_string()); continue; } }; @@ -198,7 +195,7 @@ fn parse_installed_mods(game_install: GameInstall) -> Result<Vec<NorthstarMod>, // 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) { + None => match parse_for_thunderstore_mod_string(&directory_str) { Ok(thunderstore_mod_string) => Some(thunderstore_mod_string), Err(_err) => None, }, @@ -209,7 +206,7 @@ fn parse_installed_mods(game_install: GameInstall) -> Result<Vec<NorthstarMod>, let ns_mod = NorthstarMod { name: parsed_mod_json.name, version: parsed_mod_json.version, - thunderstore_mod_string: thunderstore_mod_string, + thunderstore_mod_string, enabled: false, // Placeholder directory: mod_directory, }; @@ -229,13 +226,13 @@ pub fn get_installed_mods_and_properties( game_install: GameInstall, ) -> Result<Vec<NorthstarMod>, String> { // Get actually installed mods - let found_installed_mods = match parse_installed_mods(game_install.clone()) { + let found_installed_mods = match parse_installed_mods(&game_install) { Ok(res) => res, Err(err) => return Err(err.to_string()), }; // Get enabled mods as JSON - let enabled_mods: serde_json::Value = match get_enabled_mods(game_install) { + 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 }; @@ -256,7 +253,7 @@ pub fn get_installed_mods_and_properties( Ok(installed_mods) } -async fn get_ns_mod_download_url(thunderstore_mod_string: String) -> Result<String, String> { +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(); @@ -276,7 +273,7 @@ async fn get_ns_mod_download_url(thunderstore_mod_string: String) -> Result<Stri for ns_mod in index { // Iterate over all versions of a given mod - for (_key, ns_mod) in &ns_mod.versions { + for ns_mod in ns_mod.versions.values() { if ns_mod.url.contains(&ts_mod_string_url) { dbg!(ns_mod.clone()); return Ok(ns_mod.url.clone()); @@ -288,21 +285,19 @@ async fn get_ns_mod_download_url(thunderstore_mod_string: String) -> Result<Stri } /// Returns a vector of modstrings containing the dependencies of a given mod -async fn get_mod_dependencies( - thunderstore_mod_string: String, -) -> Result<Vec<String>, anyhow::Error> { - dbg!(thunderstore_mod_string.clone()); +async fn get_mod_dependencies(thunderstore_mod_string: &str) -> Result<Vec<String>, anyhow::Error> { + dbg!(thunderstore_mod_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(); // String replace works but more care should be taken in the future - let ts_mod_string_url = thunderstore_mod_string.replace("-", "/"); + 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 (_key, ns_mod) in &ns_mod.versions { + for ns_mod in ns_mod.versions.values() { if ns_mod.url.contains(&ts_mod_string_url) { dbg!(ns_mod.clone()); return Ok(ns_mod.deps.clone()); @@ -317,8 +312,8 @@ async fn get_mod_dependencies( /// Download and install mod to the specified target. #[async_recursion] pub async fn fc_download_mod_and_install( - game_install: GameInstall, - thunderstore_mod_string: String, + game_install: &GameInstall, + thunderstore_mod_string: &str, ) -> Result<(), String> { // Get mods and download directories let download_directory = format!( @@ -328,11 +323,11 @@ pub async fn fc_download_mod_and_install( let mods_directory = format!("{}/R2Northstar/mods/", game_install.game_path); // Early return on empty string - if thunderstore_mod_string.len() == 0 { + if thunderstore_mod_string.is_empty() { return Err("Passed empty string".to_string()); } - let deps = match get_mod_dependencies(thunderstore_mod_string.clone()).await { + let deps = match get_mod_dependencies(thunderstore_mod_string).await { Ok(deps) => deps, Err(err) => return Err(err.to_string()), }; @@ -340,13 +335,13 @@ pub async fn fc_download_mod_and_install( // Recursively install dependencies for dep in deps { - match fc_download_mod_and_install(game_install.clone(), dep).await { + match fc_download_mod_and_install(game_install, &dep).await { Ok(()) => (), Err(err) => { - if err.to_string() == "Cannot install Northstar as a mod!" { + if err == "Cannot install Northstar as a mod!" { continue; // For Northstar as a dependency, we just skip it } else { - return Err(err.to_string()); + return Err(err); } } }; @@ -361,7 +356,7 @@ pub async fn fc_download_mod_and_install( } // Get download URL for the specified mod - let download_url = get_ns_mod_download_url(thunderstore_mod_string.clone()).await?; + let download_url = get_ns_mod_download_url(thunderstore_mod_string).await?; // Create download directory match std::fs::create_dir_all(download_directory.clone()) { @@ -369,20 +364,19 @@ pub async fn fc_download_mod_and_install( Err(err) => return Err(err.to_string()), }; - let name = thunderstore_mod_string.clone(); let path = format!( - "{}/___flightcore-temp-download-dir/{}.zip", - game_install.game_path, name + "{}/___flightcore-temp-download-dir/{thunderstore_mod_string}.zip", + game_install.game_path ); // Download the mod - let f = match thermite::core::manage::download_file(&download_url, path.clone()) { + let f = match thermite::core::manage::download_file(download_url, path.clone()) { Ok(f) => f, Err(e) => return Err(e.to_string()), }; // Get Thunderstore mod author - let author = thunderstore_mod_string.split("-").next().unwrap(); + let author = thunderstore_mod_string.split('-').next().unwrap(); // Extract the mod to the mods directory match thermite::core::manage::install_mod(author, &f, std::path::Path::new(&mods_directory)) { @@ -397,7 +391,7 @@ pub async fn fc_download_mod_and_install( } /// Deletes a given Northstar mod folder -fn delete_mod_folder(ns_mod_directory: String) -> Result<(), String> { +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 @@ -408,7 +402,7 @@ fn delete_mod_folder(ns_mod_directory: String) -> Result<(), String> { return Err(format!("mod.json does not exist in {}", ns_mod_directory)); } - match std::fs::remove_dir_all(&ns_mod_directory) { + match std::fs::remove_dir_all(ns_mod_directory) { Ok(()) => Ok(()), Err(err) => Err(format!("Failed deleting mod: {err}")), } @@ -432,7 +426,7 @@ pub fn delete_northstar_mod(game_install: GameInstall, nsmod_name: String) -> Re // Installed mod matches specified mod if installed_ns_mod.name == nsmod_name { // Delete folder - return delete_mod_folder(installed_ns_mod.directory); + return delete_mod_folder(&installed_ns_mod.directory); } } @@ -483,7 +477,7 @@ pub fn delete_thunderstore_mod( } } - if !(mod_folders_to_remove.len() > 0) { + 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." )); @@ -491,7 +485,7 @@ pub fn delete_thunderstore_mod( // Delete given folders for mod_folder in mod_folders_to_remove { - delete_mod_folder(mod_folder)?; + delete_mod_folder(&mod_folder)?; } Ok(()) diff --git a/src-tauri/src/northstar/mod.rs b/src-tauri/src/northstar/mod.rs index a043632c..7bd0b0a3 100644 --- a/src-tauri/src/northstar/mod.rs +++ b/src-tauri/src/northstar/mod.rs @@ -5,25 +5,23 @@ use crate::{check_mod_version_number, constants::CORE_MODS}; use anyhow::anyhow; /// Returns the current Northstar version number as a string -pub fn get_northstar_version_number(game_path: String) -> Result<String, anyhow::Error> { - println!("{}", game_path); - // println!("{:?}", install_type); +pub fn get_northstar_version_number(game_path: &str) -> Result<String, anyhow::Error> { + log::info!("{}", game_path); // TODO: // Check if NorthstarLauncher.exe exists and check its version number let profile_folder = "R2Northstar"; - let initial_version_number = match check_mod_version_number(format!( - "{}/{}/mods/{}", - game_path, profile_folder, CORE_MODS[0] + let initial_version_number = match check_mod_version_number(&format!( + "{game_path}/{profile_folder}/mods/{}", + CORE_MODS[0] )) { Ok(version_number) => version_number, Err(err) => return Err(err), }; for core_mod in CORE_MODS { - let current_version_number = match check_mod_version_number(format!( - "{}/{}/mods/{}", - game_path, profile_folder, core_mod + let current_version_number = match check_mod_version_number(&format!( + "{game_path}/{profile_folder}/mods/{core_mod}", )) { Ok(version_number) => version_number, Err(err) => return Err(err), @@ -33,7 +31,7 @@ pub fn get_northstar_version_number(game_path: String) -> Result<String, anyhow: return Err(anyhow!("Found version number mismatch")); } } - println!("All mods same version"); + log::info!("All mods same version"); Ok(initial_version_number) } diff --git a/src-tauri/src/platform_specific/linux.rs b/src-tauri/src/platform_specific/linux.rs index eb9fbea6..4b9964e9 100644 --- a/src-tauri/src/platform_specific/linux.rs +++ b/src-tauri/src/platform_specific/linux.rs @@ -14,10 +14,10 @@ pub fn check_glibc_v() -> f32 { let lddvl: Vec<&str> = lddva.split('\n').collect(); let lddvlo = &lddvl[0]; let reg = Regex::new(r"(2.\d{2}$)").unwrap(); - for caps in reg.captures_iter(lddvlo) { + if let Some(caps) = reg.captures_iter(lddvlo).next() { return caps.get(1).unwrap().as_str().parse::<f32>().unwrap(); // theres prolly a better way ijdk how tho } - return 0.0; // this shouldnt ever be reached but it has to be here + 0.0 // this shouldnt ever be reached but it has to be here } /* diff --git a/src-tauri/src/platform_specific/windows.rs b/src-tauri/src/platform_specific/windows.rs index 21772b91..004beb6e 100644 --- a/src-tauri/src/platform_specific/windows.rs +++ b/src-tauri/src/platform_specific/windows.rs @@ -3,7 +3,7 @@ use anyhow::{anyhow, Result}; use crate::{check_is_valid_game_path, constants::TITANFALL2_ORIGIN_IDS}; -/// Runs a powershell command and parses output to get Titanfall2 install location on Origin +/// Gets Titanfall2 install location on Origin pub fn origin_install_location_detection() -> Result<String, anyhow::Error> { // Iterate over known Titanfall2 Origin IDs for origin_id in TITANFALL2_ORIGIN_IDS { @@ -18,14 +18,14 @@ pub fn origin_install_location_detection() -> Result<String, anyhow::Error> { return Ok(game_path_str.to_string()); } Err(err) => { - println!("{}", err.to_string()); + log::warn!("{}", err); continue; // Not a valid game path } } } } Err(err) => { - println!("Couldn't find {origin_id}: {err}") + log::warn!("Couldn't find {origin_id}: {err}") } } } diff --git a/src-tauri/src/repair_and_verify/mod.rs b/src-tauri/src/repair_and_verify/mod.rs index 9d020f15..ecf5e1ec 100644 --- a/src-tauri/src/repair_and_verify/mod.rs +++ b/src-tauri/src/repair_and_verify/mod.rs @@ -15,9 +15,9 @@ pub fn verify_game_files(game_install: GameInstall) -> Result<String, String> { #[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.clone())?; + rebuild_enabled_mods_json(&game_install)?; - let current_mods = get_enabled_mods(game_install.clone())?; + 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() { @@ -37,7 +37,7 @@ pub fn disable_all_but_core(game_install: GameInstall) -> Result<(), String> { /// 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, + game_install: &GameInstall, force: bool, ) -> Result<(), anyhow::Error> { // Get download directory @@ -51,7 +51,7 @@ pub fn clean_up_download_folder( // dbg!(download_dir_contents); let mut count = 0; - download_dir_contents.inspect(|_| count += 1).for_each(drop); + download_dir_contents.for_each(|_| count += 1); if count > 0 && !force { return Err(anyhow!("Folder not empty, not deleting")); @@ -84,7 +84,7 @@ pub fn get_log_list(game_install: GameInstall) -> Result<Vec<std::path::PathBuf> } } - if log_files.len() > 0 { + 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 index 9151ba7c..e9eb30d7 100644 --- a/src-tauri/src/thunderstore/mod.rs +++ b/src-tauri/src/thunderstore/mod.rs @@ -43,7 +43,7 @@ pub struct ThunderstoreModVersion { /// Queries Thunderstore packages API #[tauri::command] pub async fn query_thunderstore_packages_api() -> Result<Vec<ThunderstoreMod>, String> { - println!("Fetching Thunderstore API"); + log::info!("Fetching Thunderstore API"); // Fetches let url = "https://northstar.thunderstore.io/api/v1/package/"; @@ -66,7 +66,7 @@ pub async fn query_thunderstore_packages_api() -> Result<Vec<ThunderstoreMod>, S }; // Remove some mods from listing - let to_remove_set: HashSet<&str> = BLACKLISTED_MODS.iter().map(|s| s.as_ref()).collect(); + 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())) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 77a10d73..c24251e1 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "FlightCore", - "version": "1.10.2" + "version": "1.13.2" }, "tauri": { "allowlist": { |