From 7a5dec42910f4697caad89d1078934781817e468 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 2 Sep 2023 20:23:25 +0800
Subject: [PATCH] fix #882 gachalog import & aggressive merge refresh
---
.../Resource/Localization/SH.Designer.cs | 9 ++++
.../Snap.Hutao/Resource/Localization/SH.resx | 3 ++
.../Service/GachaLog/GachaItemSaveContext.cs | 8 ++-
.../Service/GachaLog/GachaLogDbService.cs | 25 ++++++++-
.../Service/GachaLog/GachaLogFetchContext.cs | 2 +-
.../Service/GachaLog/GachaLogService.cs | 1 +
.../Service/GachaLog/IGachaLogDbService.cs | 4 +-
.../Service/GachaLog/UIGFImportService.cs | 52 ++++++++++---------
.../Snap.Hutao/View/Page/GachaLogPage.xaml | 2 +-
.../Event/GachaInfo/GachaLogQueryOptions.cs | 18 +++----
10 files changed, 84 insertions(+), 40 deletions(-)
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 0c5ef13c..180987c3 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
@@ -1860,6 +1860,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
+ ///
+ /// 查找类似 不支持的 UIGF 版本 的本地化字符串。
+ ///
+ internal static string ServiceUIGFImportUnsupportedVersion {
+ get {
+ return ResourceManager.GetString("ServiceUIGFImportUnsupportedVersion", resourceCulture);
+ }
+ }
+
///
/// 查找类似 多个用户记录为选中状态 的本地化字符串。
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index 1150b286..d2f3ac95 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -773,6 +773,9 @@
签到成功,{0}×{1}
+
+ 不支持的 UIGF 版本
+
多个用户记录为选中状态
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs
index bd8a88e5..9c031b2f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs
@@ -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
///
public readonly bool IsLazy;
+ public readonly GachaConfigType QueryType;
+
///
/// 结尾 Id
///
@@ -30,10 +33,11 @@ internal readonly struct GachaItemSaveContext
///
public readonly IGachaLogDbService GachaLogDbService;
- public GachaItemSaveContext(List itemsToAdd, bool isLazy, long endId, IGachaLogDbService gachaLogDbService)
+ public GachaItemSaveContext(List 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);
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs
index b963b45d..39225a7e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs
@@ -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();
+
+ // 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.GachaItems
.AsNoTracking()
- .Where(i => i.ArchiveId == archiveId)
+ .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType)
.Where(i => i.Id >= endId)
.ExecuteDelete();
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs
index 756d04b4..e243efe7 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs
@@ -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);
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs
index 3796c577..4ff85ee4 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs
@@ -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);
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs
index 4940c1d6..ffa59866 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs
@@ -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 GetGachaArchiveByUidAsync(string uid, CancellationToken token);
@@ -34,4 +34,6 @@ internal interface IGachaLogDbService
ValueTask GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token);
long GetOldestGachaItemIdByArchiveId(Guid archiveId);
+
+ long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType);
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs
index d0c06ddf..93fd0ccf 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs
@@ -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 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 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;
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml
index 3572727d..cfc62001 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml
@@ -61,7 +61,7 @@
Text="{shcm:ResourceString Name=ViewPageGachaLogRefreshByManualInput}"/>
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogQueryOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogQueryOptions.cs
index 8019cfa0..5352e0c6 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogQueryOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogQueryOptions.cs
@@ -31,6 +31,8 @@ internal struct GachaLogQueryOptions
///
public long EndId;
+ public GachaConfigType Type;
+
///
/// Keys required:
/// authkey_ver
@@ -49,18 +51,20 @@ internal struct GachaLogQueryOptions
/// 构造一个新的祈愿记录请求配置
///
/// 原始查询字符串
- /// 祈愿类型
+ /// 祈愿类型
/// 终止Id
- 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;
}
///
@@ -82,10 +86,6 @@ internal struct GachaLogQueryOptions
return queryString.ToString();
}
- ///
- /// 转换到查询字符串
- ///
- /// 匹配的查询字符串
public readonly string ToQueryString()
{
// Make the cached end id into query.