Add gui machinery to crash reporting system
MODIFY
WalletWasabi.Gui/CommandLine/CrashReportCommand.cs
WalletWasabi.Gui/CommandLine/CrashReportCommand.cs
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using WalletWasabi.Helpers;
using Newtonsoft.Json;
using WalletWasabi.Logging;
+using WalletWasabi.Gui.CrashReporter.Models;
namespace WalletWasabi.Gui.CommandLine
{
@@ -16,33 +17,31 @@ namespace WalletWasabi.Gui.CommandLine
Options = new OptionSet()
{
- { "e|exception=", "The serialized exception from the previous crash.", ExceptionDecode }
+ { "attempt=", "Number of attempts at starting the crash reporter.", x => Attempts = x },
+ { "exception=", "The serialized exception from the previous crash.", x => ExceptionString = x },
};
}
private void ExceptionDecode(string exceptionString)
- {
- try
{
var e = Guard.NotNullOrEmptyOrWhitespace(nameof(exceptionString), exceptionString);
- ReportedException = JsonConvert.DeserializeObject<Exception>(e);
-
- Global.ShowCrashReporter = true;
- Global.CrashReportException = e;
- }
- catch (Exception ex)
- {
- Logger.LogCritical(ex.Message);
- Environment.Exit(1);
- }
+ e = e.Trim(' ').Trim('\"');
+ Global.CrashReportException = JsonConvert.DeserializeObject<SerializedException>(e);
}
public Global Global { get; }
- public object ReportedException { get; private set; }
+ public string Attempts { get; private set; }
+ public string ExceptionString { get; private set; }
- public override Task<int> InvokeAsync(IEnumerable<string> arguments)
+ public override async Task<int> InvokeAsync(IEnumerable<string> args)
{
- return base.InvokeAsync(arguments);
+ Options.Parse(args);
+
+ Global.CrashReportStartAttempt = Attempts;
+
+ ExceptionDecode(ExceptionString);
+
+ return 0;
}
}
}

ADD
WalletWasabi.Gui/CrashReporter/CrashReportApp.xaml.cs
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using WalletWasabi.Gui.CrashReporter.ViewModels;
+using WalletWasabi.Gui.CrashReporter.Views;
+
+namespace WalletWasabi.Gui.CrashReporter
+{
+ public class CrashReportApp : Application
+ {
+ public CrashReportApp()
+ {
+ Name = "Wasabi Wallet Crash Reporting";
+ }
+
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new CrashReportWindow()
+ {
+ DataContext = new CrashReportWindowViewModel()
+ };
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+ }
+}

ADD
WalletWasabi.Gui/CrashReporter/Models/SerializedException.cs
+using System;
+
+namespace WalletWasabi.Gui.CrashReporter.Models
+{
+ [Serializable]
+ public class SerializedException
+ {
+ public Type ExceptionType { get; set; }
+ public string Message { get; set; }
+ public string StackTrace { get; set; }
+ public SerializedException InnerException { get; set; }
+
+ public SerializedException()
+ {
+ }
+
+ public SerializedException(Exception ex)
+ {
+ if (ex.InnerException is object)
+ {
+ InnerException = new SerializedException(ex.InnerException);
+ }
+ ExceptionType = ex.GetType();
+ Message = ex.Message;
+ StackTrace = ex.StackTrace;
+ }
+ }
+}

ADD
WalletWasabi.Gui/CrashReporter/ViewModels/CrashReportWindowViewModel.cs
+using Splat;
+using WalletWasabi.Gui.CrashReporter.Models;
+
+namespace WalletWasabi.Gui.CrashReporter.ViewModels
+{
+ public class CrashReportWindowViewModel
+ {
+ public CrashReportWindowViewModel()
+ {
+ Global = Locator.Current.GetService<Global>();
+ }
+
+ public string Title => "Wasabi Wallet - Crash Reporting";
+ public SerializedException ReportedException => Global.CrashReportException;
+
+ public Global Global { get; }
+ }
+}
\ No newline at end of file

