refactor static resource

This commit is contained in:
DismissedLight
2024-04-12 21:40:00 +08:00
parent 72b62aa9c6
commit ee99d0b665
7 changed files with 107 additions and 62 deletions

View File

@@ -5,6 +5,9 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Core.IO;
using Snap.Hutao.Core.IO.Hashing;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.ViewModel.Guide;
using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.IO;
@@ -36,6 +39,7 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
private readonly IHttpClientFactory httpClientFactory;
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
private readonly IServiceProvider serviceProvider;
private readonly ILogger<ImageCache> logger;
@@ -169,38 +173,49 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
HttpClient httpClient = httpClientFactory.CreateClient(nameof(ImageCache));
while (retryCount < 3)
{
using (HttpResponseMessage message = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
if (message.RequestMessage is { RequestUri: { } target } && target != uri)
{
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
}
HttpRequestMessageBuilder requestMessageBuilder = httpRequestMessageBuilderFactory
.Create()
.SetRequestUri(uri)
if (message.IsSuccessStatusCode)
// These headers are only available for our own api
.SetStaticResourceControlHeadersIf(uri.Host.Contains("api.snapgenshin.com", StringComparison.OrdinalIgnoreCase))
.Get();
using (HttpRequestMessage requestMessage = requestMessageBuilder.HttpRequestMessage)
{
using (HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
using (Stream httpStream = await message.Content.ReadAsStreamAsync().ConfigureAwait(false))
if (responseMessage.RequestMessage is { RequestUri: { } target } && target != uri)
{
using (FileStream fileStream = File.Create(baseFile))
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
}
if (responseMessage.IsSuccessStatusCode)
{
using (Stream httpStream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false))
{
await httpStream.CopyToAsync(fileStream).ConfigureAwait(false);
return;
using (FileStream fileStream = File.Create(baseFile))
{
await httpStream.CopyToAsync(fileStream).ConfigureAwait(false);
return;
}
}
}
}
switch (message.StatusCode)
{
case HttpStatusCode.TooManyRequests:
{
retryCount++;
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? retryCountToDelay[retryCount];
logger.LogInformation("Retry download '{Uri}' after {Delay}.", uri, delay);
await Task.Delay(delay).ConfigureAwait(false);
break;
}
switch (responseMessage.StatusCode)
{
case HttpStatusCode.TooManyRequests:
{
retryCount++;
TimeSpan delay = responseMessage.Headers.RetryAfter?.Delta ?? retryCountToDelay[retryCount];
logger.LogInformation("Retry download '{Uri}' after {Delay}.", uri, delay);
await Task.Delay(delay).ConfigureAwait(false);
break;
}
default:
return;
default:
return;
}
}
}
}

View File

@@ -22,7 +22,7 @@ internal static class SettingKeys
public const string DataFolderPath = "DataFolderPath";
public const string Major1Minor10Revision0GuideState = "Major1Minor10Revision0GuideState1";
public const string StaticResourceImageQuality = "StaticResourceImageQuality";
public const string StaticResourceUseTrimmedArchive = "StaticResourceUseTrimmedArchive";
public const string StaticResourceImageArchive = "StaticResourceImageArchive";
public const string HotKeyMouseClickRepeatForever = "HotKeyMouseClickRepeatForever";
public const string IsAllocConsoleDebugModeEnabled = "IsAllocConsoleDebugModeEnabled2";
#endregion

View File

@@ -223,11 +223,13 @@
ItemsSource="{Binding StaticResourceOptions.ImageQualities}"
SelectedItem="{Binding StaticResourceOptions.ImageQuality, Mode=TwoWay}"/>
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumHeader}"/>
<ToggleSwitch
IsOn="{Binding StaticResourceOptions.UseTrimmedArchive, Mode=TwoWay}"
OffContent="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumOff}"
OnContent="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumOn}"/>
<ListView
MinWidth="320"
Margin="0,8,0,32"
DisplayMemberPath="Name"
ItemsSource="{Binding StaticResourceOptions.ImageArchives}"
SelectedItem="{Binding StaticResourceOptions.ImageArchive, Mode=TwoWay}"/>
<TextBlock Margin="0,16,0,0" Text="{Binding StaticResourceOptions.SizeInformationText, Mode=OneWay}"/>
</StackPanel>

View File

