Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Lightczx committed Oct 17, 2024
1 parent 4b7537b commit 343f401
Show file tree
Hide file tree
Showing 58 changed files with 512 additions and 697 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public sealed class DependencyInjectionTest
.AddKeyedTransient<IKeyedService, KeyedServiceA>("A")
.AddKeyedTransient<IKeyedService, KeyedServiceB>("B")
.AddTransient(typeof(IGenericService<>), typeof(GenericService<>))
.AddTransient(typeof(IGenericService<int>), typeof(CloseGenericService))
.AddLogging(builder => builder.AddConsole())
.BuildServiceProvider();

Expand All @@ -28,11 +29,14 @@ public void OriginalTypeCannotResolved()
[TestMethod]
public void GenericServicesCanBeResolved()
{
IServiceProvider services = new ServiceCollection()
.AddTransient(typeof(IGenericService<>), typeof(GenericService<>))
.BuildServiceProvider();
Assert.IsNotNull(services.GetService<IGenericService<double>>());
}

Assert.IsNotNull(services.GetService<IGenericService<int>>());
[TestMethod]
public void CloseGenericSeriveCanBeResolved()
{
IGenericService<int> service = services.GetRequiredService<IGenericService<int>>();
Assert.IsTrue(service is CloseGenericService);
}

[TestMethod]
Expand All @@ -54,7 +58,7 @@ public void LoggerWithInterfaceTypeCanBeResolved()
}

