diff --git a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Automation/SaltConstantGenerator.cs b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Automation/SaltConstantGenerator.cs index 862d1101..86967884 100644 --- a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Automation/SaltConstantGenerator.cs +++ b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Automation/SaltConstantGenerator.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.CodeAnalysis; +using System; using System.Net.Http; using System.Runtime.Serialization; @@ -10,7 +11,18 @@ namespace Snap.Hutao.SourceGeneration.Automation; [Generator(LanguageNames.CSharp)] internal sealed class SaltConstantGenerator : IIncrementalGenerator { - private static readonly HttpClient httpClient = new(); + private static readonly HttpClient httpClient; + private static readonly Lazy> lazySaltInfo; + + static SaltConstantGenerator() + { + httpClient = new(); + lazySaltInfo = new Lazy>(() => + { + string body = httpClient.GetStringAsync("https://internal.snapgenshin.cn/Archive/Salt/Latest").GetAwaiter().GetResult(); + return JsonParser.FromJson>(body)!; + }); + } public void Initialize(IncrementalGeneratorInitializationContext context) { @@ -19,8 +31,7 @@ internal sealed class SaltConstantGenerator : IIncrementalGenerator private static void GenerateSaltContstants(IncrementalGeneratorPostInitializationContext context) { - string body = httpClient.GetStringAsync("https://internal.snapgenshin.cn/Archive/Salt/Latest").GetAwaiter().GetResult(); - Response saltInfo = JsonParser.FromJson>(body)!; + Response saltInfo = lazySaltInfo.Value; string code = $$""" namespace Snap.Hutao.Web.Hoyolab; diff --git a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Enum/LocalizedEnumGenerator.cs b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Enum/LocalizedEnumGenerator.cs index 1235b404..c8a4f07e 100644 --- a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Enum/LocalizedEnumGenerator.cs +++ b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Enum/LocalizedEnumGenerator.cs @@ -50,6 +50,8 @@ internal class LocalizedEnumGenerator : IIncrementalGenerator // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. + using System.Globalization; + namespace Snap.Hutao.Resource.Localization; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(LocalizedEnumGenerator)}}", "1.0.0.0")] @@ -79,7 +81,7 @@ internal class LocalizedEnumGenerator : IIncrementalGenerator } else { - return SH.ResourceManager.GetString(key); + return SH.ResourceManager.GetString(key, CultureInfo.CurrentCulture); } } @@ -102,7 +104,7 @@ internal class LocalizedEnumGenerator : IIncrementalGenerator _ => string.Empty, }; - return SH.ResourceManager.GetString(key); + return SH.ResourceManager.GetString(key, CultureInfo.CurrentCulture); } } """); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs index 8cf344d2..fec24cb5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs @@ -27,6 +27,7 @@ internal sealed partial class ExceptionRecorder app.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed; } + [SuppressMessage("", "CA2012")] private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) { ValueTask task = serviceProvider diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs index 27f8ce66..824cb508 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs @@ -1140,6 +1140,213 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 胡桃云保存的祈愿记录存档数已达当前账号上限 的本地化字符串。 + /// + internal static string ServerGachaLogServiceInsufficientRecordSlot { + get { + return ResourceManager.GetString("ServerGachaLogServiceInsufficientRecordSlot", resourceCulture); + } + } + + /// + /// 查找类似 未开通祈愿记录上传服务或已到期 的本地化字符串。 + /// + internal static string ServerGachaLogServiceInsufficientTime { + get { + return ResourceManager.GetString("ServerGachaLogServiceInsufficientTime", resourceCulture); + } + } + + /// + /// 查找类似 祈愿数据存在无效的物品,无法保存至胡桃云 的本地化字符串。 + /// + internal static string ServerGachaLogServiceInvalidGachaLogData { + get { + return ResourceManager.GetString("ServerGachaLogServiceInvalidGachaLogData", resourceCulture); + } + } + + /// + /// 查找类似 数据异常,无法保存至云端,请勿跨账号上传或尝试删除云端数据后重试 的本地化字符串。 + /// + internal static string ServerGachaLogServiceServerDatabaseError { + get { + return ResourceManager.GetString("ServerGachaLogServiceServerDatabaseError", resourceCulture); + } + } + + /// + /// 查找类似 当前邮箱尚未注册 的本地化字符串。 + /// + internal static string ServerPassportServiceEmailHasNotRegistered { + get { + return ResourceManager.GetString("ServerPassportServiceEmailHasNotRegistered", resourceCulture); + } + } + + /// + /// 查找类似 当前邮箱已被注册 的本地化字符串。 + /// + internal static string ServerPassportServiceEmailHasRegistered { + get { + return ResourceManager.GetString("ServerPassportServiceEmailHasRegistered", resourceCulture); + } + } + + /// + /// 查找类似 注册失败,服务器异常,请尽快联系开发者解决 的本地化字符串。 + /// + internal static string ServerPassportServiceInternalException { + get { + return ResourceManager.GetString("ServerPassportServiceInternalException", resourceCulture); + } + } + + /// + /// 查找类似 用户不存在,注销失败 的本地化字符串。 + /// + internal static string ServerPassportServiceUnregisterFailed { + get { + return ResourceManager.GetString("ServerPassportServiceUnregisterFailed", resourceCulture); + } + } + + /// + /// 查找类似 用户不存在,获取用户信息失败 的本地化字符串。 + /// + internal static string ServerPassportUserInfoNotExist { + get { + return ResourceManager.GetString("ServerPassportUserInfoNotExist", resourceCulture); + } + } + + /// + /// 查找类似 用户名或密码错误 的本地化字符串。 + /// + internal static string ServerPassportUsernameOrPassportIncorrect { + get { + return ResourceManager.GetString("ServerPassportUsernameOrPassportIncorrect", resourceCulture); + } + } + + /// + /// 查找类似 验证失败 的本地化字符串。 + /// + internal static string ServerPassportVerifyFailed { + get { + return ResourceManager.GetString("ServerPassportVerifyFailed", resourceCulture); + } + } + + /// + /// 查找类似 验证请求过快,请 1 分钟后再试 的本地化字符串。 + /// + internal static string ServerPassportVerifyTooFrequent { + get { + return ResourceManager.GetString("ServerPassportVerifyTooFrequent", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录失败,当前 Uid 已被胡桃数据库封禁 的本地化字符串。 + /// + internal static string ServerRecordBannedUid { + get { + return ResourceManager.GetString("ServerRecordBannedUid", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录失败,正在计算统计数据 的本地化字符串。 + /// + internal static string ServerRecordComputingStatistics { + get { + return ResourceManager.GetString("ServerRecordComputingStatistics", resourceCulture); + } + } + + /// + /// 查找类似 获取数据失败,正在计算统计数据 的本地化字符串。 + /// + internal static string ServerRecordComputingStatistics2 { + get { + return ResourceManager.GetString("ServerRecordComputingStatistics2", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录失败,服务器异常,请尽快联系开发者解决 的本地化字符串。 + /// + internal static string ServerRecordInternalException { + get { + return ResourceManager.GetString("ServerRecordInternalException", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录失败,存在无效的数据 的本地化字符串。 + /// + internal static string ServerRecordInvalidData { + get { + return ResourceManager.GetString("ServerRecordInvalidData", resourceCulture); + } + } + + /// + /// 查找类似 无效的 Uid 的本地化字符串。 + /// + internal static string ServerRecordInvalidUid { + get { + return ResourceManager.GetString("ServerRecordInvalidUid", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录失败,不是本期数据 的本地化字符串。 + /// + internal static string ServerRecordNotCurrentSchedule { + get { + return ResourceManager.GetString("ServerRecordNotCurrentSchedule", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录失败,当前 Uid 的记录仍在处理中,请勿重复操作 的本地化字符串。 + /// + internal static string ServerRecordPreviousRequestNotCompleted { + get { + return ResourceManager.GetString("ServerRecordPreviousRequestNotCompleted", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录成功,获赠祈愿记录上传服务时长 的本地化字符串。 + /// + internal static string ServerRecordUploadSuccessAndGachaLogServiceTimeExtended { + get { + return ResourceManager.GetString("ServerRecordUploadSuccessAndGachaLogServiceTimeExtended", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录成功,但未登录胡桃账号,无法获赠祈愿记录上传服务时长 的本地化字符串。 + /// + internal static string ServerRecordUploadSuccessButNoPassport { + get { + return ResourceManager.GetString("ServerRecordUploadSuccessButNoPassport", resourceCulture); + } + } + + /// + /// 查找类似 上传深渊记录成功,但不是本期首次提交,无法获赠祈愿记录上传服务时长 的本地化字符串。 + /// + internal static string ServerRecordUploadSuccessButNotFirstTimeAtCurrentSchedule { + get { + return ResourceManager.GetString("ServerRecordUploadSuccessButNotFirstTimeAtCurrentSchedule", resourceCulture); + } + } + /// /// 查找类似 新增:{0} 个成就 | 更新:{1} 个成就 | 删除:{2} 个成就 的本地化字符串。 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 42c2f090..96616973 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -506,6 +506,75 @@ 必须先选择一个用户与角色 + + 胡桃云保存的祈愿记录存档数已达当前账号上限 + + + 未开通祈愿记录上传服务或已到期 + + + 祈愿数据存在无效的物品,无法保存至胡桃云 + + + 数据异常,无法保存至云端,请勿跨账号上传或尝试删除云端数据后重试 + + + 当前邮箱尚未注册 + + + 当前邮箱已被注册 + + + 注册失败,服务器异常,请尽快联系开发者解决 + + + 用户不存在,注销失败 + + + 用户不存在,获取用户信息失败 + + + 用户名或密码错误 + + + 验证失败 + + + 验证请求过快,请 1 分钟后再试 + + + 上传深渊记录失败,当前 Uid 已被胡桃数据库封禁 + + + 上传深渊记录失败,正在计算统计数据 + + + 获取数据失败,正在计算统计数据 + + + 上传深渊记录失败,服务器异常,请尽快联系开发者解决 + + + 上传深渊记录失败,存在无效的数据 + + + 无效的 Uid + + + 上传深渊记录失败,不是本期数据 + + + 上传深渊记录失败,当前 Uid 的记录仍在处理中,请勿重复操作 + + + 上传深渊记录成功,获赠祈愿记录上传服务时长 + + + 上传深渊记录成功,但未登录胡桃账号,无法获赠祈愿记录上传服务时长 + + + 上传深渊记录成功,但不是本期首次提交,无法获赠祈愿记录上传服务时长 + 新增:{0} 个成就 | 更新:{1} 个成就 | 删除:{2} 个成就 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilderContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilderContext.cs index de01bb6f..d5e89da4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilderContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilderContext.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; +using Snap.Hutao.Web.Hutao; using Snap.Hutao.Web.Hutao.GachaLog; using Snap.Hutao.Web.Response; @@ -54,7 +55,7 @@ internal readonly struct TypedWishSummaryBuilderContext return new(taskContext, gachaLogClient, SH.ServiceGachaLogFactoryWeaponWishName, 80, 10, IsWeaponEventWish, GachaDistributionType.WeaponEvent); } - public ValueTask> GetGachaDistributionAsync() + public ValueTask> GetGachaDistributionAsync() { return GachaLogClient.GetGachaDistributionAsync(DistributionType); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs index 746af4ad..2ea24ed2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs @@ -10,6 +10,7 @@ using Snap.Hutao.Service.GachaLog.Factory; using Snap.Hutao.Service.Metadata; using Snap.Hutao.ViewModel.GachaLog; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; +using Snap.Hutao.Web.Hutao; using Snap.Hutao.Web.Hutao.GachaLog; using Snap.Hutao.Web.Response; @@ -27,7 +28,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer private readonly IGachaLogDbService gachaLogDbService; /// - public ValueTask>> GetGachaEntriesAsync(CancellationToken token = default) + public ValueTask>> GetGachaEntriesAsync(CancellationToken token = default) { return homaGachaLogClient.GetGachaEntriesAsync(token); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs index c8372147..bd00fab1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs @@ -3,6 +3,7 @@ using Snap.Hutao.Model.Entity; using Snap.Hutao.ViewModel.GachaLog; +using Snap.Hutao.Web.Hutao; using Snap.Hutao.Web.Hutao.GachaLog; using Snap.Hutao.Web.Response; @@ -28,7 +29,7 @@ internal interface IGachaLogHutaoCloudService /// 祈愿统计信息 ValueTask> GetCurrentEventStatisticsAsync(CancellationToken token = default); - ValueTask>> GetGachaEntriesAsync(CancellationToken token = default); + ValueTask>> GetGachaEntriesAsync(CancellationToken token = default); /// /// 异步获取祈愿记录 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoSpiralAbyssService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoSpiralAbyssService.cs index 2db8133c..0566c9a0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoSpiralAbyssService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoSpiralAbyssService.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.Extensions.Caching.Memory; +using Snap.Hutao.Web.Hutao; using Snap.Hutao.Web.Hutao.SpiralAbyss; using Snap.Hutao.Web.Response; @@ -64,7 +65,7 @@ internal sealed partial class HutaoSpiralAbyssService : IHutaoSpiralAbyssService return FromCacheOrWebAsync(nameof(TeamAppearance), homaClient.GetTeamCombinationsAsync); } - private async ValueTask FromCacheOrWebAsync(string typeName, Func>> taskFunc) + private async ValueTask FromCacheOrWebAsync(string typeName, Func>> taskFunc) where T : class, new() { string key = $"{nameof(HutaoSpiralAbyssService)}.Cache.{typeName}"; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs index dfa6ab9e..301024dc 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs @@ -8,6 +8,7 @@ using Snap.Hutao.Service.SpiralAbyss; using Snap.Hutao.Service.User; using Snap.Hutao.ViewModel.Complex; using Snap.Hutao.ViewModel.User; +using Snap.Hutao.Web.Hutao; using Snap.Hutao.Web.Hutao.SpiralAbyss; using Snap.Hutao.Web.Hutao.SpiralAbyss.Post; using System.Collections.ObjectModel; @@ -134,11 +135,17 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel if (response is { ReturnCode: 0 }) { - infoBarService.Success(response.Message); + if (response is ILocalizableResponse localizableResponse) + { + infoBarService.Success(localizableResponse.GetLocalizationMessage()); + } } else { - infoBarService.Warning(response.Message); + if (response is ILocalizableResponse localizableResponse) + { + infoBarService.Warning(localizableResponse.GetLocalizationMessage()); + } } } } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssView.cs index d898d8f6..68244651 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssView.cs @@ -148,5 +148,4 @@ internal sealed class SpiralAbyssView : IEntityOnly, { return ranks.Where(r => r.AvatarId != 0U).Select(r => new RankAvatar(r.Value, context.IdAvatarMap[r.AvatarId])).SingleOrDefault(); } - } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs index 02957b2c..1659306a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs @@ -27,7 +27,7 @@ internal sealed partial class HomaGachaLogClient /// /// 取消令牌 /// 祈愿统计信息 - public async ValueTask> GetGachaEventStatisticsAsync(CancellationToken token = default) + public async ValueTask> GetGachaEventStatisticsAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.GachaLogStatisticsCurrentEvents) @@ -35,11 +35,11 @@ internal sealed partial class HomaGachaLogClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -48,7 +48,7 @@ internal sealed partial class HomaGachaLogClient /// 分布类型 /// 取消令牌 /// 祈愿分布 - public async ValueTask> GetGachaDistributionAsync(GachaDistributionType distributionType, CancellationToken token = default) + public async ValueTask> GetGachaDistributionAsync(GachaDistributionType distributionType, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.GachaLogStatisticsDistribution(distributionType)) @@ -56,11 +56,11 @@ internal sealed partial class HomaGachaLogClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -68,7 +68,7 @@ internal sealed partial class HomaGachaLogClient /// /// 取消令牌 /// Uid 列表 - public async ValueTask>> GetGachaEntriesAsync(CancellationToken token = default) + public async ValueTask>> GetGachaEntriesAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.GachaLogEntries) @@ -76,11 +76,11 @@ internal sealed partial class HomaGachaLogClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -89,7 +89,7 @@ internal sealed partial class HomaGachaLogClient /// uid /// 取消令牌 /// 末尾Id - public async ValueTask> GetEndIdsAsync(string uid, CancellationToken token = default) + public async ValueTask> GetEndIdsAsync(string uid, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.GachaLogEndIds(uid)) @@ -97,11 +97,11 @@ internal sealed partial class HomaGachaLogClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -111,7 +111,7 @@ internal sealed partial class HomaGachaLogClient /// 末尾 Id /// 取消令牌 /// 云端祈愿记录 - public async ValueTask>> RetrieveGachaItemsAsync(string uid, EndIds endIds, CancellationToken token = default) + public async ValueTask>> RetrieveGachaItemsAsync(string uid, EndIds endIds, CancellationToken token = default) { UidAndEndIds uidAndEndIds = new(uid, endIds); @@ -121,11 +121,11 @@ internal sealed partial class HomaGachaLogClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -135,7 +135,7 @@ internal sealed partial class HomaGachaLogClient /// 祈愿记录 /// 取消令牌 /// 响应 - public async ValueTask UploadGachaItemsAsync(string uid, List gachaItems, CancellationToken token = default) + public async ValueTask UploadGachaItemsAsync(string uid, List gachaItems, CancellationToken token = default) { UidAndItems uidAndItems = new(uid, gachaItems); @@ -145,11 +145,11 @@ internal sealed partial class HomaGachaLogClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response.Response? resp = await builder - .TryCatchSendAsync(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -158,7 +158,7 @@ internal sealed partial class HomaGachaLogClient /// uid /// 取消令牌 /// 响应 - public async ValueTask DeleteGachaItemsAsync(string uid, CancellationToken token = default) + public async ValueTask DeleteGachaItemsAsync(string uid, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.GachaLogDelete(uid)) @@ -166,11 +166,11 @@ internal sealed partial class HomaGachaLogClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response.Response? resp = await builder - .TryCatchSendAsync(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } private sealed class UidAndEndIds diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs index 064b1757..66a8cc8f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs @@ -24,20 +24,20 @@ internal sealed partial class HutaoAsAServiceClient private readonly MetadataOptions metadataOptions; private readonly HttpClient httpClient; - public async ValueTask>> GetAnnouncementListAsync(List excluedeIds, CancellationToken token = default) + public async ValueTask>> GetAnnouncementListAsync(List excluedeIds, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.Announcement(metadataOptions.LocaleName)) .PostJson(excluedeIds); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } - public async ValueTask UploadAnnouncementAsync(UploadAnnouncement uploadAnnouncement, CancellationToken token = default) + public async ValueTask UploadAnnouncementAsync(UploadAnnouncement uploadAnnouncement, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.AnnouncementUpload) @@ -45,14 +45,14 @@ internal sealed partial class HutaoAsAServiceClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response.Response? resp = await builder - .TryCatchSendAsync(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } - public async ValueTask GachaLogCompensationAsync(int days, CancellationToken token = default) + public async ValueTask GachaLogCompensationAsync(int days, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.GachaLogCompensation(days)) @@ -60,14 +60,14 @@ internal sealed partial class HutaoAsAServiceClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response.Response? resp = await builder - .TryCatchSendAsync(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } - public async ValueTask GachaLogDesignationAsync(string userName, int days, CancellationToken token = default) + public async ValueTask GachaLogDesignationAsync(string userName, int days, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.GachaLogDesignation(userName, days)) @@ -75,10 +75,10 @@ internal sealed partial class HutaoAsAServiceClient await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false); - Response.Response? resp = await builder - .TryCatchSendAsync(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoResponse.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoResponse.cs new file mode 100644 index 00000000..37b54b81 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoResponse.cs @@ -0,0 +1,58 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Service.Notification; +using System.Runtime.CompilerServices; + +namespace Snap.Hutao.Web.Hutao; + +internal sealed class HutaoResponse : Response.Response, ILocalizableResponse +{ + [JsonConstructor] + public HutaoResponse(int returnCode, string message, string? localizationKey) + : base(returnCode, message) + { + LocalizationKey = localizationKey; + } + + [JsonPropertyName("l10nKey")] + public string? LocalizationKey { get; set; } + + public static HutaoResponse DefaultIfNull(HutaoResponse? response, [CallerMemberName] string callerName = default!) + { + // 0x26F19335 is a magic number that hashed from "Snap.Hutao" + response ??= new(InternalFailure, SH.WebResponseRequestExceptionFormat.Format(callerName, null), default); + return response; + } + + public static HutaoResponse DefaultIfNull(HutaoResponse? response, [CallerMemberName] string callerName = default!) + { + // 0x26F19335 is a magic number that hashed from "Snap.Hutao" + response ??= new(InternalFailure, SH.WebResponseRequestExceptionFormat.Format(callerName, typeof(TData).Name), default, default); + return response ?? new(InternalFailure, SH.WebResponseRequestExceptionFormat.Format(callerName, typeof(TData).Name), default, default); + } + + public override string ToString() + { + return SH.WebResponseFormat.Format(ReturnCode, this.GetLocalizationMessageOrDefault()); + } +} + +[SuppressMessage("", "SA1402")] +internal sealed class HutaoResponse : Response.Response, ILocalizableResponse +{ + [JsonConstructor] + public HutaoResponse(int returnCode, string message, TData? data, string? localizationKey) + : base(returnCode, message, data) + { + LocalizationKey = localizationKey; + } + + [JsonPropertyName("l10nKey")] + public string? LocalizationKey { get; set; } + + public override string ToString() + { + return SH.WebResponseFormat.Format(ReturnCode, this.GetLocalizationMessageOrDefault()); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/ILocalizableResponse.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/ILocalizableResponse.cs new file mode 100644 index 00000000..49eaf8c5 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/ILocalizableResponse.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Hutao; + +internal interface ILocalizableResponse +{ + public string? LocalizationKey { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/LocalizableResponseExtension.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/LocalizableResponseExtension.cs new file mode 100644 index 00000000..b35eacab --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/LocalizableResponseExtension.cs @@ -0,0 +1,31 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System.Globalization; + +namespace Snap.Hutao.Web.Hutao; + +internal static class LocalizableResponseExtension +{ + public static string? GetLocalizationMessageOrDefault(this ILocalizableResponse localizableResponse) + { + string? key = localizableResponse.LocalizationKey; + if (string.IsNullOrEmpty(key)) + { + return default; + } + + return SH.ResourceManager.GetString(key, CultureInfo.CurrentCulture); + } + + public static string GetLocalizationMessage(this ILocalizableResponse localizableResponse) + { + string? key = localizableResponse.LocalizationKey; + if (string.IsNullOrEmpty(key)) + { + return string.Empty; + } + + return SH.ResourceManager.GetString(key, CultureInfo.CurrentCulture) ?? string.Empty; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HomaSpiralAbyssClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HomaSpiralAbyssClient.cs index 13f5b9c3..d4841cd1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HomaSpiralAbyssClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HomaSpiralAbyssClient.cs @@ -36,17 +36,17 @@ internal sealed partial class HomaSpiralAbyssClient /// uid /// 取消令牌 /// 当前是否上传了数据 - public async ValueTask> CheckRecordUploadedAsync(PlayerUid uid, CancellationToken token = default) + public async ValueTask> CheckRecordUploadedAsync(PlayerUid uid, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.RecordCheck(uid.Value)) .Get(); - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -56,17 +56,17 @@ internal sealed partial class HomaSpiralAbyssClient /// uid /// 取消令牌 /// 排行信息 - public async ValueTask> GetRankAsync(PlayerUid uid, CancellationToken token = default) + public async ValueTask> GetRankAsync(PlayerUid uid, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.RecordRank(uid.Value)) .Get(); - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -75,17 +75,17 @@ internal sealed partial class HomaSpiralAbyssClient /// /// 取消令牌 /// 总览信息 - public async ValueTask> GetOverviewAsync(CancellationToken token = default) + public async ValueTask> GetOverviewAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.StatisticsOverview) .Get(); - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -94,17 +94,17 @@ internal sealed partial class HomaSpiralAbyssClient /// /// 取消令牌 /// 角色出场率 - public async ValueTask>> GetAvatarAttendanceRatesAsync(CancellationToken token = default) + public async ValueTask>> GetAvatarAttendanceRatesAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.StatisticsAvatarAttendanceRate) .Get(); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -113,17 +113,17 @@ internal sealed partial class HomaSpiralAbyssClient /// /// 取消令牌 /// 角色出场率 - public async ValueTask>> GetAvatarUtilizationRatesAsync(CancellationToken token = default) + public async ValueTask>> GetAvatarUtilizationRatesAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.StatisticsAvatarUtilizationRate) .Get(); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -132,17 +132,17 @@ internal sealed partial class HomaSpiralAbyssClient /// /// 取消令牌 /// 角色/武器/圣遗物搭配 - public async ValueTask>> GetAvatarCollocationsAsync(CancellationToken token = default) + public async ValueTask>> GetAvatarCollocationsAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.StatisticsAvatarAvatarCollocation) .Get(); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -151,17 +151,17 @@ internal sealed partial class HomaSpiralAbyssClient /// /// 取消令牌 /// 角色/武器/圣遗物搭配 - public async ValueTask>> GetWeaponCollocationsAsync(CancellationToken token = default) + public async ValueTask>> GetWeaponCollocationsAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.StatisticsWeaponWeaponCollocation) .Get(); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -170,17 +170,17 @@ internal sealed partial class HomaSpiralAbyssClient /// /// 取消令牌 /// 角色图片列表 - public async ValueTask>> GetAvatarHoldingRatesAsync(CancellationToken token = default) + public async ValueTask>> GetAvatarHoldingRatesAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.StatisticsAvatarHoldingRate) .Get(); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -189,17 +189,17 @@ internal sealed partial class HomaSpiralAbyssClient /// /// 取消令牌 /// 队伍出场列表 - public async ValueTask>> GetTeamCombinationsAsync(CancellationToken token = default) + public async ValueTask>> GetTeamCombinationsAsync(CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.StatisticsTeamCombination) .Get(); - Response>? resp = await builder - .TryCatchSendAsync>>(httpClient, logger, token) + HutaoResponse>? resp = await builder + .TryCatchSendAsync>>(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } /// @@ -248,16 +248,16 @@ internal sealed partial class HomaSpiralAbyssClient /// 玩家记录 /// 取消令牌 /// 响应 - public async ValueTask UploadRecordAsync(SimpleRecord playerRecord, CancellationToken token = default) + public async ValueTask UploadRecordAsync(SimpleRecord playerRecord, CancellationToken token = default) { HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() .SetRequestUri(HutaoEndpoints.RecordUpload) .PostJson(playerRecord); - Response.Response? resp = await builder - .TryCatchSendAsync(httpClient, logger, token) + HutaoResponse? resp = await builder + .TryCatchSendAsync(httpClient, logger, token) .ConfigureAwait(false); - return Response.Response.DefaultIfNull(resp); + return HutaoResponse.DefaultIfNull(resp); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs index 2d190762..30697bca 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs @@ -139,7 +139,7 @@ internal class Response /// 数据类型 [SuppressMessage("", "SA1402")] [HighQuality] -internal sealed class Response : Response, IJsResult +internal class Response : Response, IJsResult { /// /// 构造一个新的 Mihoyo 标准API响应