mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
support Send on sync context
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Windows.ApplicationModel.Resources;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using Snap.Hutao.Service;
|
||||
using System.Globalization;
|
||||
|
||||
@@ -29,11 +29,14 @@ internal sealed partial class ExceptionRecorder
|
||||
|
||||
private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
serviceProvider
|
||||
ValueTask<string?> task = serviceProvider
|
||||
.GetRequiredService<Web.Hutao.Log.HomaLogUploadClient>()
|
||||
.UploadLogAsync(e.Exception)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
.UploadLogAsync(e.Exception);
|
||||
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
task.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
logger.LogError("未经处理的全局异常:\r\n{Detail}", ExceptionFormat.Format(e.Exception));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ internal sealed class RuntimeEnvironmentException : Exception
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="innerException">内部错误</param>
|
||||
public RuntimeEnvironmentException(string message, Exception innerException)
|
||||
public RuntimeEnvironmentException(string message, Exception? innerException)
|
||||
: base($"{message}\n{innerException.Message}", innerException)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -14,27 +14,27 @@ namespace Snap.Hutao.Core.ExceptionService;
|
||||
[System.Diagnostics.StackTraceHidden]
|
||||
internal static class ThrowHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作取消
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="inner">内部错误</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="OperationCanceledException">操作取消异常</exception>
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static OperationCanceledException OperationCanceled(string message, Exception? inner = default)
|
||||
public static ArgumentException Argument(string message, string? paramName)
|
||||
{
|
||||
throw new OperationCanceledException(message, inner);
|
||||
throw new ArgumentException(message, paramName);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static DatabaseCorruptedException DatabaseCorrupted(string message, Exception? inner)
|
||||
{
|
||||
throw new DatabaseCorruptedException(message, inner);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static GameFileOperationException GameFileOperation(string message, Exception? inner)
|
||||
{
|
||||
throw new GameFileOperationException(message, inner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无效操作
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="inner">内部错误</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="InvalidOperationException">无效操作异常</exception>
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static InvalidOperationException InvalidOperation(string message, Exception? inner = default)
|
||||
@@ -42,71 +42,38 @@ internal static class ThrowHelper
|
||||
throw new InvalidOperationException(message, inner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏文件操作失败
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="inner">内部错误</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="GameFileOperationException">文件操作失败</exception>
|
||||
public static GameFileOperationException GameFileOperation(string message, Exception inner)
|
||||
{
|
||||
throw new GameFileOperationException(message, inner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 包转换错误
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="inner">内部错误</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="PackageConvertException">包转换错误异常</exception>
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static PackageConvertException PackageConvert(string message, Exception inner)
|
||||
{
|
||||
throw new PackageConvertException(message, inner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户数据损坏
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="inner">内部错误</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="UserdataCorruptedException">数据损坏</exception>
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static UserdataCorruptedException UserdataCorrupted(string message, Exception inner)
|
||||
{
|
||||
throw new UserdataCorruptedException(message, inner);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static DatabaseCorruptedException DatabaseCorrupted(string message, Exception inner)
|
||||
{
|
||||
throw new DatabaseCorruptedException(message, inner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行环境异常
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="inner">内部错误</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="RuntimeEnvironmentException">环境异常</exception>
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static RuntimeEnvironmentException RuntimeEnvironment(string message, Exception inner)
|
||||
{
|
||||
throw new RuntimeEnvironmentException(message, inner);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static NotSupportedException NotSupported()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static OperationCanceledException OperationCanceled(string message, Exception? inner = default)
|
||||
{
|
||||
throw new OperationCanceledException(message, inner);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static PackageConvertException PackageConvert(string message, Exception? inner)
|
||||
{
|
||||
throw new PackageConvertException(message, inner);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static RuntimeEnvironmentException RuntimeEnvironment(string message, Exception? inner)
|
||||
{
|
||||
throw new RuntimeEnvironmentException(message, inner);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static UserdataCorruptedException UserdataCorrupted(string message, Exception? inner)
|
||||
{
|
||||
throw new UserdataCorruptedException(message, inner);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Dispatching;
|
||||
using System.Runtime.ExceptionServices;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
|
||||
@@ -18,15 +19,35 @@ internal static class DispatcherQueueExtension
|
||||
/// <param name="action">执行的回调</param>
|
||||
public static void Invoke(this DispatcherQueue dispatcherQueue, Action action)
|
||||
{
|
||||
using (ManualResetEventSlim blockEvent = new())
|
||||
if (dispatcherQueue.HasThreadAccess)
|
||||
{
|
||||
action();
|
||||
return;
|
||||
}
|
||||
|
||||
ExceptionDispatchInfo? exceptionDispatchInfo = null;
|
||||
using (ManualResetEventSlim blockEvent = new(false))
|
||||
{
|
||||
dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
action();
|
||||
blockEvent.Set();
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
blockEvent.Set();
|
||||
}
|
||||
});
|
||||
|
||||
blockEvent.Wait();
|
||||
#pragma warning disable CA1508
|
||||
exceptionDispatchInfo?.Throw();
|
||||
#pragma warning restore CA1508
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Dispatching;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
|
||||
internal sealed class DispatcherQueueSynchronizationContextSendSupport : SynchronizationContext
|
||||
{
|
||||
private readonly DispatcherQueue dispatcherQueue;
|
||||
|
||||
public DispatcherQueueSynchronizationContextSendSupport(DispatcherQueue dispatcherQueue)
|
||||
{
|
||||
this.dispatcherQueue = dispatcherQueue;
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback d, object? state)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(d);
|
||||
dispatcherQueue.TryEnqueue(() => d(state));
|
||||
}
|
||||
|
||||
public override void Send(SendOrPostCallback d, object? state)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(d);
|
||||
dispatcherQueue.Invoke(() => d(state));
|
||||
}
|
||||
|
||||
public override SynchronizationContext CreateCopy()
|
||||
{
|
||||
return new DispatcherQueueSynchronizationContextSendSupport(dispatcherQueue);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Snap.Hutao.Core.Threading;
|
||||
[Injection(InjectAs.Singleton, typeof(ITaskContext))]
|
||||
internal sealed class TaskContext : ITaskContext
|
||||
{
|
||||
private readonly DispatcherQueueSynchronizationContext dispatcherQueueSynchronizationContext;
|
||||
private readonly DispatcherQueueSynchronizationContextSendSupport synchronizationContext;
|
||||
private readonly DispatcherQueue dispatcherQueue;
|
||||
|
||||
/// <summary>
|
||||
@@ -20,8 +20,8 @@ internal sealed class TaskContext : ITaskContext
|
||||
public TaskContext()
|
||||
{
|
||||
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
dispatcherQueueSynchronizationContext = new(dispatcherQueue);
|
||||
SynchronizationContext.SetSynchronizationContext(dispatcherQueueSynchronizationContext);
|
||||
synchronizationContext = new(dispatcherQueue);
|
||||
SynchronizationContext.SetSynchronizationContext(synchronizationContext);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -39,18 +39,11 @@ internal sealed class TaskContext : ITaskContext
|
||||
/// <inheritdoc/>
|
||||
public void InvokeOnMainThread(Action action)
|
||||
{
|
||||
if (dispatcherQueue.HasThreadAccess)
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcherQueue.Invoke(action);
|
||||
}
|
||||
dispatcherQueue.Invoke(action);
|
||||
}
|
||||
|
||||
public IProgress<T> CreateProgressForMainThread<T>(Action<T> handler)
|
||||
{
|
||||
return new DispatcherQueueProgress<T>(handler, dispatcherQueueSynchronizationContext);
|
||||
return new DispatcherQueueProgress<T>(handler, synchronizationContext);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ internal sealed class GameFileOperationException : Exception
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="innerException">内部错误</param>
|
||||
public GameFileOperationException(string message, Exception innerException)
|
||||
public GameFileOperationException(string message, Exception? innerException)
|
||||
: base(SH.ServiceGameFileOperationExceptionMessage.Format(message), innerException)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Service.Game.Package;
|
||||
internal sealed class PackageConvertException : Exception
|
||||
{
|
||||
/// <inheritdoc cref="Exception(string?, Exception?)"/>
|
||||
public PackageConvertException(string message, Exception innerException)
|
||||
public PackageConvertException(string message, Exception? innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -39,19 +39,20 @@ internal class MiHoYoJSInterface
|
||||
document.querySelector('body').appendChild(st);
|
||||
""";
|
||||
|
||||
private readonly SemaphoreSlim webMessageSemaphore = new(1);
|
||||
private readonly Guid interfaceId = Guid.NewGuid();
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly UserAndUid userAndUid;
|
||||
private CoreWebView2 webView;
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly ILogger<MiHoYoJSInterface> logger;
|
||||
private readonly SemaphoreSlim webMessageSemaphore = new(1);
|
||||
|
||||
private readonly TypedEventHandler<CoreWebView2, CoreWebView2WebMessageReceivedEventArgs> webMessageReceivedEventHandler;
|
||||
private readonly TypedEventHandler<CoreWebView2, CoreWebView2DOMContentLoadedEventArgs> domContentLoadedEventHandler;
|
||||
private readonly TypedEventHandler<CoreWebView2, CoreWebView2NavigationStartingEventArgs> navigationStartingEventHandler;
|
||||
|
||||
private CoreWebView2 webView;
|
||||
|
||||
public MiHoYoJSInterface(CoreWebView2 webView, UserAndUid userAndUid)
|
||||
{
|
||||
// 由于Webview2 的作用域特殊性,我们在此处直接使用根服务
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
@@ -66,7 +67,7 @@ internal abstract class HttpContentSerializer : IHttpContentSerializer, IHttpCon
|
||||
The content to be serialized does not match the specified type.
|
||||
Expected an instance of the class "{contentType.FullName}", but got "{actualContentType.FullName}".
|
||||
""";
|
||||
throw new ArgumentException(message, nameof(contentType));
|
||||
ThrowHelper.Argument(message, nameof(contentType));
|
||||
}
|
||||
|
||||
// The contentType is optional. In that case, try to get the type on our own.
|
||||
|
||||
Reference in New Issue
Block a user