@@ -46,31 +46,31 @@ internal static class StaticResource
private static readonly ApplicationDataCompositeValue LatestResourceVersionMap = new()
{
{ "AchievementIcon", 1 },
{ "AvatarCard", 1 },
{ "AvatarIcon", 4 },
{ "Bg", 2 },
{ "ChapterIcon", 2 },
{ "AchievementIcon", 2 },
{ "AvatarCard", 2 },
{ "AvatarIcon", 5 },
{ "Bg", 3 },
{ "ChapterIcon", 3 },
{ "CodexMonster", 0 },
{ "Costume", 1 },
{ "EmotionIcon", 2 },
{ "EquipIcon", 3 },
{ "GachaAvatarIcon", 3 },
{ "GachaAvatarImg", 3 },
{ "GachaEquipIcon", 3 },
{ "Costume", 2 },
{ "EmotionIcon", 3 },
{ "EquipIcon", 4 },
{ "GachaAvatarIcon", 4 },
{ "GachaAvatarImg", 4 },
{ "GachaEquipIcon", 4 },
{ "GcgCharAvatarIcon", 0 },
{ "IconElement", 2 },
{ "ItemIcon", 3 },
{ "LoadingPic", 1 },
{ "MonsterIcon", 2 },
{ "MonsterSmallIcon", 1 },
{ "NameCardIcon", 2 },
{ "NameCardPic", 3 },
{ "IconElement", 3 },
{ "ItemIcon", 4 },
{ "LoadingPic", 2 },
{ "MonsterIcon", 3 },
{ "MonsterSmallIcon", 2 },
{ "NameCardIcon", 3 },
{ "NameCardPic", 4 },
{ "NameCardPicAlpha", 0 },
{ "Property", 1 },
{ "RelicIcon", 3 },
{ "Skill", 3 },
{ "Talent", 3 },
{ "Property", 2 },
{ "RelicIcon", 4 },
{ "Skill", 4 },
{ "Talent", 4 },
};
public static void FulfillAll()

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.ViewModel.Guide;
[Localization]
internal enum StaticResourceArchive
{
[LocalizationKey(nameof(SH.ViewGuideStepStaticResourceSettingMinimumOff))]
Full,
[LocalizationKey(nameof(SH.ViewGuideStepStaticResourceSettingMinimumOn))]
Minimum,
}

View File

@@ -15,6 +15,12 @@ internal static class StaticResourceHttpHeaderBuilderExtension
{
return builder
.SetHeader("x-quality", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw)}")
.SetHeader("x-minimum", $"{LocalSetting.Get(SettingKeys.StaticResourceUseTrimmedArchive, false)}");
.SetHeader("x-archive", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageArchive, StaticResourceArchive.Full)}");
}
public static TBuilder SetStaticResourceControlHeadersIf<TBuilder>(this TBuilder builder, bool condition)
where TBuilder : IHttpHeadersBuilder<HttpHeaders>
{
return condition ? builder.SetStaticResourceControlHeaders() : builder;
}
}

View File

@@ -13,9 +13,12 @@ namespace Snap.Hutao.ViewModel.Guide;
internal sealed class StaticResourceOptions : ObservableObject
{
private readonly List<NameValue<StaticResourceQuality>> imageQualities = CollectionsNameValue.FromEnum<StaticResourceQuality>(q => q.GetLocalizedDescription());
private readonly List<NameValue<StaticResourceArchive>> imageArchives = CollectionsNameValue.FromEnum<StaticResourceArchive>(a => a.GetLocalizedDescription());
private NameValue<StaticResourceQuality>? imageQuality;
private NameValue<StaticResourceArchive>? imageArchive;
private string? sizeInformationText;
private StaticResourceSizeInformation? sizeInformation;
public List<NameValue<StaticResourceQuality>> ImageQualities { get => imageQualities; }
@@ -33,13 +36,18 @@ internal sealed class StaticResourceOptions : ObservableObject
}
}
public bool UseTrimmedArchive
public List<NameValue<StaticResourceArchive>> ImageArchives { get => imageArchives; }
public NameValue<StaticResourceArchive>? ImageArchive
{
get => LocalSetting.Get(SettingKeys.StaticResourceUseTrimmedArchive, false);
get => imageArchive ??= ImageArchives.First(a => a.Value == UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageArchive, StaticResourceArchive.Full));
set
{
LocalSetting.Set(SettingKeys.StaticResourceUseTrimmedArchive, value);
UpdateSizeInformationText();
if (SetProperty(ref imageArchive, value) && value is not null)
{
UnsafeLocalSetting.Set(SettingKeys.StaticResourceImageArchive, value.Value);
UpdateSizeInformationText();
}
}
}
@@ -59,12 +67,12 @@ internal sealed class StaticResourceOptions : ObservableObject
{
if (SizeInformation is not null)
{
long result = (ImageQuality?.Value, minimum: UseTrimmedArchive) switch
long result = (ImageQuality?.Value, ImageArchive?.Value) switch
{
(StaticResourceQuality.Raw, minimum: false) => SizeInformation.RawFull,
(StaticResourceQuality.Raw, minimum: true) => SizeInformation.RawMinimum,
(StaticResourceQuality.High, minimum: false) => SizeInformation.HighFull,
(StaticResourceQuality.High, minimum: true) => SizeInformation.HighMinimum,
(StaticResourceQuality.Raw, StaticResourceArchive.Full) => SizeInformation.RawFull,
(StaticResourceQuality.Raw, StaticResourceArchive.Minimum) => SizeInformation.RawMinimum,
(StaticResourceQuality.High, StaticResourceArchive.Full) => SizeInformation.HighFull,
(StaticResourceQuality.High, StaticResourceArchive.Minimum) => SizeInformation.HighMinimum,
_ => 0,
};