fix: app restarting after the user closes when there's a pending update (#6074)

* fix: app restarting after the user closes when there's a pending update

* add logging and fix tauri variable

* use state

* use atomicbool
This commit is contained in:
Prospector
2026-05-12 12:01:12 -07:00
committed by GitHub
parent a192f7857e
commit 882b01c7c9
4 changed files with 72 additions and 14 deletions

View File

@@ -109,6 +109,7 @@ import {
getUpdateSize, getUpdateSize,
isDev, isDev,
isNetworkMetered, isNetworkMetered,
setRestartAfterPendingUpdate,
} from '@/helpers/utils.js' } from '@/helpers/utils.js'
import i18n from '@/i18n.config' import i18n from '@/i18n.config'
import { createContentInstall, provideContentInstall } from '@/providers/content-install' import { createContentInstall, provideContentInstall } from '@/providers/content-install'
@@ -1025,6 +1026,13 @@ async function downloadUpdate(versionToDownload) {
async function installUpdate() { async function installUpdate() {
restarting.value = true restarting.value = true
try {
await setRestartAfterPendingUpdate(true)
} catch (e) {
restarting.value = false
handleError(e)
return
}
setTimeout(async () => { setTimeout(async () => {
await handleClose() await handleClose()
}, 250) }, 250)

View File

@@ -22,6 +22,10 @@ export async function removeEnqueuedUpdate() {
return await invoke('remove_enqueued_update') return await invoke('remove_enqueued_update')
} }
export async function setRestartAfterPendingUpdate(should_restart) {
return await invoke('set_restart_after_pending_update', { shouldRestart: should_restart })
}
// One of 'Windows', 'Linux', 'MacOS' // One of 'Windows', 'Linux', 'MacOS'
export async function getOS() { export async function getOS() {
return await invoke('plugin:utils|get_os') return await invoke('plugin:utils|get_os')

View File

@@ -6,6 +6,7 @@
use native_dialog::{DialogBuilder, MessageLevel}; use native_dialog::{DialogBuilder, MessageLevel};
use std::env; use std::env;
use std::sync::atomic::Ordering;
use tauri::{Listener, Manager}; use tauri::{Listener, Manager};
use tauri_plugin_fs::FsExt; use tauri_plugin_fs::FsExt;
use theseus::prelude::*; use theseus::prelude::*;
@@ -96,6 +97,17 @@ fn restart_app(app: tauri::AppHandle) {
app.restart(); app.restart();
} }
#[tauri::command]
async fn set_restart_after_pending_update(
should_restart: bool,
) -> api::Result<()> {
let state = State::get().await?;
state
.restart_after_pending_update
.store(should_restart, Ordering::Relaxed);
Ok(())
}
// if Tauri app is called with arguments, then those arguments will be treated as commands // if Tauri app is called with arguments, then those arguments will be treated as commands
// ie: deep links or filepaths for .mrpacks // ie: deep links or filepaths for .mrpacks
fn main() { fn main() {
@@ -245,6 +257,7 @@ fn main() {
get_update_size, get_update_size,
enqueue_update_for_installation, enqueue_update_for_installation,
remove_enqueued_update, remove_enqueued_update,
set_restart_after_pending_update,
toggle_decorations, toggle_decorations,
show_window, show_window,
restart_app, restart_app,
@@ -262,7 +275,13 @@ fn main() {
#[cfg(feature = "updater")] #[cfg(feature = "updater")]
if matches!(event, tauri::RunEvent::Exit) { if matches!(event, tauri::RunEvent::Exit) {
let update_data = app.state::<PendingUpdateData>().inner(); let update_data = app.state::<PendingUpdateData>().inner();
if let Some((update, data)) = &*update_data.0.lock().unwrap() { let should_restart = State::get_if_initialized()
.map(|s| {
s.restart_after_pending_update.load(Ordering::Relaxed)
})
.unwrap_or(false);
if let Some((update, data)) = &*update_data.0.lock().unwrap()
{
fn set_changelog_toast(version: Option<String>) { fn set_changelog_toast(version: Option<String>) {
let toast_result: theseus::Result<()> = tauri::async_runtime::block_on(async move { let toast_result: theseus::Result<()> = tauri::async_runtime::block_on(async move {
let mut settings = settings::get().await?; let mut settings = settings::get().await?;
@@ -271,27 +290,46 @@ fn main() {
Ok(()) Ok(())
}); });
if let Err(e) = toast_result { if let Err(e) = toast_result {
tracing::warn!("Failed to set pending_update_toast: {e}") tracing::warn!(
"Failed to set pending_update_toast: {e}"
)
} }
} }
set_changelog_toast(Some(update.version.clone())); set_changelog_toast(Some(update.version.clone()));
if let Err(e) = update.install(data) { match update.install(data) {
tracing::error!("Error while updating: {e}"); Ok(()) => {
set_changelog_toast(None); if should_restart {
tracing::info!(
"Pending update installed successfully (version {}); restarting because user requested reload",
update.version
);
app.restart();
} else {
tracing::info!(
"Pending update installed successfully (version {}); exiting without relaunch (user did not request reload)",
update.version
);
}
}
Err(e) => {
tracing::error!(
"Pending update install failed (version {}): {e}",
update.version
);
set_changelog_toast(None);
DialogBuilder::message() DialogBuilder::message()
.set_level(MessageLevel::Error) .set_level(MessageLevel::Error)
.set_title("Update error") .set_title("Update error")
.set_text(format!("Failed to install update due to an error:\n{e}")) .set_text(format!("Failed to install update due to an error:\n{e}"))
.alert() .alert()
.show() .show()
.unwrap(); .unwrap();
}
} }
app.restart();
} }
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
if let tauri::RunEvent::Opened { urls } = event { if let tauri::RunEvent::Opened { urls } = event {
tracing::info!("Handling webview open {urls:?}"); tracing::info!("Handling webview open {urls:?}");

View File

@@ -1,6 +1,7 @@
//! Theseus state management system //! Theseus state management system
use crate::util::fetch::{FetchSemaphore, IoSemaphore}; use crate::util::fetch::{FetchSemaphore, IoSemaphore};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use tokio::sync::{OnceCell, Semaphore}; use tokio::sync::{OnceCell, Semaphore};
use crate::state::fs_watcher::FileWatcher; use crate::state::fs_watcher::FileWatcher;
@@ -83,6 +84,8 @@ pub struct State {
/// Friends socket /// Friends socket
pub friends_socket: FriendsSocket, pub friends_socket: FriendsSocket,
pub restart_after_pending_update: AtomicBool,
pub(crate) pool: SqlitePool, pub(crate) pool: SqlitePool,
pub(crate) file_watcher: FileWatcher, pub(crate) file_watcher: FileWatcher,
@@ -146,6 +149,10 @@ impl State {
LAUNCHER_STATE.initialized() LAUNCHER_STATE.initialized()
} }
pub fn get_if_initialized() -> Option<Arc<Self>> {
LAUNCHER_STATE.get().map(Arc::clone)
}
#[tracing::instrument] #[tracing::instrument]
async fn initialize_state( async fn initialize_state(
app_identifier: String, app_identifier: String,
@@ -194,6 +201,7 @@ impl State {
discord_rpc, discord_rpc,
process_manager, process_manager,
friends_socket, friends_socket,
restart_after_pending_update: AtomicBool::new(false),
pool, pool,
file_watcher, file_watcher,
// app_identifier, // app_identifier,