ADD
WalletWasabi.Gui/CrashReporter/Views/CrashReportWindow.xaml
+<cont:MetroWindow xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:cont="clr-namespace:AvalonStudio.Shell.Controls;assembly=AvalonStudio.Shell"
+ xmlns:wasabi="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui"
+ x:Class="WalletWasabi.Gui.CrashReporter.Views.CrashReportWindow"
+ Icon="avares://WalletWasabi.Gui/Assets/WasabiLogo256.png"
+ Title="{Binding Title}"
+ MinWidth="400" MinHeight="400"
+ FontFamily="{DynamicResource UiFont}" FontSize="14"
+ Foreground="{DynamicResource ThemeForegroundBrush}"
+ WindowState="{Binding WindowState}">
+ <Grid>
+
+ </Grid>
+</cont:MetroWindow>

ADD
WalletWasabi.Gui/CrashReporter/Views/CrashReportWindow.xaml.cs
+using Avalonia;
+using Avalonia.Markup.Xaml;
+using AvalonStudio.Shell.Controls;
+using Splat;
+
+namespace WalletWasabi.Gui.CrashReporter.Views
+{
+ public class CrashReportWindow : MetroWindow
+ {
+ public CrashReportWindow()
+ {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}

MODIFY
WalletWasabi.Gui/Global.cs
WalletWasabi.Gui/Global.cs
@@ -27,6 +27,7 @@ using WalletWasabi.Blockchain.TransactionProcessing;
using WalletWasabi.CoinJoin.Client;
using WalletWasabi.CoinJoin.Client.Clients;
using WalletWasabi.CoinJoin.Client.Clients.Queuing;
+using WalletWasabi.Gui.CrashReporter.Models;
using WalletWasabi.Gui.Helpers;
using WalletWasabi.Gui.Models;
using WalletWasabi.Gui.Rpc;
@@ -109,8 +110,8 @@ namespace WalletWasabi.Gui
private bool InitializationStarted { get; set; } = false;
private CancellationTokenSource StoppingCts { get; }
- public bool ShowCrashReporter { get; set; }
- public string CrashReportException { get; set; }
+ public SerializedException CrashReportException { get; set; }
+ public string CrashReportStartAttempt { get; internal set; }
public async Task InitializeNoWalletAsync()
{

MODIFY
WalletWasabi.Gui/Program.cs
WalletWasabi.Gui/Program.cs
@@ -9,6 +9,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using WalletWasabi.Gui.CommandLine;
+using WalletWasabi.Gui.CrashReporter.Models;
using WalletWasabi.Gui.ViewModels;
using WalletWasabi.Logging;
@@ -35,6 +36,11 @@ namespace WalletWasabi.Gui
runGui = CommandInterpreter.ExecuteCommandsAsync(Global, args).GetAwaiter().GetResult();
+ if (Global.CrashReportException != null)
+ {
+ StartCrashReporter();
+ }
+
if (!runGui)
{
return;
@@ -98,6 +104,33 @@ namespace WalletWasabi.Gui
Logger.LogWarning(e?.ExceptionObject as Exception);
}
+ private static void StartCrashReporter()
+ {
+ var result = AppBuilder.Configure<CrashReporter.CrashReportApp>();
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ result
+ .UseWin32()
+ .UseSkia();
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ result.UsePlatformDetect();
+ }
+ else
+ {
+ result.UsePlatformDetect();
+ }
+
+ result
+ .With(new Win32PlatformOptions { AllowEglInitialization = false, UseDeferredRendering = true })
+ .With(new X11PlatformOptions { UseGpu = false, WmClass = "Wasabi Wallet Crash Reporting" })
+ .With(new AvaloniaNativePlatformOptions { UseDeferredRendering = true, UseGpu = false })
+ .With(new MacOSPlatformOptions { ShowInDock = true })
+ .StartWithClassicDesktopLifetime(null);
+ }
+
private static AppBuilder BuildAvaloniaApp()
{
bool useGpuLinux = true;

Add gui machinery to crash reporting system