From 3a8627fd0ed6924abf171fb669b850c0a10c098a Mon Sep 17 00:00:00 2001 From: Natsumi Date: Tue, 23 Dec 2025 00:43:04 +1300 Subject: [PATCH] Crash auto recovery in the worst way possible --- Dotnet/Cef/CefCustomRequestHandler.cs | 8 +++++++- Dotnet/Cef/SubProcess.cs | 22 ++++++++++++++++++---- Dotnet/Program.cs | 17 +---------------- src/localization/en.json | 3 ++- src/plugin/sentry.js | 4 ++++ src/service/sqlite.js | 15 ++++++++++++++- 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Dotnet/Cef/CefCustomRequestHandler.cs b/Dotnet/Cef/CefCustomRequestHandler.cs index 607994e3..5377bab3 100644 --- a/Dotnet/Cef/CefCustomRequestHandler.cs +++ b/Dotnet/Cef/CefCustomRequestHandler.cs @@ -80,7 +80,7 @@ namespace VRCX break; case CefTerminationStatus.ProcessCrashed: - _logger.Error("Browser crashed while."); + _logger.Error("Browser crashed."); break; case CefTerminationStatus.OutOfMemory: @@ -91,6 +91,12 @@ namespace VRCX _logger.Error($"Browser terminated with unhandled status '{status}' while at address."); break; } + + if (chromiumWebBrowser.IsDisposed || chromiumWebBrowser.IsLoading) + return; + + _logger.Info("Attempting to reload browser..."); + chromiumWebBrowser.Reload(); } } } diff --git a/Dotnet/Cef/SubProcess.cs b/Dotnet/Cef/SubProcess.cs index 827744c0..c76fdc72 100644 --- a/Dotnet/Cef/SubProcess.cs +++ b/Dotnet/Cef/SubProcess.cs @@ -1,6 +1,7 @@ using CefSharp.Internals; using System; using System.IO; +using System.Threading; namespace VRCX; @@ -26,7 +27,7 @@ public class BrowserSubprocess if (string.IsNullOrEmpty(type)) { - // If --type param missing from command line CEF/Chromium assums + // If --type param missing from command line CEF/Chromium assumes // this is the main process (as all subprocesses must have a type param). return; } @@ -46,9 +47,22 @@ public class BrowserSubprocess var methodArgs = new object[] { args }; - var exitCode = mainMethod.Invoke(null, methodArgs); - - Environment.Exit((int)exitCode); + int exitCode = -1; + while (true) + { + try + { + exitCode = (int)mainMethod.Invoke(null, methodArgs); + } + catch (Exception ex) + { + // TODO: Log this exception somewhere more useful + Console.WriteLine("Exception in BrowserSubprocess: " + ex); + Thread.Sleep(1000); + continue; + } + Environment.Exit(exitCode); + } } } diff --git a/Dotnet/Program.cs b/Dotnet/Program.cs index f25c803a..58ab3e05 100644 --- a/Dotnet/Program.cs +++ b/Dotnet/Program.cs @@ -10,7 +10,6 @@ using System; using System.Data.SQLite; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Runtime.InteropServices; using System.Text.Json; using System.Threading; #if !LINUX @@ -128,6 +127,7 @@ namespace VRCX [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] private static void Main() { + BrowserSubprocess.Start(); if (Wine.GetIfWine()) { MessageBox.Show( @@ -192,20 +192,6 @@ namespace VRCX #endregion - #region Handle Out Of Memory - - catch (SEHException e) - { - logger.Fatal(e, "Unhandled SEH Exception, most likely out of memory, closing."); - var messageBoxResult = MessageBox.Show( - "VRCX has run out of memory and needs to close.\n" + - "We're actively working on fixing this issue. \n" + - e, "Out of Memory", MessageBoxButtons.OK, MessageBoxIcon.Error); - Environment.Exit(0); - } - - #endregion - catch (Exception e) { var cpuError = WinApi.GetCpuErrorMessage(); @@ -233,7 +219,6 @@ namespace VRCX StartupArgs.ArgsCheck(args); SetProgramDirectories(); VRCXStorage.Instance.Load(); - BrowserSubprocess.Start(); ConfigureLogger(); GetVersion(); Update.Check(); diff --git a/src/localization/en.json b/src/localization/en.json index 78c0623d..bc556574 100644 --- a/src/localization/en.json +++ b/src/localization/en.json @@ -282,7 +282,8 @@ }, "vrcplus": { "gift": "VRC+ Gift" - } + }, + "localNotifs": "System" } }, "friend_list": { diff --git a/src/plugin/sentry.js b/src/plugin/sentry.js index 3be3fa94..26d1bbd5 100644 --- a/src/plugin/sentry.js +++ b/src/plugin/sentry.js @@ -70,8 +70,12 @@ export async function initSentry(app) { 'An error occurred while sending the request' ) || error.message.includes('database or disk is full') || + error.message.includes('disk I/O error') || error.message.includes( 'There is not enough space on the disk.' + ) || + error.message.includes( + 'The requested address is not valid in its context.' ) ) { return null; diff --git a/src/service/sqlite.js b/src/service/sqlite.js index 02bf08da..8359154e 100644 --- a/src/service/sqlite.js +++ b/src/service/sqlite.js @@ -33,7 +33,10 @@ class SQLiteService { } ).catch(() => {}); } - if (e.message.includes('database is locked')) { + if ( + e.message.includes('database is locked') || + e.message.includes('attempt to write a readonly database') + ) { ElMessageBox.alert( 'Please close other applications that might be using the database file.', 'Database is locked', @@ -43,6 +46,16 @@ class SQLiteService { } ).catch(() => {}); } + if (e.message.includes('disk I/O error')) { + ElMessageBox.alert( + 'Please check your disk for errors.', + 'Disk I/O error', + { + confirmButtonText: 'OK', + type: 'warning' + } + ).catch(() => {}); + } } throw e; }