From 0a505f460e5516eaed8928421502fa2c1096bb3c Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Fri, 30 Aug 2024 20:25:10 -0400 Subject: [PATCH] support: Compile mod info into support package and use a temp file when creating the package (#545) My theory still remains that users are uploading the zip before it's done being constructed (or it fails for some reason). So I switched to making it as a temp file, then copying that temp file over if everything succeeds. This should hopefully help... --- src-tauri/Cargo.lock | 17 ++++- src-tauri/Cargo.toml | 1 + src-tauri/src/commands/features/mods.rs | 4 +- src-tauri/src/commands/support.rs | 98 +++++++++++++++++++++++-- src-tauri/src/util/zip.rs | 4 +- 5 files changed, 110 insertions(+), 14 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ce56eebb..e659f5f2 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3113,6 +3113,7 @@ dependencies = [ "tar", "tauri", "tauri-build", + "tempfile", "thiserror", "tokio", "ts-rs", @@ -4909,14 +4910,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6076,6 +6078,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.42.2" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 753b394f..412e6b65 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -41,6 +41,7 @@ walkdir = "2.5.0" wgpu = "22.1.0" zip = { version = "2.2.0", features = ["deflate-zlib-ng"] } zip-extract = "0.2.1" +tempfile = "3.12.0" [target.'cfg(windows)'.dependencies] winreg = "0.52.0" diff --git a/src-tauri/src/commands/features/mods.rs b/src-tauri/src/commands/features/mods.rs index 2f17c323..eef4b7de 100644 --- a/src-tauri/src/commands/features/mods.rs +++ b/src-tauri/src/commands/features/mods.rs @@ -780,7 +780,9 @@ pub async fn uninstall_mod( .join("mods") .join(&source_name) .join(&mod_name); - std::fs::remove_dir_all(mod_dir)?; + if mod_dir.exists() { + std::fs::remove_dir_all(mod_dir)?; + } config_lock .uninstall_mod(game_name, mod_name, source_name) .map_err(|_| CommandError::GameFeatures("Unable to uninstall mod".to_owned()))?; diff --git a/src-tauri/src/commands/support.rs b/src-tauri/src/commands/support.rs index 1c381a23..718bbfdb 100644 --- a/src-tauri/src/commands/support.rs +++ b/src-tauri/src/commands/support.rs @@ -1,9 +1,13 @@ +use log::info; use serde::{Deserialize, Serialize}; use std::{ + fs, io::{BufWriter, Write}, path::Path, }; use sysinfo::{Disks, System}; +use tempfile::NamedTempFile; +use walkdir::WalkDir; use zip::write::SimpleFileOptions; use tauri::api::path::config_dir; @@ -83,7 +87,7 @@ pub struct SupportPackage { fn dump_per_game_info( config_lock: &tokio::sync::MutexGuard<'_, LauncherConfig>, package: &mut SupportPackage, - zip_file: &mut zip::ZipWriter, + zip_file: &mut zip::ZipWriter<&std::fs::File>, install_path: &Path, game_name: &str, ) -> Result<(), CommandError> { @@ -186,6 +190,76 @@ fn dump_per_game_info( dir_diff::is_different(data_dir.join("goal_src"), version_data_dir.join("goal_src")) .unwrap_or(true); } + + // Append mod settings and logs + let mod_directory = install_path.join("features").join(&game_name).join("mods"); + info!("Scanning mod directory {mod_directory:?}"); + if mod_directory.exists() { + let mod_source_iter = WalkDir::new(mod_directory) + .into_iter() + .filter_map(|e| e.ok()); + for source_entry in mod_source_iter { + let mod_source_path = source_entry.path(); + let mod_source_name = mod_source_path.file_name().unwrap().to_string_lossy(); // TODO + if mod_source_path.is_dir() { + let mod_iter = WalkDir::new(mod_source_path) + .max_depth(0) + .into_iter() + .filter_map(|e| e.ok()); + for mod_entry in mod_iter { + let mod_path = mod_entry.path(); + if mod_path.is_dir() { + let folder_name = mod_path.file_name().unwrap().to_string_lossy(); + // Check for settings + if folder_name.eq("_settings") { + if mod_path.exists() { + append_dir_contents_to_zip( + zip_file, + &mod_path, + format!("Game Settings and Saves/{game_name}/mods/{mod_source_name}/settings") + .as_str(), + vec!["gc", "json"], + ) + .map_err(|_| { + CommandError::Support( + "Unable to append mod settings to support package".to_owned(), + ) + })?; + append_dir_contents_to_zip( + zip_file, + &mod_path, + format!("Game Settings and Saves/{game_name}/mods/{mod_source_name}/saves") + .as_str(), + vec!["bin"], + ) + .map_err(|_| { + CommandError::Support("Unable to append mod saves to support package".to_owned()) + })?; + } + } else { + // Get logs for each individual mod + let mod_log_folder = mod_path.join("data").join("log"); + if mod_log_folder.exists() { + append_dir_contents_to_zip( + zip_file, + &mod_log_folder, + format!( + "Game Logs and ISO Info/{game_name}/mods/{mod_source_name}/{folder_name}/logs" + ) + .as_str(), + vec!["log", "json", "txt"], + ) + .map_err(|_| { + CommandError::Support("Unable to append mod logs to support package".to_owned()) + })?; + } + } + } + } + } + } + } + Ok(()) } @@ -270,9 +344,9 @@ pub async fn generate_support_package( // Create zip file let save_path = Path::new(&user_path); - let save_file = std::fs::File::create(save_path) + let save_file = NamedTempFile::new() .map_err(|_| CommandError::Support("Unable to create support file".to_owned()))?; - let mut zip_file = zip::ZipWriter::new(save_file); + let mut zip_file = zip::ZipWriter::new(save_file.as_file()); // Save Launcher config folder let launcher_config_dir = match app_handle.path_resolver().app_config_dir() { @@ -362,15 +436,23 @@ pub async fn generate_support_package( .map_err(|_| CommandError::Support("Unable to finalize zip file".to_owned()))?; // Sanity check that the zip file was actually made correctly - let info_found = - check_if_zip_contains_top_level_file(&save_path.to_path_buf(), "support-info.json".to_string()) - .map_err(|_| { - CommandError::Support("Support package was unable to be written properly".to_owned()) - })?; + let info_found = check_if_zip_contains_top_level_file( + &save_file.path().to_path_buf(), + "support-info.json".to_string(), + ) + .map_err(|_| { + CommandError::Support("Support package was unable to be written properly".to_owned()) + })?; if !info_found { return Err(CommandError::Support( "Support package was unable to be written properly".to_owned(), )); } + // Seems good, move it to the user's intended destination + fs::rename(&save_file.path(), save_path).map_err(|_| { + CommandError::Support( + "Support package was unable to be moved from it's temporary file location".to_owned(), + ) + })?; Ok(()) } diff --git a/src-tauri/src/util/zip.rs b/src-tauri/src/util/zip.rs index 422d2684..334fc14f 100644 --- a/src-tauri/src/util/zip.rs +++ b/src-tauri/src/util/zip.rs @@ -10,7 +10,7 @@ use walkdir::WalkDir; use zip::write::SimpleFileOptions; pub fn append_dir_contents_to_zip( - zip_file: &mut zip::ZipWriter, + zip_file: &mut zip::ZipWriter<&File>, dir: &Path, internal_folder: &str, allowed_extensions: Vec<&str>, @@ -66,7 +66,7 @@ pub fn append_dir_contents_to_zip( } pub fn append_file_to_zip( - zip_file: &mut zip::ZipWriter, + zip_file: &mut zip::ZipWriter<&File>, src: &Path, path_in_zip: &str, ) -> zip::result::ZipResult<()> {