mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
fix #882 gachalog import & aggressive merge refresh
This commit is contained in:
@@ -1860,6 +1860,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 不支持的 UIGF 版本 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ServiceUIGFImportUnsupportedVersion {
|
||||
get {
|
||||
return ResourceManager.GetString("ServiceUIGFImportUnsupportedVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 多个用户记录为选中状态 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -773,6 +773,9 @@
|
||||
<data name="ServiceSignInSuccessRewardFormat" xml:space="preserve">
|
||||
<value>签到成功,{0}×{1}</value>
|
||||
</data>
|
||||
<data name="ServiceUIGFImportUnsupportedVersion" xml:space="preserve">
|
||||
<value>不支持的 UIGF 版本</value>
|
||||
</data>
|
||||
<data name="ServiceUserCurrentMultiMatched" xml:space="preserve">
|
||||
<value>多个用户记录为选中状态</value>
|
||||
</data>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog;
|
||||
|
||||
@@ -20,6 +21,8 @@ internal readonly struct GachaItemSaveContext
|
||||
/// </summary>
|
||||
public readonly bool IsLazy;
|
||||
|
||||
public readonly GachaConfigType QueryType;
|
||||
|
||||
/// <summary>
|
||||
/// 结尾 Id
|
||||
/// </summary>
|
||||
@@ -30,10 +33,11 @@ internal readonly struct GachaItemSaveContext
|
||||
/// </summary>
|
||||
public readonly IGachaLogDbService GachaLogDbService;
|
||||
|
||||
public GachaItemSaveContext(List<GachaItem> itemsToAdd, bool isLazy, long endId, IGachaLogDbService gachaLogDbService)
|
||||
public GachaItemSaveContext(List<GachaItem> itemsToAdd, bool isLazy, GachaConfigType queryType, long endId, IGachaLogDbService gachaLogDbService)
|
||||
{
|
||||
ItemsToAdd = itemsToAdd;
|
||||
IsLazy = isLazy;
|
||||
QueryType = queryType;
|
||||
EndId = endId;
|
||||
GachaLogDbService = gachaLogDbService;
|
||||
}
|
||||
@@ -45,7 +49,7 @@ internal readonly struct GachaItemSaveContext
|
||||
// 全量刷新
|
||||
if (!IsLazy)
|
||||
{
|
||||
GachaLogDbService.DeleteNewerGachaItemsByArchiveIdAndEndId(archive.InnerId, EndId);
|
||||
GachaLogDbService.DeleteNewerGachaItemsByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId);
|
||||
}
|
||||
|
||||
GachaLogDbService.AddGachaItems(ItemsToAdd);
|
||||
|
||||
@@ -139,6 +139,27 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
return item?.Id ?? long.MaxValue;
|
||||
}
|
||||
|
||||
public long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
// TODO: replace with MaxBy
|
||||
// https://github.com/dotnet/efcore/issues/25566
|
||||
// .MaxBy(i => i.Id);
|
||||
item = appDbContext.GachaItems
|
||||
.AsNoTracking()
|
||||
.Where(i => i.ArchiveId == archiveId && i.QueryType == queryType)
|
||||
.OrderBy(i => i.Id)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
return item?.Id ?? long.MaxValue;
|
||||
}
|
||||
|
||||
public async ValueTask AddGachaArchiveAsync(GachaArchive archive)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
@@ -212,14 +233,14 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteNewerGachaItemsByArchiveIdAndEndId(Guid archiveId, long endId)
|
||||
public void DeleteNewerGachaItemsByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
appDbContext.GachaItems
|
||||
.AsNoTracking()
|
||||
.Where(i => i.ArchiveId == archiveId)
|
||||
.Where(i => i.ArchiveId == archiveId && i.QueryType == queryType)
|
||||
.Where(i => i.Id >= endId)
|
||||
.ExecuteDelete();
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ internal struct GachaLogFetchContext
|
||||
// While no item is fetched, archive can be null.
|
||||
if (TargetArchive is not null)
|
||||
{
|
||||
GachaItemSaveContext saveContext = new(ItemsToAdd, isLazy, QueryOptions.EndId, gachaLogDbService);
|
||||
GachaItemSaveContext saveContext = new(ItemsToAdd, isLazy, QueryOptions.Type, QueryOptions.EndId, gachaLogDbService);
|
||||
saveContext.SaveItems(TargetArchive);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +214,7 @@ internal sealed partial class GachaLogService : IGachaLogService
|
||||
break;
|
||||
}
|
||||
|
||||
// save items for each queryType
|
||||
token.ThrowIfCancellationRequested();
|
||||
fetchContext.SaveItems();
|
||||
await Delay.Random(1000, 2000).ConfigureAwait(false);
|
||||
|
||||
@@ -19,7 +19,7 @@ internal interface IGachaLogDbService
|
||||
|
||||
ValueTask DeleteGachaArchiveByIdAsync(Guid archiveId);
|
||||
|
||||
void DeleteNewerGachaItemsByArchiveIdAndEndId(Guid archiveId, long endId);
|
||||
void DeleteNewerGachaItemsByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId);
|
||||
|
||||
ValueTask<GachaArchive?> GetGachaArchiveByUidAsync(string uid, CancellationToken token);
|
||||
|
||||
@@ -34,4 +34,6 @@ internal interface IGachaLogDbService
|
||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token);
|
||||
|
||||
long GetOldestGachaItemIdByArchiveId(Guid archiveId);
|
||||
|
||||
long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog;
|
||||
@@ -35,36 +36,39 @@ internal sealed partial class UIGFImportService : IUIGFImportService
|
||||
GachaArchiveOperation.GetOrAdd(gachaLogDbService, taskContext, uigf.Info.Uid, archives, out GachaArchive? archive);
|
||||
Guid archiveId = archive.InnerId;
|
||||
|
||||
long trimId = gachaLogDbService.GetOldestGachaItemIdByArchiveId(archiveId);
|
||||
|
||||
logger.LogInformation("Last Id to trim with: [{Id}]", trimId);
|
||||
|
||||
_ = uigf.IsCurrentVersionSupported(out UIGFVersion version);
|
||||
|
||||
List<GachaItem> toAdd = version switch
|
||||
foreach (GachaConfigType queryType in GachaLog.QueryTypes)
|
||||
{
|
||||
UIGFVersion.Major2Minor3OrHigher => uigf.List
|
||||
.OrderByDescending(i => i.Id)
|
||||
.Where(i => i.Id < trimId)
|
||||
.Select(i => GachaItem.From(archiveId, i))
|
||||
.ToList(),
|
||||
UIGFVersion.Major2Minor2OrLower => uigf.List
|
||||
.OrderByDescending(i => i.Id)
|
||||
.Where(i => i.Id < trimId)
|
||||
.Select(i => GachaItem.From(archiveId, i, context.GetItemId(i)))
|
||||
.ToList(),
|
||||
_ => new(),
|
||||
};
|
||||
long trimId = gachaLogDbService.GetOldestGachaItemIdByArchiveIdAndQueryType(archiveId, queryType);
|
||||
logger.LogInformation("Last Id to trim with: [{Id}]", trimId);
|
||||
|
||||
// 越早的记录手工导入的可能性越高
|
||||
// 错误率相对来说会更高
|
||||
// 因此从尾部开始查找
|
||||
if (toAdd.LastOrDefault(item => item.ItemId is 0U) is { } item)
|
||||
{
|
||||
ThrowHelper.InvalidOperation(SH.ServiceGachaLogUIGFImportItemInvalidFormat.Format(item.Id));
|
||||
List<GachaItem> currentTypeToAdd = version switch
|
||||
{
|
||||
UIGFVersion.Major2Minor3OrHigher => uigf.List
|
||||
.Where(i => i.UIGFGachaType == queryType && i.Id < trimId)
|
||||
.OrderByDescending(i => i.Id)
|
||||
.Select(i => GachaItem.From(archiveId, i))
|
||||
.ToList(),
|
||||
UIGFVersion.Major2Minor2OrLower => uigf.List
|
||||
.Where(i => i.UIGFGachaType == queryType && i.Id < trimId)
|
||||
.OrderByDescending(i => i.Id)
|
||||
.Select(i => GachaItem.From(archiveId, i, context.GetItemId(i)))
|
||||
.ToList(),
|
||||
_ => throw ThrowHelper.InvalidOperation(SH.ServiceUIGFImportUnsupportedVersion),
|
||||
};
|
||||
|
||||
// 越早的记录手工导入的可能性越高
|
||||
// 错误率相对来说会更高
|
||||
// 因此从尾部开始查找
|
||||
if (currentTypeToAdd.LastOrDefault(item => item.ItemId is 0U) is { } item)
|
||||
{
|
||||
ThrowHelper.InvalidOperation(SH.ServiceGachaLogUIGFImportItemInvalidFormat.Format(item.Id));
|
||||
}
|
||||
|
||||
await gachaLogDbService.AddGachaItemsAsync(currentTypeToAdd).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await gachaLogDbService.AddGachaItemsAsync(toAdd).ConfigureAwait(false);
|
||||
return archive;
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@
|
||||
Text="{shcm:ResourceString Name=ViewPageGachaLogRefreshByManualInput}"/>
|
||||
<ToggleMenuFlyoutItem
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
IsChecked="{Binding IsAggressiveRefresh}"
|
||||
IsChecked="{Binding IsAggressiveRefresh, Mode=TwoWay}"
|
||||
Text="{shcm:ResourceString Name=ViewPageGachaLogAggressiveRefresh}"/>
|
||||
</MenuFlyout>
|
||||
</AppBarButton.Flyout>
|
||||
|
||||
@@ -31,6 +31,8 @@ internal struct GachaLogQueryOptions
|
||||
/// </summary>
|
||||
public long EndId;
|
||||
|
||||
public GachaConfigType Type;
|
||||
|
||||
/// <summary>
|
||||
/// Keys required:
|
||||
/// authkey_ver
|
||||
@@ -49,18 +51,20 @@ internal struct GachaLogQueryOptions
|
||||
/// 构造一个新的祈愿记录请求配置
|
||||
/// </summary>
|
||||
/// <param name="query">原始查询字符串</param>
|
||||
/// <param name="type">祈愿类型</param>
|
||||
/// <param name="queryType">祈愿类型</param>
|
||||
/// <param name="endId">终止Id</param>
|
||||
public GachaLogQueryOptions(in GachaLogQuery query, GachaConfigType type, long endId = 0L)
|
||||
public GachaLogQueryOptions(in GachaLogQuery query, GachaConfigType queryType)
|
||||
{
|
||||
IsOversea = query.IsOversea;
|
||||
|
||||
// 对于每个类型我们需要单独创建
|
||||
// 对应类型的 GachaLogQueryOptions
|
||||
Type = queryType;
|
||||
innerQuery = QueryString.Parse(query.Query);
|
||||
|
||||
// innerQuery.Set("lang", "zh-cn");
|
||||
innerQuery.Set("gacha_type", (int)type);
|
||||
innerQuery.Set("gacha_type", (int)queryType);
|
||||
innerQuery.Set("size", Size);
|
||||
|
||||
EndId = endId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -82,10 +86,6 @@ internal struct GachaLogQueryOptions
|
||||
return queryString.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到查询字符串
|
||||
/// </summary>
|
||||
/// <returns>匹配的查询字符串</returns>
|
||||
public readonly string ToQueryString()
|
||||
{
|
||||
// Make the cached end id into query.
|
||||
|
||||
Reference in New Issue
Block a user