From 25791906cc8c81368af5718f8ec6ee8b4f428b31 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Mon, 20 Mar 2023 18:55:50 +0100 Subject: fix: Add error handling if default EA App path (#211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Add error handling if default EA App path We cannot install to `C:\Program Files\EA Games\Titanfall2` cause Windows™ As such if install fails we check for that path and show according error message * fix: Check only for `Program Files` path instead of the full one As the issue is technically the permissions with `Program Files`, not the EA Games subdirectory... * fix: Format check error --- src-tauri/src/lib.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index ee3c91ed..050b4238 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -239,12 +239,27 @@ pub async fn install_northstar( ..Default::default() }); - do_install( + match do_install( 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()) } -- cgit v1.2.3 From 36fdc302bef162d213d6a026c99614673b24a069 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Tue, 21 Mar 2023 09:31:36 +0100 Subject: feat: Proper logging (#223) * feat: Initial setup of sentry logging * refactor: Replace some println with log call Not replacing all cause too large diff --- src-tauri/Cargo.lock | 73 ++++++++++++++++++++++++++++++++++- src-tauri/Cargo.toml | 5 +++ src-tauri/src/github/release_notes.rs | 6 +-- src-tauri/src/lib.rs | 13 ++----- src-tauri/src/main.rs | 15 +++++-- src-tauri/src/northstar/mod.rs | 5 +-- 6 files changed, 97 insertions(+), 20 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 70e50a8e..954b80a8 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -96,9 +96,12 @@ dependencies = [ "game-scanner", "json5", "libthermite", + "log", + "pretty_env_logger", "regex", "reqwest", "sentry", + "sentry-log", "serde", "serde_json", "steamlocate", @@ -163,6 +166,17 @@ dependencies = [ "url", ] +[[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" @@ -878,6 +892,19 @@ dependencies = [ "cfg-if", ] +[[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" @@ -1453,6 +1480,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" 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" @@ -1542,6 +1578,15 @@ version = "1.0.2" 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" @@ -2208,7 +2253,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", ] @@ -2672,6 +2717,16 @@ version = "0.1.1" 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" @@ -2774,6 +2829,12 @@ dependencies = [ "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" @@ -3302,6 +3363,16 @@ dependencies = [ "sentry-core", ] +[[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" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 0e972064..2d803e7e 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -25,7 +25,9 @@ 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" # Error messages @@ -54,6 +56,9 @@ chrono = "0.4.23" 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" diff --git a/src-tauri/src/github/release_notes.rs b/src-tauri/src/github/release_notes.rs index b59358ec..e8e5c1fa 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 { - 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 { #[tauri::command] pub async fn get_newest_flightcore_version() -> Result { // 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) } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 050b4238..2e0a0250 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,7 +1,6 @@ use std::env; use anyhow::{anyhow, Context, Result}; -use sentry::{add_breadcrumb, Breadcrumb, Level}; mod northstar; @@ -61,7 +60,7 @@ pub fn check_mod_version_number(path_to_mod_folder: String) -> Result return Err(anyhow!("No version number found")), }; - println!("{}", mod_version_number); + log::info!("{}", mod_version_number); Ok(mod_version_number.to_string()) } @@ -132,7 +131,7 @@ pub fn find_game_install_location() -> Result { 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 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 { @@ -231,13 +230,7 @@ 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); match do_install( nmod.versions.get(&nmod.latest).unwrap(), diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 50e439c8..0733d5a0 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -45,6 +45,14 @@ use tokio::time::sleep; struct Counter(Arc>); 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(( @@ -222,10 +230,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) } } @@ -353,7 +361,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/northstar/mod.rs b/src-tauri/src/northstar/mod.rs index a043632c..f3f8cde3 100644 --- a/src-tauri/src/northstar/mod.rs +++ b/src-tauri/src/northstar/mod.rs @@ -6,8 +6,7 @@ use anyhow::anyhow; /// Returns the current Northstar version number as a string pub fn get_northstar_version_number(game_path: String) -> Result { - println!("{}", game_path); - // println!("{:?}", install_type); + log::info!("{}", game_path); // TODO: // Check if NorthstarLauncher.exe exists and check its version number @@ -33,7 +32,7 @@ pub fn get_northstar_version_number(game_path: String) -> Result Date: Wed, 22 Mar 2023 14:18:11 +0100 Subject: fix: Address clippy errors in glibc parsing code (#226) --- src-tauri/src/lib.rs | 3 +-- src-tauri/src/platform_specific/linux.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 2e0a0250..5bdc82c4 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -80,8 +80,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 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::().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 } /* -- cgit v1.2.3 From 7f25d130c1e4ec8f57d91f87cb5420696e9ed774 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 23 Mar 2023 00:07:26 +0100 Subject: fix: Remove unnecessary `.to_string()` (#230) Thanks clippy <3 --- src-tauri/src/lib.rs | 2 +- src-tauri/src/platform_specific/windows.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 5bdc82c4..964039eb 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -385,7 +385,7 @@ pub fn get_enabled_mods(game_install: GameInstall) -> 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/platform_specific/windows.rs b/src-tauri/src/platform_specific/windows.rs index 21772b91..5d054808 100644 --- a/src-tauri/src/platform_specific/windows.rs +++ b/src-tauri/src/platform_specific/windows.rs @@ -18,7 +18,7 @@ pub fn origin_install_location_detection() -> Result { return Ok(game_path_str.to_string()); } Err(err) => { - println!("{}", err.to_string()); + println!("{}", err); continue; // Not a valid game path } } -- cgit v1.2.3 From c18ea937b568df72e48696daaec321bd0d6fda66 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 23 Mar 2023 00:07:38 +0100 Subject: fix: Address clippy warnings regarding format!() (#229) Use the varible name directly inside the string --- src-tauri/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 964039eb..0c17caa8 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -52,7 +52,7 @@ pub struct NorthstarServer { /// Check version number of a mod pub fn check_mod_version_number(path_to_mod_folder: String) -> Result { // 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()) { @@ -128,13 +128,13 @@ pub fn find_game_install_location() -> Result { /// 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(); 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(()) } @@ -191,7 +191,7 @@ async fn do_install(nmod: &thermite::model::ModVersion, game_path: &std::path::P std::fs::create_dir_all(download_directory.clone())?; let download_path = format!("{}/{}", download_directory.clone(), filename); - println!("{}", download_path); + println!("{download_path}"); let nfile = thermite::core::manage::download_file(&nmod.url, download_path).unwrap(); -- cgit v1.2.3 From a8c3c12361b66c7cc29937cfad9475db985a5d41 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 26 Mar 2023 01:13:19 +0100 Subject: fix: Remove unnecessary borrows (#231) According to `clippy` --- src-tauri/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0c17caa8..26878866 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -162,7 +162,7 @@ fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> { .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() @@ -318,7 +318,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()); -- cgit v1.2.3 From 673297bd93d9824400fda41158d0e457cf92adfa Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 26 Mar 2023 01:25:10 +0100 Subject: fix: Adjust code for single iteration loop (#232) * fix: Adjust code for single iteration loop `clippy` said this is way is better... * refactor: Implement more compact suggestion * refactor: Implement more compact suggestion --- src-tauri/src/lib.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 26878866..e9791835 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -333,29 +333,16 @@ 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; - } - // 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; - } - false + s.processes_by_name("Origin.exe").next().is_some() + || s.processes_by_name("EADesktop.exe").next().is_some() } /// 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 + sysinfo::System::new_all() + .processes_by_name("NorthstarLauncher.exe") + .next() + .is_some() } /// Helps with converting release candidate numbers which are different on Thunderstore -- cgit v1.2.3 From fe3cb8202f4332a547c15c1e9fb46eb2a5f7a470 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 26 Mar 2023 14:25:58 +0200 Subject: refactor: Replace all `println!()` with log statements (#236) * refactor: Replace all println with calls to logger in `do_install()` * refactor: Replace all println with calls to logger in `verify_install_location()` * refactor: Replace all println with calls to logger in `get_northstar_release_notes()` * refactor: Replace all println with calls to logger in `update_northstar_caller()` * refactor: Replace all println with calls to logger in `install_northstar_caller()` * refactor: Replace all println with calls to logger in `apply_launcher_pr()` * refactor: Replace all println with calls to logger in `apply_mods_pr()` * refactor: Replace all println with calls to logger in `find_game_install_location()` * refactor: Replace all println with calls to logger in `install_mod_caller()` * refactor: Replace all println with calls to logger in `set_mod_enabled_status()` * refactor: Replace all println with calls to logger in `parse_installed_mods()` * refactor: Replace all println with calls to logger in `origin_install_location_detection()` * refactor: Replace all println with calls to logger in `query_thunderstore_packages_api()` * refactor: Replace all println with calls to logger in `add_batch_file()` * refactor: Replace all println with calls to logger in `extract()` * refactor: Replace all println with calls to logger in `check_is_northstar_outdated()` --- src-tauri/src/github/pull_requests.rs | 10 +++++----- src-tauri/src/github/release_notes.rs | 2 +- src-tauri/src/lib.rs | 18 +++++++++--------- src-tauri/src/main.rs | 14 +++++++------- src-tauri/src/mod_management/mod.rs | 8 ++++---- src-tauri/src/platform_specific/windows.rs | 4 ++-- src-tauri/src/thunderstore/mod.rs | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/github/pull_requests.rs b/src-tauri/src/github/pull_requests.rs index 4bba2a2c..45a11c1c 100644 --- a/src-tauri/src/github/pull_requests.rs +++ b/src-tauri/src/github/pull_requests.rs @@ -208,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), } } @@ -281,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(()) } @@ -309,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"); } }; @@ -331,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 e8e5c1fa..edba5761 100644 --- a/src-tauri/src/github/release_notes.rs +++ b/src-tauri/src/github/release_notes.rs @@ -98,7 +98,7 @@ pub async fn get_northstar_release_notes() -> Result, String> { let release_info_vector: Vec = 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); } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e9791835..3bcbdfa6 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -102,10 +102,10 @@ pub fn find_game_install_location() -> Result { }; 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 @@ -119,7 +119,7 @@ pub fn find_game_install_location() -> Result { return Ok(game_install); } Err(err) => { - println!("{}", err); + log::info!("{}", err); } }; @@ -157,7 +157,7 @@ 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; @@ -171,7 +171,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")?; } @@ -191,18 +191,18 @@ async fn do_install(nmod: &thermite::model::ModVersion, game_path: &std::path::P std::fs::create_dir_all(download_directory.clone())?; let download_path = format!("{}/{}", download_directory.clone(), filename); - println!("{download_path}"); + log::info!("Download path: {download_path}"); let nfile = thermite::core::manage::download_file(&nmod.url, download_path).unwrap(); - println!("Extracting Northstar..."); + 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!"); Ok(()) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index d5fef9cb..4d03e967 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -234,7 +234,7 @@ async fn check_is_northstar_outdated( 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()); } @@ -266,7 +266,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 } } @@ -284,11 +284,11 @@ async fn install_northstar_caller( game_path: String, northstar_package_name: Option, ) -> Result { - println!("Running"); + log::info!("Running"); match install_northstar(&game_path, northstar_package_name).await { Ok(_) => Ok(true), Err(err) => { - println!("{}", err); + log::error!("{}", err); Err(err.to_string()) } } @@ -300,13 +300,13 @@ async fn update_northstar_caller( game_path: String, northstar_package_name: Option, ) -> Result { - 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 { Ok(_) => Ok(true), Err(err) => { - println!("{}", err); + log::error!("{}", err); Err(err.to_string()) } } @@ -331,7 +331,7 @@ async fn install_mod_caller( 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(()) diff --git a/src-tauri/src/mod_management/mod.rs b/src-tauri/src/mod_management/mod.rs index d2b5040b..eff3ec01 100644 --- a/src-tauri/src/mod_management/mod.rs +++ b/src-tauri/src/mod_management/mod.rs @@ -94,8 +94,8 @@ pub fn set_mod_enabled_status( let mut res: serde_json::Value = match get_enabled_mods(game_install.clone()) { 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())?; @@ -108,7 +108,7 @@ pub fn set_mod_enabled_status( // 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"); + log::info!("Value not found in `enabledmod.json`. Rebuilding file"); rebuild_enabled_mods_json(game_install.clone())?; // Then try again @@ -189,7 +189,7 @@ fn parse_installed_mods(game_install: GameInstall) -> Result, 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; } }; diff --git a/src-tauri/src/platform_specific/windows.rs b/src-tauri/src/platform_specific/windows.rs index 2862fde2..004beb6e 100644 --- a/src-tauri/src/platform_specific/windows.rs +++ b/src-tauri/src/platform_specific/windows.rs @@ -18,14 +18,14 @@ pub fn origin_install_location_detection() -> Result { return Ok(game_path_str.to_string()); } Err(err) => { - println!("{}", err); + 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/thunderstore/mod.rs b/src-tauri/src/thunderstore/mod.rs index 9151ba7c..483968cf 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, String> { - println!("Fetching Thunderstore API"); + log::info!("Fetching Thunderstore API"); // Fetches let url = "https://northstar.thunderstore.io/api/v1/package/"; -- cgit v1.2.3 From b4e68d085da69e68529720bd3faf1dd3ad369a74 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 2 Apr 2023 18:02:22 +0200 Subject: fix: Another set of various clippy fixes (#246) * fix: Remove unnecessary clone * fix: Remove redundant field name in struct init * fix: Single-char string constant used as pattern * fix: calling `push_str()` using a single-character string literal * fix: this pattern reimplements `Option::unwrap_or` * fix: Remove unnecessary borrow * fix: Remove useless use of `format!` * fix: called `inspect(..).for_each(..)` on an `Iterator` * fix: Formatting --- src-tauri/src/github/mod.rs | 19 ++++++++++++------- src-tauri/src/lib.rs | 9 +++------ src-tauri/src/repair_and_verify/mod.rs | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/src/github/mod.rs b/src-tauri/src/github/mod.rs index 87ea629c..c46d7c60 100644 --- a/src-tauri/src/github/mod.rs +++ b/src-tauri/src/github/mod.rs @@ -49,7 +49,7 @@ pub fn get_list_of_tags() -> Result, String> { // Fetch the list of tags for the repository as a `Vec`. let tags_url = format!("https://api.github.com/repos/{}/tags", FLIGHTCORE_REPO_NAME); - let tags: Vec = client.get(&tags_url).send().unwrap().json().unwrap(); + let tags: Vec = 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 = tags @@ -102,10 +102,15 @@ pub fn compare_tags(first_tag: Tag, second_tag: Tag) -> Result { commit.sha, commit.commit.message.split('\n').next().unwrap() ); - patch_notes.push(format!( - "{}", - 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); @@ -140,7 +145,7 @@ fn generate_flightcore_release_notes(commits: Vec) -> String { release_notes.push_str(&format!("- {}\n", commit_message)); } - release_notes.push_str("\n"); + release_notes.push('\n'); } } } @@ -155,7 +160,7 @@ fn group_commits_by_type(commits: Vec) -> HashMap> { let mut other_commits: Vec = vec![]; for commit in commits { - let commit_parts: Vec<&str> = commit.splitn(2, ":").collect(); + 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(); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 3bcbdfa6..ff1445e5 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -113,7 +113,7 @@ pub fn find_game_install_location() -> Result { 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); @@ -190,7 +190,7 @@ async fn do_install(nmod: &thermite::model::ModVersion, game_path: &std::path::P std::fs::create_dir_all(download_directory.clone())?; - let download_path = format!("{}/{}", download_directory.clone(), filename); + let download_path = format!("{}/{}", download_directory, filename); log::info!("Download path: {download_path}"); let nfile = thermite::core::manage::download_file(&nmod.url, download_path).unwrap(); @@ -282,10 +282,7 @@ 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 { diff --git a/src-tauri/src/repair_and_verify/mod.rs b/src-tauri/src/repair_and_verify/mod.rs index 31b31040..b3dbe3b2 100644 --- a/src-tauri/src/repair_and_verify/mod.rs +++ b/src-tauri/src/repair_and_verify/mod.rs @@ -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")); -- cgit v1.2.3 From dd1e870b279f990981dcbaff79c9db58fde18ba9 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 6 Apr 2023 15:06:38 +0200 Subject: feat: Add ability to launch via Steam to DevView (#178) * feat: Add ability to launch via Steam * document what get_titanfall_proton() does * revert explicit use of newly imported Path * Format source code to pass CI * Use new steamlocate compat_tool helper * cargo fmt * fix: Address various clippy issues Addresses clippy warnings caused by newly introduced code * fix: Cargo toml dependency formatting --- src-tauri/Cargo.lock | 56 +++++++++++++++++---- src-tauri/Cargo.toml | 4 +- src-tauri/src/constants.rs | 3 ++ src-tauri/src/lib.rs | 99 +++++++++++++++++++++++++++++++++++-- src-tauri/src/main.rs | 10 ++++ src-vue/src/plugins/store.ts | 26 ++++++++++ src-vue/src/views/DeveloperView.vue | 7 +++ 7 files changed, 191 insertions(+), 14 deletions(-) (limited to 'src-tauri/src/lib.rs') diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ec1756b4..733831e4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -97,6 +97,7 @@ dependencies = [ "json5", "libthermite", "log", + "open", "pretty_env_logger", "regex", "reqwest", @@ -800,16 +801,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]] @@ -833,6 +834,17 @@ dependencies = [ "winapi", ] +[[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" @@ -1136,7 +1148,7 @@ dependencies = [ "serde_yaml", "sysinfo 0.23.13", "url", - "winreg", + "winreg 0.10.1", ] [[package]] @@ -1864,6 +1876,20 @@ dependencies = [ "thiserror", ] +[[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" @@ -3054,7 +3080,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "winreg 0.10.1", ] [[package]] @@ -3652,14 +3678,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]] @@ -5002,6 +5030,16 @@ dependencies = [ "winapi", ] +[[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" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c7d52d89..2267c239 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -29,7 +29,7 @@ tokio = { version = "1", features = ["full"] } 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 @@ -61,6 +61,8 @@ 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/src/constants.rs b/src-tauri/src/constants.rs index 0f4e9ab4..8c88df1e 100644 --- a/src-tauri/src/constants.rs +++ b/src-tauri/src/constants.rs @@ -29,6 +29,9 @@ 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", diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index ff1445e5..a3553448 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,4 @@ -use std::env; +use std::{env, fs, path::Path, time::Duration}; use anyhow::{anyhow, Context, Result}; @@ -14,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, @@ -92,7 +95,7 @@ pub fn find_game_install_location() -> Result { // 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); @@ -328,6 +331,93 @@ pub fn launch_northstar( )) } +/// Prepare Northstar and Launch through Steam using the Browser Protocol +pub fn launch_northstar_steam( + game_install: GameInstall, + _bypass_checks: Option, +) -> Result { + if !matches!(game_install.install_type, InstallType::STEAM) { + return Err("Titanfall2 was not installed via Steam".to_string()); + } + + 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()); + } + } + + // 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()); + } + + 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(); s.processes_by_name("Origin.exe").next().is_some() @@ -336,10 +426,11 @@ pub fn check_origin_running() -> bool { /// Checks if Northstar process is running pub fn check_northstar_running() -> bool { - sysinfo::System::new_all() - .processes_by_name("NorthstarLauncher.exe") + let s = sysinfo::System::new_all(); + s.processes_by_name("NorthstarLauncher.exe") .next() .is_some() + || s.processes_by_name("Titanfall2.exe").next().is_some() } /// Helps with converting release candidate numbers which are different on Thunderstore diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 21045db1..16b951ec 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -121,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, @@ -323,6 +324,15 @@ async fn launch_northstar_caller( launch_northstar(game_install, bypass_checks) } +#[tauri::command] +/// Launches Northstar +async fn launch_northstar_steam_caller( + game_install: GameInstall, + bypass_checks: Option, +) -> Result { + launch_northstar_steam(game_install, bypass_checks) +} + #[tauri::command] /// Installs the specified mod async fn install_mod_caller( diff --git a/src-vue/src/plugins/store.ts b/src-vue/src/plugins/store.ts index 60208879..cdbd6738 100644 --- a/src-vue/src/plugins/store.ts +++ b/src-vue/src/plugins/store.ts @@ -243,6 +243,32 @@ export const store = createStore({ break; } }, + async launchGameSteam(state: any, no_checks = false) { + let game_install = { + game_path: state.game_path, + install_type: state.install_type + } as GameInstall; + + await invoke("launch_northstar_steam_caller", { gameInstall: game_install, bypassChecks: no_checks }) + .then((message) => { + ElNotification({ + title: 'Success', + type: 'success', + position: 'bottom-right' + }); + }) + .catch((error) => { + console.error(error); + ElNotification({ + title: 'Error', + message: error, + type: 'error', + position: 'bottom-right' + }); + }); + + return; + }, async fetchReleaseNotes(state: FlightCoreStore) { if (state.releaseNotes.length !== 0) return; state.releaseNotes = await invoke("get_northstar_release_notes"); diff --git a/src-vue/src/views/DeveloperView.vue b/src-vue/src/views/DeveloperView.vue index bca473fb..7712756c 100644 --- a/src-vue/src/views/DeveloperView.vue +++ b/src-vue/src/views/DeveloperView.vue @@ -59,6 +59,10 @@ Launch Northstar (bypass all checks) + + Launch Northstar via Steam + +

Mod install:

@@ -156,6 +160,9 @@ export default defineComponent({ async launchGameWithoutChecks() { this.$store.commit('launchGame', true); }, + async launchGameViaSteam() { + this.$store.commit('launchGameSteam', true); + }, async getInstalledMods() { let game_install = { game_path: this.$store.state.game_path, -- cgit v1.2.3 From 2be2ef6ce5232ea859ae814c401cd99e87f57af9 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:17:00 +0200 Subject: feat: Show download progress for installing Northstar (#200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Bump libthermite to 0.5.3 This adds a change needed for making progressbar work on dowload * wip: First attempt at showing download progress Simply prints it to JavaScript console for now * feat: Emit download progress at most every 250ms If we spam emit too much we use a lot of extra resources, slowing down the actual download * feat: Initial messages for extracting * feat: Add install state enum * refactor: Change payload to current + total size downloaded * fix: Remove extra emit * fix: Remove extra emit * refactor: Rename struct * refactor: Move struct to top of file * feat: Add TypeScript bindings * feat: Add console logs for printing state for now * fix: Remove duplicate identifier * feat: Initial progressbar in frontend * fix: Remove event listener added for debugging * feat: Display status and downloaded bytes * feat: Set loading bar to indeterminate on extract * fix: Phrasing in comment * feat: Add i18n for progress state * refactor: Adjust control flow do not show downloaded size anymore during extraction * fix: Manually specify progressbar size * fix: Update download progress every 100ms instead of 250ms Gives impression of faster / more fluent download. * feat: layout does not move when progress bar is hidden * feat: fix progress bar width to 200px * refactor: put services container in a flex container, for it not to overlap play button * refactor: export progress bar to dedicated component file * refactor: Update status first outside of branch * fix: Proper typing of event payload * fix: Do not assign to unused variable --------- Co-authored-by: Rémy Raes --- src-tauri/bindings/InstallProgress.ts | 4 + src-tauri/bindings/InstallState.ts | 3 + src-tauri/src/lib.rs | 74 ++++++++++++++++++- src-tauri/src/main.rs | 6 +- src-vue/src/components/InstallProgressBar.vue | 102 ++++++++++++++++++++++++++ src-vue/src/components/PlayButton.vue | 48 ++++++------ src-vue/src/i18n/lang/en.json | 4 +- src-vue/src/views/PlayView.vue | 17 +++-- src-vue/src/views/RepairView.vue | 11 +++ 9 files changed, 231 insertions(+), 38 deletions(-) create mode 100644 src-tauri/bindings/InstallProgress.ts create mode 100644 src-tauri/bindings/InstallState.ts create mode 100644 src-vue/src/components/InstallProgressBar.vue (limited to 'src-tauri/src/lib.rs') 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/src/lib.rs b/src-tauri/src/lib.rs index a3553448..56bc590c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,4 @@ -use std::{env, fs, path::Path, time::Duration}; +use std::{cell::RefCell, env, fs, path::Path, time::Duration, time::Instant}; use anyhow::{anyhow, Context, Result}; @@ -52,6 +52,22 @@ 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 { // println!("{}", format!("{}/mod.json", path_to_mod_folder)); @@ -187,7 +203,11 @@ 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()); @@ -196,7 +216,43 @@ async fn do_install(nmod: &thermite::model::ModVersion, game_path: &std::path::P let download_path = format!("{}/{}", download_directory, filename); log::info!("Download path: {download_path}"); - let nfile = thermite::core::manage::download_file(&nmod.url, download_path).unwrap(); + let last_emit = RefCell::new(Instant::now()); // Keep track of the last time a signal was emitted + let nfile = 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(); + } + } + }, + ) + .unwrap(); + + 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)?; @@ -206,11 +262,22 @@ async fn do_install(nmod: &thermite::model::ModVersion, game_path: &std::path::P std::fs::remove_dir_all(download_directory).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_path: &str, northstar_package_name: Option, ) -> Result { @@ -235,6 +302,7 @@ pub async fn install_northstar( log::info!("Install path \"{}\"", game_path); match do_install( + window, nmod.versions.get(&nmod.latest).unwrap(), std::path::Path::new(game_path), ) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 16b951ec..76e8833e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -284,11 +284,12 @@ 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, ) -> Result { log::info!("Running"); - match install_northstar(&game_path, northstar_package_name).await { + match install_northstar(window, &game_path, northstar_package_name).await { Ok(_) => Ok(true), Err(err) => { log::error!("{}", err); @@ -300,13 +301,14 @@ 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, ) -> Result { 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) => { log::error!("{}", err); diff --git a/src-vue/src/components/InstallProgressBar.vue b/src-vue/src/components/InstallProgressBar.vue new file mode 100644 index 00000000..d0c2047c --- /dev/null +++ b/src-vue/src/components/InstallProgressBar.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/src-vue/src/components/PlayButton.vue b/src-vue/src/components/PlayButton.vue index 3efcc9f5..208b4703 100644 --- a/src-vue/src/components/PlayButton.vue +++ b/src-vue/src/components/PlayButton.vue @@ -83,10 +83,10 @@ export default defineComponent({ return this.showReleaseSwitch ? 'border-radius: 2px 0 0 2px;' : 'border-radius: 2px'; - } + }, }, methods: { - launchGame() { + async launchGame() { this.$store.commit('launchGame'); } } @@ -94,30 +94,31 @@ export default defineComponent({