diff --git a/package.json b/package.json index 1c8bdc90..73e6d37b 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "svelte": "^3.58.0", "svelte-preprocess": "^5.0.3", "tailwindcss": "^3.2.7", - "typescript": "^4.9.5", + "typescript": "^5.0.3", "vite": "^4.1.4" }, "dependencies": { diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 9ee31bd1..227469bb 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -775,6 +775,15 @@ dependencies = [ "walkdir", ] +[[package]] +name = "directories" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74be3be809c18e089de43bdc504652bb2bc473fca8756131f8689db8cf079ba9" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -785,6 +794,17 @@ dependencies = [ "dirs-sys-next", ] +[[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" @@ -2258,8 +2278,10 @@ dependencies = [ name = "opengoal-launcher" version = "2.0.6" dependencies = [ + "backtrace", "chrono", "dir-diff", + "directories", "fern", "flate2", "fs_extra", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b86ddd7e..8378cee1 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -15,26 +15,28 @@ rust-version = "1.61" tauri-build = { version = "1.2.1", features = [] } [dependencies] -fs_extra = "1.3.0" -serde_json = "1.0.95" -serde = { version = "1.0", features = ["derive"] } -tauri = { version = "1.2.4", features = ["api-all", "devtools", "reqwest-client"] } -zip-extract = "0.1.1" -zip = { version = "0.6.2" } -fern = { version = "0.6.1", features = ["date-based","colored"] } +backtrace = "0.3.67" chrono = "0.4.23" +dir-diff = "0.3.2" +directories = "5.0.0" +fern = { version = "0.6.1", features = ["date-based","colored"] } +flate2 = "1.0.25" +fs_extra = "1.3.0" +futures-util = "0.3.26" log = "0.4.17" reqwest = { version = "0.11", features = ["json"] } -tokio = { version = "1", features = ["full"] } -futures-util = "0.3.26" -sysinfo = "0.28.4" -wgpu = "0.15.1" -walkdir = "2.3.2" -dir-diff = "0.3.2" -thiserror = "1.0.40" rev_buf_reader = "0.3.0" -flate2 = "1.0.25" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.95" +sysinfo = "0.28.4" tar = "0.4.38" +tauri = { version = "1.2.4", features = ["api-all", "devtools", "reqwest-client"] } +thiserror = "1.0.40" +tokio = { version = "1", features = ["full"] } +walkdir = "2.3.2" +wgpu = "0.15.1" +zip = { version = "0.6.2" } +zip-extract = "0.1.1" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 226238d9..8e117ac1 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -27,6 +27,8 @@ pub enum CommandError { #[error("{0}")] OSOperation(String), #[error("{0}")] + WindowManagement(String), + #[error("{0}")] BinaryExecution(String), #[error("{0}")] Support(String), diff --git a/src-tauri/src/commands/window.rs b/src-tauri/src/commands/window.rs index d5eaba46..21d95784 100644 --- a/src-tauri/src/commands/window.rs +++ b/src-tauri/src/commands/window.rs @@ -5,14 +5,50 @@ use tauri::Manager; use super::CommandError; #[tauri::command] -pub async fn close_splashscreen(window: tauri::Window) { +pub async fn open_main_window(handle: tauri::AppHandle) -> Result<(), CommandError> { + // NOTE: + // When you create multiple static windows (inside the conf file) + // they are actually all running in the background + // + // This seemed to sometimes create a race condition where the app was not fully setup + // and when a panic hook was added that exited the process, the app would crash. + // + // So instead we make the main window at runtime, and close the splashscreen + + // Create main window + // { + // "title": "OpenGOAL Launcher", + // "label": "main", + // "width": 800, + // "height": 600, + // "resizable": false, + // "fullscreen": false, + // "visible": false, + // "center": true, + // "decorations": false + // }, + log::info!("Creating main window"); + tauri::WindowBuilder::new( + &handle, + "main", /* the unique window label */ + tauri::WindowUrl::App("index.html".parse().unwrap()), + ) + .title("OpenGOAL Launcher") + .resizable(false) + .fullscreen(false) + .visible(true) + .center() + .decorations(false) + .build() + .map_err(|_| CommandError::WindowManagement(format!("Unable to create main launcher window")))?; + log::info!("Closing splash window"); // Close splashscreen - if let Some(splashscreen) = window.get_window("splashscreen") { - splashscreen.close().unwrap(); + if let Some(splashscreen) = handle.app_handle().get_window("splashscreen") { + splashscreen + .close() + .map_err(|_| CommandError::WindowManagement(format!("Unable to close splash window")))?; } - // Show main window - // TODO - cleanup this, return an error if we can't close it - window.get_window("main").unwrap().show().unwrap(); + Ok(()) } #[tauri::command] diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 9fe4193e..54acd38c 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,19 +3,57 @@ windows_subsystem = "windows" )] +use directories::UserDirs; use fern::colors::{Color, ColoredLevelConfig}; use tauri::{Manager, RunEvent}; use util::file::create_dir; -use std::env; +use backtrace::Backtrace; +use std::{env, io::Write}; mod commands; mod config; mod textures; mod util; +fn log_crash(panic_info: Option<&std::panic::PanicInfo>, error: Option) { + let backtrace = Backtrace::new(); + let log_contents; + if let Some(panic_info) = panic_info { + log_contents = format!("panic occurred: {:?}\n{:?}", panic_info, backtrace); + } else if let Some(error) = error { + log_contents = format!( + "unexpected app error occurred: {:?}\n{:?}", + error, backtrace + ); + } else { + log_contents = format!("unexpected error occurred: {:?}", backtrace); + } + log::error!("{}", log_contents); + if let Some(user_dirs) = UserDirs::new() { + if let Some(desktop_dir) = user_dirs.desktop_dir() { + match std::fs::File::create(desktop_dir.join("og-launcher-crash.log")) { + Ok(mut file) => { + if let Err(err) = file.write_all(log_contents.as_bytes()) { + log::error!("unable to log crash report to a file - {:?}", err) + } + } + Err(err) => log::error!("unable to log crash report to a file - {:?}", err), + } + } + } +} + +fn panic_hook(info: &std::panic::PanicInfo) { + log_crash(Some(info), None); +} + fn main() { - tauri::Builder::default() + // In the event that some catastrophic happens, atleast log it out + // the panic_hook will log to a file in the folder of the executable + std::panic::set_hook(Box::new(panic_hook)); + + let tauri_setup = tauri::Builder::default() .setup(|app| { // Setup Logging let log_path = app @@ -37,7 +75,7 @@ fn main() { // since almost all of them are the same as the color for the whole line, we // just clone `colors_line` and overwrite our changes let colors_level = colors_line.clone().info(Color::Cyan); - fern::Dispatch::new() + let log_setup_ok = fern::Dispatch::new() // Perform allocation-free log formatting .format(move |out, message, record| { out.finish(format_args!( @@ -60,23 +98,26 @@ fn main() { .chain(std::io::stdout()) .chain(fern::DateBased::new(&log_path, "/%Y-%m-%d.log")) // Apply globally - .apply() - .expect("Could not setup logs"); - log::info!("Logging Initialized"); - - // Truncate rotated log files to '5' - let mut paths: Vec<_> = std::fs::read_dir(&log_path)?.map(|r| r.unwrap()).collect(); - paths.sort_by_key(|dir| dir.path()); - paths.reverse(); - let mut i = 0; - for path in paths { - i += 1; - log::info!("{}", path.path().display()); - if i > 5 { - log::info!("deleting - {}", path.path().display()); - std::fs::remove_file(path.path())?; + .apply(); + match log_setup_ok { + Ok(_) => { + log::info!("Logging Initialized"); + // Truncate rotated log files to '5' + let mut paths: Vec<_> = std::fs::read_dir(&log_path)?.map(|r| r.unwrap()).collect(); + paths.sort_by_key(|dir| dir.path()); + paths.reverse(); + let mut i = 0; + for path in paths { + i += 1; + log::info!("{}", path.path().display()); + if i > 5 { + log::info!("deleting - {}", path.path().display()); + std::fs::remove_file(path.path())?; + } + } } - } + Err(err) => log::error!("Could not initialize logging {:?}", err), + }; // Load the config (or initialize it with defaults) // @@ -120,15 +161,27 @@ fn main() { commands::versions::remove_version, commands::versions::go_to_version_folder, commands::versions::list_downloaded_versions, - commands::window::close_splashscreen, + commands::window::open_main_window, commands::window::open_dir_in_os ]) .build(tauri::generate_context!()) - .expect("error building tauri app") - .run(|_app_handle, event| match event { - RunEvent::ExitRequested { .. } => { - std::process::exit(0); - } - _ => (), - }) + .map_err(|err| { + log_crash(None, Some(err)); + }); + match tauri_setup { + Ok(app) => { + log::info!("application starting up"); + app.run(|_app_handle, event| match event { + RunEvent::ExitRequested { .. } => { + log::info!("Exit requested, exiting!"); + std::process::exit(0); + } + _ => (), + }) + } + Err(err) => { + log::error!("Could not setup tauri application {:?}, exiting", err); + std::process::exit(1); + } + }; } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 971da325..73ad6705 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -38,10 +38,7 @@ "windows": { "certificateThumbprint": null, "digestAlgorithm": "sha256", - "timestampUrl": "", - "webviewInstallMode": { - "type": "embedBootstrapper" - } + "timestampUrl": "" } }, "allowlist": { @@ -67,18 +64,9 @@ } }, "windows": [ - { - "title": "OpenGOAL Launcher", - "width": 800, - "height": 600, - "resizable": false, - "fullscreen": false, - "visible": false, - "center": true, - "decorations": false - }, { "title": "OpenGOAL Launcher - Splash", + "label": "splashscreen", "width": 200, "height": 300, "center": true, @@ -87,8 +75,8 @@ "resizable": false, "fullscreen": false, "url": "./src/splash/index.html", - "label": "splashscreen", - "visible": true + "visible": true, + "focus": true } ], "security": { diff --git a/src/App.svelte b/src/App.svelte index 76390f65..80911a06 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -20,14 +20,9 @@ // Events onMount(async () => { - // TODO - tauri doesn't seem to handle this event being unlistented to properly (go back to closing the window) - // - need to make an issue - // For now, we'll just handle all close events ourselves - await appWindow.listen("tauri://close-requested", async () => { - // TODO - confirm during an install - await appWindow.close(); - }); // Temporary fix related to https://github.com/open-goal/launcher/issues/110 + // TODO - this doesn't feel required anymore after i fixed the window switching + // but let's keep it for now because im paranoid about the issue cropping up again... if (window.sessionStorage.getItem("refreshHack") !== "true") { location.reload(); window.sessionStorage.setItem("refreshHack", "true"); diff --git a/src/lib/rpc/window.ts b/src/lib/rpc/window.ts index 19f66373..b49a6c06 100644 --- a/src/lib/rpc/window.ts +++ b/src/lib/rpc/window.ts @@ -11,13 +11,13 @@ export async function openDir(directory: string): Promise { } } -export async function closeSplashScreen(): Promise { +export async function openMainWindow(): Promise { try { - invoke("close_splashscreen"); + invoke("open_main_window"); return true; } catch (e) { exceptionLog( - "Unexpected error encountered when closing the splash screen", + "Unexpected error encountered when attempting to open the main window", e ); } diff --git a/src/splash/Splash.svelte b/src/splash/Splash.svelte index 7b837694..de3a8425 100644 --- a/src/splash/Splash.svelte +++ b/src/splash/Splash.svelte @@ -1,5 +1,5 @@ diff --git a/yarn.lock b/yarn.lock index 7098af82..d908d3ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4385,10 +4385,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.9.5: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.3.tgz#fe976f0c826a88d0a382007681cbb2da44afdedf" + integrity sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA== unbzip2-stream@^1.0.9: version "1.4.3"