From b545c0d09b2c2b530cb36a596bee1e6f119cb34f Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Thu, 6 Oct 2022 11:29:07 +0800 Subject: [PATCH] fix #88 --- src/Snap.Hutao/.editorconfig | 1 + .../Snap.Hutao/Core/Caching/CacheBase.cs | 2 +- .../Core/Exception/ExceptionRecorder.cs | 36 +++++++++------ .../Snap.Hutao/Core/Logging/LogEntryQueue.cs | 10 +++- .../Factory/AsyncRelayCommandFactory.cs | 2 +- .../Model/Metadata/Avatar/SkillDepot.cs | 6 ++- .../Snap.Hutao/Package.appxmanifest | 2 +- src/Snap.Hutao/Snap.Hutao/Program.cs | 6 +-- .../Service/AvatarInfo/AvatarInfoService.cs | 46 +++++++++++-------- .../Service/AvatarInfo/RefreshResult.cs | 5 ++ src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj | 1 + .../View/Page/AvatarPropertyPage.xaml | 6 +-- .../Snap.Hutao/ViewModel/GachaLogViewModel.cs | 3 -- .../Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs | 2 +- .../Snap.Hutao/Web/Hoyolab/Cookie.cs | 4 +- 15 files changed, 85 insertions(+), 47 deletions(-) diff --git a/src/Snap.Hutao/.editorconfig b/src/Snap.Hutao/.editorconfig index 2a13ab68..c7c29c71 100644 --- a/src/Snap.Hutao/.editorconfig +++ b/src/Snap.Hutao/.editorconfig @@ -159,6 +159,7 @@ dotnet_diagnostic.CA1805.severity = suggestion # VSTHRD111: Use ConfigureAwait(bool) dotnet_diagnostic.VSTHRD111.severity = suggestion +csharp_style_prefer_top_level_statements = true:silent [*.vb] #### 命名样式 #### diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs index 15811179..3b8dd1b3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs @@ -139,7 +139,7 @@ public abstract class CacheBase IStorageItem? item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false); - if (item == null) + if (item == null || (await item.GetBasicPropertiesAsync()).Size == 0) { StorageFile baseFile = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting).AsTask().ConfigureAwait(false); await DownloadFileAsync(uri, baseFile).ConfigureAwait(false); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Exception/ExceptionRecorder.cs b/src/Snap.Hutao/Snap.Hutao/Core/Exception/ExceptionRecorder.cs index ed294afc..032e33b9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Exception/ExceptionRecorder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Exception/ExceptionRecorder.cs @@ -3,6 +3,7 @@ using Microsoft.UI.Xaml; using Snap.Hutao.Core.Logging; +using System.IO; namespace Snap.Hutao.Core.Exception; @@ -24,24 +25,33 @@ internal class ExceptionRecorder application.UnhandledException += OnAppUnhandledException; application.DebugSettings.BindingFailed += OnXamlBindingFailed; + AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException; } - /// - /// 当应用程序未经处理的异常引发时调用 - /// - /// 实例 - /// 事件参数 - public void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) + private void OnCurrentDomainUnhandledException(object sender, System.UnhandledExceptionEventArgs e) { - logger.LogError(EventIds.UnhandledException, e.Exception, "未经处理的异常: [HResult:{code}]", e.Exception.HResult); + logger.LogError(EventIds.UnhandledException, e.ExceptionObject as System.Exception, "未经处理的异常"); + + foreach (ILoggerProvider provider in Ioc.Default.GetRequiredService>()) + { + provider.Dispose(); + } } - /// - /// Xaml 绑定失败时触发 - /// - /// 实例 - /// 事件参数 - public void OnXamlBindingFailed(object? sender, BindingFailedEventArgs e) + private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) + { + logger.LogError(EventIds.UnhandledException, e.Exception, "未经处理的异常"); + + string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + File.WriteAllText(Path.Combine(path, "Excpetion.txt"), e.Exception?.ToString()); + + foreach (ILoggerProvider provider in Ioc.Default.GetRequiredService>()) + { + provider.Dispose(); + } + } + + private void OnXamlBindingFailed(object? sender, BindingFailedEventArgs e) { logger.LogCritical(EventIds.XamlBindingError, "XAML绑定失败: {message}", e.Message); } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Logging/LogEntryQueue.cs b/src/Snap.Hutao/Snap.Hutao/Core/Logging/LogEntryQueue.cs index 15b668ca..6f0d84fa 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Logging/LogEntryQueue.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Logging/LogEntryQueue.cs @@ -20,6 +20,8 @@ public sealed class LogEntryQueue : IDisposable private readonly TaskCompletionSource writeDbCompletionSource = new(); private readonly LogDbContext logDbContext; + private bool disposed; + /// /// 构造一个新的日志队列 /// @@ -27,7 +29,7 @@ public sealed class LogEntryQueue : IDisposable { logDbContext = InitializeDbContext(); - Task.Run(async () => await WritePendingLogsAsync(disposeTokenSource.Token)).SafeForget(); + Task.Run(() => WritePendingLogsAsync(disposeTokenSource.Token)).SafeForget(); } /// @@ -43,6 +45,11 @@ public sealed class LogEntryQueue : IDisposable [SuppressMessage("", "VSTHRD002")] public void Dispose() { + if (disposed) + { + return; + } + // notify the write task to complete. disposeTokenSource.Cancel(); @@ -50,6 +57,7 @@ public sealed class LogEntryQueue : IDisposable writeDbCompletionSource.Task.GetAwaiter().GetResult(); logDbContext.Dispose(); + disposed = true; } private static LogDbContext InitializeDbContext() diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/AsyncRelayCommandFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/AsyncRelayCommandFactory.cs index 07352a9d..9c1c159d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Factory/AsyncRelayCommandFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Factory/AsyncRelayCommandFactory.cs @@ -93,7 +93,7 @@ internal class AsyncRelayCommandFactory : IAsyncRelayCommandFactory if (asyncRelayCommand.ExecutionTask?.Exception is AggregateException exception) { Exception baseException = exception.GetBaseException(); - logger.LogError(EventIds.AsyncCommandException, baseException, "{name} Exception", nameof(asyncRelayCommand)); + logger.LogError(EventIds.AsyncCommandException, baseException, "{name} Exception", nameof(AsyncRelayCommand)); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs index 03d6f539..391bf5be 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs @@ -44,7 +44,11 @@ public class SkillDepot { foreach (ProudableSkill skill in Skills) { - yield return skill; + // skip skills like Mona's & Ayaka's shift + if (skill.Proud.Parameters.Count > 1) + { + yield return skill; + } } yield return EnergySkill; diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest index 2c0b5fda..97ea6ceb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest @@ -9,7 +9,7 @@ + Version="1.1.6.0" /> 胡桃 diff --git a/src/Snap.Hutao/Snap.Hutao/Program.cs b/src/Snap.Hutao/Snap.Hutao/Program.cs index 5d6ed8f3..486050da 100644 --- a/src/Snap.Hutao/Snap.Hutao/Program.cs +++ b/src/Snap.Hutao/Snap.Hutao/Program.cs @@ -15,7 +15,7 @@ namespace Snap.Hutao; /// /// Program class /// -public static class Program +public static partial class Program { /// /// 主线程队列 @@ -62,8 +62,8 @@ public static class Program // Microsoft extension .AddLogging(builder => builder - .AddDatabase() - .AddDebug()) + .AddDebug() + .AddDatabase()) .AddMemoryCache() // Hutao extensions diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs index 98d9edee..c51002a0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs @@ -5,6 +5,7 @@ using Snap.Hutao.Context.Database; using Snap.Hutao.Core.Threading; using Snap.Hutao.Model.Binding.AvatarProperty; using Snap.Hutao.Service.AvatarInfo.Factory; +using Snap.Hutao.Service.Metadata; using Snap.Hutao.Web.Enka; using Snap.Hutao.Web.Enka.Model; using Snap.Hutao.Web.Hoyolab; @@ -20,6 +21,7 @@ internal class AvatarInfoService : IAvatarInfoService private readonly AppDbContext appDbContext; private readonly ISummaryFactory summaryFactory; private readonly EnkaClient enkaClient; + private readonly IMetadataService metadataService; /// /// 构造一个新的角色信息服务 @@ -27,9 +29,10 @@ internal class AvatarInfoService : IAvatarInfoService /// 数据库上下文 /// 简述工厂 /// Enka客户端 - public AvatarInfoService(AppDbContext appDbContext, ISummaryFactory summaryFactory, EnkaClient enkaClient) + public AvatarInfoService(AppDbContext appDbContext, IMetadataService metadataService, ISummaryFactory summaryFactory, EnkaClient enkaClient) { this.appDbContext = appDbContext; + this.metadataService = metadataService; this.summaryFactory = summaryFactory; this.enkaClient = enkaClient; } @@ -37,34 +40,41 @@ internal class AvatarInfoService : IAvatarInfoService /// public async Task> GetSummaryAsync(PlayerUid uid, RefreshOption refreshOption, CancellationToken token = default) { - if (HasOption(refreshOption, RefreshOption.RequestFromAPI)) + if (await metadataService.InitializeAsync(token).ConfigureAwait(false)) { - EnkaResponse? resp = await GetEnkaResponseAsync(uid, token).ConfigureAwait(false); - if (resp == null) + if (HasOption(refreshOption, RefreshOption.RequestFromAPI)) { - return new(RefreshResult.APIUnavailable, null); - } + EnkaResponse? resp = await GetEnkaResponseAsync(uid, token).ConfigureAwait(false); + if (resp == null) + { + return new(RefreshResult.APIUnavailable, null); + } - if (resp.IsValid) - { - IList list = HasOption(refreshOption, RefreshOption.StoreInDatabase) - ? UpdateDbAvatarInfo(uid.Value, resp.AvatarInfoList) - : resp.AvatarInfoList; + if (resp.IsValid) + { + IList list = HasOption(refreshOption, RefreshOption.StoreInDatabase) + ? UpdateDbAvatarInfo(uid.Value, resp.AvatarInfoList) + : resp.AvatarInfoList; - Summary summary = await summaryFactory.CreateAsync(resp.PlayerInfo, list).ConfigureAwait(false); - return new(RefreshResult.Ok, summary); + Summary summary = await summaryFactory.CreateAsync(resp.PlayerInfo, list).ConfigureAwait(false); + return new(RefreshResult.Ok, summary); + } + else + { + return new(RefreshResult.ShowcaseNotOpen, null); + } } else { - return new(RefreshResult.ShowcaseNotOpen, null); + PlayerInfo info = PlayerInfo.CreateEmpty(uid.Value); + + Summary summary = await summaryFactory.CreateAsync(info, GetDbAvatarInfos(uid.Value)).ConfigureAwait(false); + return new(RefreshResult.Ok, summary); } } else { - PlayerInfo info = PlayerInfo.CreateEmpty(uid.Value); - - Summary summary = await summaryFactory.CreateAsync(info, GetDbAvatarInfos(uid.Value)).ConfigureAwait(false); - return new(RefreshResult.Ok, summary); + return new(RefreshResult.MetadataUninitialized, null); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/RefreshResult.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/RefreshResult.cs index d498383b..1bb15541 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/RefreshResult.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/RefreshResult.cs @@ -13,6 +13,11 @@ public enum RefreshResult /// Ok, + /// + /// 元数据加载失败 + /// + MetadataUninitialized, + /// /// API 不可用 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 98e200cc..20ece24c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -98,6 +98,7 @@ + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml index 215da3b8..4875b9a7 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml @@ -242,7 +242,7 @@ diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs index 484b1c86..de9c0b2f 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs @@ -16,11 +16,8 @@ using Snap.Hutao.Service.Abstraction; using Snap.Hutao.Service.GachaLog; using Snap.Hutao.View.Dialog; using System.Collections.ObjectModel; -using System.IO; using Windows.Storage; using Windows.Storage.Pickers; -using Windows.Storage.Pickers.Provider; -using Windows.Storage.Streams; namespace Snap.Hutao.ViewModel; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs index d41d4d77..9f706d48 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs @@ -97,7 +97,7 @@ internal static class ApiEndpoints public const string UserGameRoles = $"{ApiTaKumiBindingApi}/getUserGameRolesByCookie?game_biz=hk4e_cn"; /// - /// 用户游戏角色 + /// AuthKey /// public const string GenAuthKey = $"{ApiTaKumiBindingApi}/genAuthKey"; #endregion diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs index 0df5901e..f1549fc2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs @@ -174,7 +174,9 @@ public partial class Cookie if (uidCounter.Count > 0) { - uid = uidCounter.MaxBy(kvp => kvp.Value).Key; + // fix #88 自带页面登录米游社,提示登录失败 + string key = uidCounter.MaxBy(kvp => kvp.Value).Key; + uid = inner[key]; return true; } else