[TestMethod]
public void KeyedServicesCanBeResolvedAsEnumerable()
public void KeyedServicesCanNotBeResolvedAsEnumerable()
{
Assert.IsNotNull(services.GetRequiredKeyedService<IKeyedService>("A"));
Assert.IsNotNull(services.GetRequiredKeyedService<IKeyedService>("B"));
Expand Down Expand Up @@ -96,6 +100,10 @@ private sealed class GenericService<T> : IGenericService<T>
{
}

private sealed class CloseGenericService : IGenericService<int>
{
}

private sealed class NonInjectedServiceA
{
}
Expand All @@ -110,11 +118,7 @@ public NonInjectedServiceB(NonInjectedServiceA? serviceA)

private interface IKeyedService;

private sealed class KeyedServiceA : IKeyedService
{
}
private sealed class KeyedServiceA : IKeyedService;

private sealed class KeyedServiceB : IKeyedService
{
}
private sealed class KeyedServiceB : IKeyedService;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Quartz;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Service;
using Snap.Hutao.Web.Response;
using System.Globalization;
using System.Runtime.CompilerServices;
using Windows.Globalization;
Expand Down Expand Up @@ -34,6 +35,7 @@ public static ServiceProvider Initialize()
.AddJsonOptions()
.AddDatabase()
.AddInjections()
.AddResponseValidation()
.AddConfiguredHttpClients()

// Discrete services
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Snap.Hutao.Core.Threading;

internal static class ValueResultExtension
{
public static bool TryGetValue<TValue>(this in ValueResult<bool, TValue> valueResult, [NotNullWhen(true)] out TValue value)
public static bool TryGetValue<TValue>(this in ValueResult<bool, TValue> valueResult, [NotNullWhen(true)][MaybeNullWhen(false)] out TValue value)
{
value = valueResult.Value;
return valueResult.IsOk;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async ValueTask<AnnouncementWrapper> GetAnnouncementWrapperAsync(string l
await taskContext.SwitchToBackgroundAsync();

List<AnnouncementContent>? contents;
AnnouncementWrapper wrapper;
AnnouncementWrapper? wrapper;
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AnnouncementClient announcementClient = scope.ServiceProvider.GetRequiredService<AnnouncementClient>();
Expand All @@ -45,23 +45,21 @@ public async ValueTask<AnnouncementWrapper> GetAnnouncementWrapperAsync(string l
.GetAnnouncementsAsync(languageCode, region, cancellationToken)
.ConfigureAwait(false);

if (!announcementWrapperResponse.IsOk())
if (!ResponseValidator.TryValidate(announcementWrapperResponse, scope.ServiceProvider, out wrapper))
{
return default!;
}

wrapper = announcementWrapperResponse.Data;

Response<ListWrapper<AnnouncementContent>> announcementContentResponse = await announcementClient
.GetAnnouncementContentsAsync(languageCode, region, cancellationToken)
.ConfigureAwait(false);

if (!announcementContentResponse.IsOk())
if (!ResponseValidator.TryValidate(announcementContentResponse, scope.ServiceProvider, out ListWrapper<AnnouncementContent>? contentsWrapper))
{
return default!;
}

contents = announcementContentResponse.Data.List;
contents = contentsWrapper.List;
}

Dictionary<int, string> contentMap = contents.ToDictionary(id => id.AnnId, content => content.Content);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,22 @@ public async ValueTask<List<EntityAvatarInfo>> UpdateDbAvatarInfosAsync(UserAndU
.GetCharacterListAsync(userAndUid, token)
.ConfigureAwait(false);

if (!listResponse.IsOk())
if (!ResponseValidator.TryValidate(listResponse, serviceProvider, out ListWrapper<Character>? charactersWrapper))
{
return avatarInfoRepository.GetAvatarInfoListByUid(uid);
}

List<AvatarId> characterIds = listResponse.Data.List.SelectList(info => info.Id);
List<AvatarId> characterIds = charactersWrapper.List.SelectList(info => info.Id);
Response<ListWrapper<DetailedCharacter>> detailResponse = await gameRecordClient
.GetCharacterDetailAsync(userAndUid, characterIds, token)
.ConfigureAwait(false);

if (!detailResponse.IsOk())
if (!ResponseValidator.TryValidate(detailResponse, serviceProvider, out ListWrapper<DetailedCharacter>? detailsWrapper))
{
return avatarInfoRepository.GetAvatarInfoListByUid(uid);
}

foreach (DetailedCharacter character in detailResponse.Data.List)
foreach (DetailedCharacter character in detailsWrapper.List)
{
if (AvatarIds.IsPlayer(character.Base.Id))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license.

using Microsoft.Windows.AppNotifications;
using Microsoft.Windows.AppNotifications.Builder;
using Snap.Hutao.Core;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Model.Entity;
Expand Down Expand Up @@ -91,7 +92,7 @@ public async ValueTask SendAsync(DailyNoteEntry entry)
</toast>
""";
AppNotification notification = new(rawXml);

AppNotificationBuilder builder = new();
if (options.IsSilentWhenPlayingGame && gameService.IsGameRunning())
{
notification.SuppressDisplay = true;
Expand All @@ -111,19 +112,18 @@ public async ValueTask SendAsync(DailyNoteEntry entry)

private async ValueTask<string> GetUserUidAsync(DailyNoteEntry entry)
{
Response<ListWrapper<UserGameRole>> rolesResponse;
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
BindingClient bindingClient = scope.ServiceProvider.GetRequiredService<BindingClient>();
rolesResponse = await bindingClient
Response<ListWrapper<UserGameRole>> rolesResponse = await bindingClient
.GetUserGameRolesOverseaAwareAsync(entry.User)
.ConfigureAwait(false);
}

if (rolesResponse.IsOk())
{
List<UserGameRole> roles = rolesResponse.Data.List;
return roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? ToastAttributionUnknown;
if (ResponseValidator.TryValidate(rolesResponse, infoBarService, out ListWrapper<UserGameRole>? listWrapper))
{
List<UserGameRole> roles = listWrapper.List;
return roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? ToastAttributionUnknown;
}
}

return SH.ServiceDailyNoteNotifierAttribution;
Expand Down
12 changes: 6 additions & 6 deletions src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hoyolab;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
using Snap.Hutao.Web.Response;
using System.Collections.ObjectModel;
using WebDailyNote = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote;

Expand Down Expand Up @@ -47,7 +48,7 @@ public async ValueTask AddDailyNoteAsync(UserAndUid userAndUid, CancellationToke

DailyNoteEntry newEntry = DailyNoteEntry.From(userAndUid);

Web.Response.Response<WebDailyNote> dailyNoteResponse;
Response<WebDailyNote> dailyNoteResponse;
DailyNoteMetadataContext context;
using (IServiceScope scope = serviceProvider.CreateScope())
{
Expand All @@ -62,9 +63,9 @@ public async ValueTask AddDailyNoteAsync(UserAndUid userAndUid, CancellationToke
context = await scope.GetRequiredService<IMetadataService>().GetContextAsync<DailyNoteMetadataContext>(token).ConfigureAwait(false);
}

if (dailyNoteResponse.IsOk())
if (ResponseValidator.TryValidate(dailyNoteResponse, serviceProvider, out WebDailyNote? data))
{
newEntry.UpdateDailyNote(dailyNoteResponse.Data);
newEntry.UpdateDailyNote(data);
}

newEntry.UserGameRole = await userService.GetUserGameRoleByUidAsync(roleUid).ConfigureAwait(false);
Expand Down Expand Up @@ -144,13 +145,12 @@ private async ValueTask RefreshDailyNotesCoreAsync(bool forceRefresh, Cancellati
.GetRequiredService<IOverseaSupportFactory<IGameRecordClient>>()
.Create(PlayerUid.IsOversea(entry.Uid));

Web.Response.Response<WebDailyNote> dailyNoteResponse = await gameRecordClient
Response<WebDailyNote> dailyNoteResponse = await gameRecordClient
.GetDailyNoteAsync(new(entry.User, entry.Uid), token)
.ConfigureAwait(false);

if (dailyNoteResponse.IsOk())
if (ResponseValidator.TryValidate(dailyNoteResponse, serviceProvider, out WebDailyNote? dailyNote))
{
WebDailyNote dailyNote = dailyNoteResponse.Data;
entry.UpdateDailyNote(dailyNote);

// 集合内的实时便笺与数据库取出的非同一个对象,需要分别更新
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(stri
GachaArchive? archive = gachaLogRepository.GetGachaArchiveByUid(uid);
EndIds endIds = CreateEndIds(archive);

Response<List<Web.Hutao.GachaLog.GachaItem>> resp;
List<Web.Hutao.GachaLog.GachaItem>? list;
using (IServiceScope scope = serviceProvider.CreateScope())
{
HomaGachaLogClient homaGachaLogClient = scope.ServiceProvider.GetRequiredService<HomaGachaLogClient>();
resp = await homaGachaLogClient.RetrieveGachaItemsAsync(uid, endIds, token).ConfigureAwait(false);
}
Response<List<Web.Hutao.GachaLog.GachaItem>> resp = await homaGachaLogClient.RetrieveGachaItemsAsync(uid, endIds, token).ConfigureAwait(false);

if (!resp.IsOk())
{
return new(false, default);
if (!ResponseValidator.TryValidate(resp, serviceProvider, out list))
{
return new(false, default);
}
}

if (archive is null)
Expand All @@ -81,7 +81,7 @@ public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(stri
}

Guid archiveId = archive.InnerId;
List<Model.Entity.GachaItem> gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archiveId, i));
List<Model.Entity.GachaItem> gachaItems = list.SelectList(i => Model.Entity.GachaItem.From(archiveId, i));
gachaLogRepository.AddGachaItemRange(gachaItems);
return new(true, archive.InnerId);
}
Expand All @@ -99,33 +99,34 @@ public async ValueTask<ValueResult<bool, string>> DeleteGachaItemsAsync(string u
/// <inheritdoc/>
public async ValueTask<ValueResult<bool, HutaoStatistics>> GetCurrentEventStatisticsAsync(CancellationToken token = default)
{
Response<GachaEventStatistics> response;
GachaEventStatistics? raw;
using (IServiceScope scope = serviceProvider.CreateScope())
{
HomaGachaLogClient homaGachaLogClient = scope.ServiceProvider.GetRequiredService<HomaGachaLogClient>();
response = await homaGachaLogClient.GetGachaEventStatisticsAsync(token).ConfigureAwait(false);
Response<GachaEventStatistics> response = await homaGachaLogClient.GetGachaEventStatisticsAsync(token).ConfigureAwait(false);

if (!ResponseValidator.TryValidate(response, serviceProvider, out raw))
{
return new(false, default!);
}
}

if (response.IsOk())
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
HutaoStatisticsFactoryMetadataContext context = await metadataService
.GetContextAsync<HutaoStatisticsFactoryMetadataContext>(token)
.ConfigureAwait(false);

try
{
HutaoStatisticsFactory factory = new(context);
HutaoStatistics statistics = factory.Create(raw);
return new(true, statistics);
}
catch
{
HutaoStatisticsFactoryMetadataContext context = await metadataService
.GetContextAsync<HutaoStatisticsFactoryMetadataContext>(token)
.ConfigureAwait(false);

GachaEventStatistics raw = response.Data;
try
{
HutaoStatisticsFactory factory = new(context);
HutaoStatistics statistics = factory.Create(raw);
return new(true, statistics);
}
catch
{
// 元数据未能即时更新导致异常?
return new(false, default!);
}
// 元数据未能即时更新导致异常?
return new(false, default!);
}
}

Expand All @@ -138,7 +139,8 @@ public async ValueTask<ValueResult<bool, HutaoStatistics>> GetCurrentEventStatis
{
HomaGachaLogClient homaGachaLogClient = scope.ServiceProvider.GetRequiredService<HomaGachaLogClient>();
Response<EndIds> resp = await homaGachaLogClient.GetEndIdsAsync(uid, token).ConfigureAwait(false);
return resp.IsOk() ? resp.Data : default;
ResponseValidator.TryValidate(resp, serviceProvider, out EndIds? raw);
return raw;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.

using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
using Snap.Hutao.Web.Request;
Expand All @@ -17,6 +18,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
[Injection(InjectAs.Transient, typeof(IGachaLogQueryProvider), Key = RefreshOption.SToken)]
internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvider
{
private readonly IInfoBarService infoBarService;
private readonly BindingClient2 bindingClient2;
private readonly CultureOptions cultureOptions;
private readonly IUserService userService;
Expand All @@ -37,12 +39,12 @@ public async ValueTask<ValueResult<bool, GachaLogQuery>> GetQueryAsync()
GenAuthKeyData data = GenAuthKeyData.CreateForWebViewGacha(userAndUid.Uid);
Response<GameAuthKey> authkeyResponse = await bindingClient2.GenerateAuthenticationKeyAsync(userAndUid.User, data).ConfigureAwait(false);

if (!authkeyResponse.IsOk())
if (!ResponseValidator.TryValidate(authkeyResponse, infoBarService, out GameAuthKey? authKey))
{
return new(false, GachaLogQuery.Invalid(SH.ServiceGachaLogUrlProviderAuthkeyRequestFailed));
}

return new(true, new(ComposeQueryString(data, authkeyResponse.Data, cultureOptions.LanguageCode)));
return new(true, new(ComposeQueryString(data, authKey, cultureOptions.LanguageCode)));
}

private static string ComposeQueryString(GenAuthKeyData genAuthKeyData, GameAuthKey gameAuthKey, string lang)
Expand Down
10 changes: 4 additions & 6 deletions src/Snap.Hutao/Snap.Hutao/Service/Game/GameAudioSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ public GameAudioSystem(bool chinese, bool english, bool japanese, bool korean)
this.korean = korean;
}

public string GameDirectory { get => gameDirectory; }
public bool Chinese { get => chinese ??= File.Exists(Path.Combine(gameDirectory, GameConstants.AudioChinesePkgVersion)); }

public bool Chinese { get => chinese ??= File.Exists(Path.Combine(GameDirectory, GameConstants.AudioChinesePkgVersion)); }
public bool English { get => english ??= File.Exists(Path.Combine(gameDirectory, GameConstants.AudioEnglishPkgVersion)); }

public bool English { get => english ??= File.Exists(Path.Combine(GameDirectory, GameConstants.AudioEnglishPkgVersion)); }
public bool Japanese { get => japanese ??= File.Exists(Path.Combine(gameDirectory, GameConstants.AudioJapanesePkgVersion)); }

public bool Japanese { get => japanese ??= File.Exists(Path.Combine(GameDirectory, GameConstants.AudioJapanesePkgVersion)); }

public bool Korean { get => korean ??= File.Exists(Path.Combine(GameDirectory, GameConstants.AudioKoreanPkgVersion)); }
public bool Korean { get => korean ??= File.Exists(Path.Combine(gameDirectory, GameConstants.AudioKoreanPkgVersion)); }
}
2 changes: 1 addition & 1 deletion src/Snap.Hutao/Snap.Hutao/Service/Game/GameFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ public string GameDirectory

public string PredownloadStatusPath { get => Path.Combine(ChunksDirectory, "snap_hutao_predownload_status.json"); }

public GameAudioSystem GameAudioSystem { get => gameAudioSystem ??= new(GameFilePath); }
public GameAudioSystem Audio { get => gameAudioSystem ??= new(GameFilePath); }
}
Loading

0 comments on commit 343f401

Please sign in to comment.