Skip to content

Commit

Permalink
fix: AOT json serialization crash issue
Browse files Browse the repository at this point in the history
  • Loading branch information
qwqcode committed Apr 13, 2024
1 parent 5ce6c4a commit 32fd040
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 49 deletions.
12 changes: 12 additions & 0 deletions SubRenamer/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.DependencyInjection;
using SubRenamer.ViewModels;
using SubRenamer.Views;
using Microsoft.Extensions.DependencyInjection;
using MsBox.Avalonia;
using MsBox.Avalonia.Dto;
using MsBox.Avalonia.Enums;
using MsBox.Avalonia.Models;
using SubRenamer.Helper;
using SubRenamer.Model;
using SubRenamer.Services;

Expand All @@ -16,6 +25,7 @@ namespace SubRenamer
public partial class App : Application
{
public static readonly UpdateService Updater = new UpdateService();
public static readonly string CrashLogFile = Path.Combine(Config.ConfigDir, "crash.log");

public App()
{
Expand Down Expand Up @@ -99,6 +109,8 @@ private void MenuSetting_OnClick(object? sender, EventArgs e)

private static void _afterInitTasks(MainViewModel? mainWindowStore)
{
IssueReporter.CheckCrashAndShowDialog();

Task.Run(async () =>
{
if (!Config.Get().UpdateCheck) return;
Expand Down
66 changes: 66 additions & 0 deletions SubRenamer/Helper/IssueReporter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Avalonia.Controls;
using Avalonia.Threading;
using MsBox.Avalonia;
using MsBox.Avalonia.Dto;
using MsBox.Avalonia.Models;
using SubRenamer.Services;

namespace SubRenamer.Helper;

public class IssueReporter
{
public static void CheckCrashAndShowDialog()
{
Dispatcher.UIThread.Post(async () =>
{
if (!File.Exists(App.CrashLogFile)) return;
var crashLog = await File.ReadAllTextAsync(App.CrashLogFile);
var title = crashLog.Split('\n').FirstOrDefault() ?? "";
var box = MessageBoxManager.GetMessageBoxCustom(new MessageBoxCustomParams
{
ButtonDefinitions = new List<ButtonDefinition>
{
new ButtonDefinition { Name = "反馈问题", IsDefault = true },
new ButtonDefinition { Name = "忽略", IsCancel = true }
},
ContentTitle = "检测到程序崩溃 x_x",
ContentMessage = $"{title}\n\n点击下方按钮反馈错误报告",
Icon = MsBox.Avalonia.Enums.Icon.Warning,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
CanResize = false,
MaxWidth = 500,
MaxHeight = 800,
ShowInCenter = true,
Topmost = true
});
var result = await box.ShowAsync();
if (result == "反馈问题")
{
CreateGitHubIssue(title, $"{crashLog}\n\nWheel: {SystemInfo.GetOSArchPair()} Version: v{Config.AppVersion}");
}
// rename CrashLog
File.Move(App.CrashLogFile, Path.Combine(Config.ConfigDir, $"crash.{DateTime.Now:yyyyMMddHHmmss}.solved.log"));
}, DispatcherPriority.Background);
}

public static void CreateGitHubIssue(Exception e)
{
CreateGitHubIssue(e.Message, e.StackTrace ?? "");
}

public static void CreateGitHubIssue(string caption, string details)
{
var title = $"[CRASH][{"v" + Config.AppVersion}] {caption}";
BrowserHelper.OpenBrowserAsync(
$"https://github.com/qwqcode/SubRenamer/issues/new?title={HttpUtility.UrlEncode(title, Encoding.UTF8)}&body={HttpUtility.UrlEncode(caption + "\n\n```\n" + details + "\n```", Encoding.UTF8)}");
}
}
12 changes: 11 additions & 1 deletion SubRenamer/Helper/JsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,19 @@
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
using SubRenamer.Services;

namespace SubRenamer.Helper;

// https://learn.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json/source-generation?pivots=dotnet-8-0
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Config))]
[JsonSerializable(typeof(GitHubRelease))]
[JsonSerializable(typeof(GitHubReleaseAsset))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}

// https://github.com/dotnet/runtimelab/issues/635
// https://github.com/dotnet/runtime/issues/63843
[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
Expand All @@ -24,7 +34,7 @@ public partial class JsonHelper
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
NumberHandling = JsonNumberHandling.AllowReadingFromString,

TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
TypeInfoResolver = SourceGenerationContext.Default,

Converters =
{
Expand Down
29 changes: 29 additions & 0 deletions SubRenamer/Helper/SystemInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Runtime.InteropServices;

namespace SubRenamer.Helper;

public class SystemInfo
{
public static string GetOSArchPair()
{
return $"{GetOSName()}_{GetArchName()}";
}

public static string GetOSName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return "windows";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return "macos";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return "linux";
else return "unknown";
}

public static string GetArchName()
{
return RuntimeInformation.OSArchitecture switch
{
Architecture.X64 => "amd64",
Architecture.Arm64 => "arm64",
_ => "unknown"
};
}
}
21 changes: 3 additions & 18 deletions SubRenamer/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.ReactiveUI;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Web;
Expand All @@ -16,28 +17,22 @@ internal class Program
[STAThread]
public static void Main(string[] args)
{
#if !DEBUG
try
{
#endif
BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
#if !DEBUG
}
catch (Exception e)
{
// here we can work with the exception, for example add it to our log file
// Log.Fatal(e, "Something very bad happened");

CreateGitHubIssue(e.Message, e.StackTrace ?? "");
File.WriteAllText(App.CrashLogFile, $"{e.Message}\n${e.StackTrace ?? ""}", Encoding.UTF8);
throw;
}
finally
{
// This block is optional.
// Use the finally-block if you need to clean things up or similar
// Log.CloseAndFlush();
}
#endif
}

// Avalonia configuration, don't remove; also used by visual designer.
Expand All @@ -51,14 +46,4 @@ public static AppBuilder BuildAvaloniaApp()
{
DisableDefaultApplicationMenuItems = true
});

private static void CreateGitHubIssue(string caption, string details)
{
Task.Run(() =>
{
var title = $"[PANIC][{"v" + Config.AppVersion}] {caption}";
BrowserHelper.OpenBrowserAsync(
$"https://github.com/qwqcode/SubRenamer/issues/new?title={HttpUtility.UrlEncode(title, Encoding.UTF8)}&body={HttpUtility.UrlEncode(caption + "\n\n```\n" + details + "\n```", Encoding.UTF8)}");
});
}
}
27 changes: 1 addition & 26 deletions SubRenamer/Services/UpdateService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Avalonia.Controls;
using SubRenamer.Helper;

namespace SubRenamer.Services;
Expand Down Expand Up @@ -61,32 +59,9 @@ public async Task<bool> VisitorHit()

private GitHubReleaseAsset? ExtractPlatformAssetItem(IEnumerable<GitHubReleaseAsset> assets)
{
string os = GetOSName();
string arch = GetArchName();

string targetAssetName = $"{os}_{arch}";

var targetAsset = assets.FirstOrDefault(asset => asset.Name.Contains(targetAssetName));
var targetAsset = assets.FirstOrDefault(asset => asset.Name.Contains(SystemInfo.GetOSArchPair()));
return targetAsset ?? null;
}

private static string GetOSName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return "windows";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return "macos";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return "linux";
else return "unknown";
}

private static string GetArchName()
{
return RuntimeInformation.OSArchitecture switch
{
Architecture.X64 => "amd64",
Architecture.Arm64 => "arm64",
_ => "unknown"
};
}
}

public class GitHubRelease
Expand Down
5 changes: 1 addition & 4 deletions SubRenamer/SubRenamer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<StripSymbols>true</StripSymbols>
<NoWarn>IL2057;IL2026;IL2104;IL3053</NoWarn>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>

<ItemGroup>
Expand Down Expand Up @@ -60,10 +61,6 @@
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.10" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="MessageBox.Avalonia" Version="3.1.5.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />

<!--Compresse with UPX-->
Expand Down

0 comments on commit 32fd040

Please sign in to comment.