code style

This commit is contained in:
Lightczx
2024-06-04 17:19:45 +08:00
parent f7e53399b4
commit b0fa05283a
68 changed files with 406 additions and 310 deletions

View File

@@ -0,0 +1,45 @@
using System.Drawing;
using System.Net.Http;
using System.Net.Http.Json;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Snap.Hutao.Test.RuntimeBehavior;
[TestClass]
public sealed class HttpClientBehaviorTest
{
private const int MessageNotYetSent = 0;
[TestMethod]
public async Task RetrySendHttpRequestMessage()
{
using (HttpClient httpClient = new())
{
HttpRequestMessage requestMessage = new(HttpMethod.Post, "https://jsonplaceholder.typicode.com/posts");
JsonContent content = JsonContent.Create(new Point(12, 34));
requestMessage.Content = content;
using (requestMessage)
{
await httpClient.SendAsync(requestMessage).ConfigureAwait(false);
}
Interlocked.Exchange(ref GetPrivateSendStatus(requestMessage), MessageNotYetSent);
Volatile.Write(ref GetPrivateDisposed(content), false);
await httpClient.SendAsync(requestMessage).ConfigureAwait(false);
}
}
// private int _sendStatus
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_sendStatus")]
private static extern ref int GetPrivateSendStatus(HttpRequestMessage message);
// private bool _disposed
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_disposed")]
private static extern ref bool GetPrivateDisposed(HttpRequestMessage message);
// private bool _disposed
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_disposed")]
private static extern ref bool GetPrivateDisposed(HttpContent content);
}

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Markup;
namespace Snap.Hutao.Control;
@@ -36,9 +37,18 @@ internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
private static void IsLoadingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Loading control = (Loading)d;
control.presenter ??= control.GetTemplateChild("ContentGrid") as FrameworkElement;
control?.Update();
if ((bool)e.NewValue)
{
control.presenter ??= control.GetTemplateChild("ContentGrid") as FrameworkElement;
}
else if (control.presenter is not null)
{
XamlMarkupHelper.UnloadObject(control.presenter);
control.presenter = null;
}
control.Update();
}
private void Update()

View File

@@ -23,7 +23,8 @@
<ContentPresenter
x:Name="ContentGrid"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
x:Load="False">
<ContentPresenter.RenderTransform>
<CompositeTransform/>
</ContentPresenter.RenderTransform>
@@ -84,4 +85,4 @@
</Setter>
</Style>
</ResourceDictionary>
</ResourceDictionary>

View File

@@ -11,16 +11,13 @@ using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
namespace Snap.Hutao.Core.Caching;
/// <summary>
/// Provides methods and tools to cache files in a folder
/// The class's name will become the cache folder's name
/// </summary>
[HighQuality]
[ConstructorGenerated]
[Injection(InjectAs.Singleton, typeof(IImageCache))]
@@ -28,10 +25,9 @@ namespace Snap.Hutao.Core.Caching;
[PrimaryHttpMessageHandler(MaxConnectionsPerServer = 8)]
internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOperation
{
private const string CacheFolderName = nameof(ImageCache);
private const string CacheFailedDownloadTasksName = $"{nameof(ImageCache)}.FailedDownloadTasks";
private readonly FrozenDictionary<int, TimeSpan> retryCountToDelay = FrozenDictionary.ToFrozenDictionary(
private static readonly FrozenDictionary<int, TimeSpan> DelayFromRetryCount = FrozenDictionary.ToFrozenDictionary(
[
KeyValuePair.Create(0, TimeSpan.FromSeconds(4)),
KeyValuePair.Create(1, TimeSpan.FromSeconds(16)),
@@ -46,16 +42,13 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
private readonly ILogger<ImageCache> logger;
private readonly IMemoryCache memoryCache;
private string? baseFolder;
private string? cacheFolder;
private string CacheFolder
{
get => LazyInitializer.EnsureInitialized(ref cacheFolder, () =>
{
baseFolder ??= serviceProvider.GetRequiredService<RuntimeOptions>().LocalCache;
DirectoryInfo info = Directory.CreateDirectory(Path.Combine(baseFolder, CacheFolderName));
return info.FullName;
return serviceProvider.GetRequiredService<RuntimeOptions>().GetLocalCacheImageCacheFolder();
});
}
@@ -149,8 +142,7 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
return treatNullFileAsInvalid;
}
FileInfo fileInfo = new(file);
return fileInfo.Length == 0;
return new FileInfo(file).Length == 0;
}
private void RemoveCore(IEnumerable<string> filePaths)
@@ -172,80 +164,76 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
[SuppressMessage("", "SH003")]
private async Task DownloadFileAsync(Uri uri, string baseFile)
{
int retryCount = 0;
HttpClient httpClient = httpClientFactory.CreateClient(nameof(ImageCache));
while (retryCount < 3)
using (HttpClient httpClient = httpClientFactory.CreateClient(nameof(ImageCache)))
{
int retryCount = 0;
HttpRequestMessageBuilder requestMessageBuilder = httpRequestMessageBuilderFactory
.Create()
.SetRequestUri(uri)
// These headers are only available for our own api
.SetStaticResourceControlHeadersIf(uri.Host.Contains("api.snapgenshin.com", StringComparison.OrdinalIgnoreCase))
.SetStaticResourceControlHeadersIf(uri.Host.Contains("api.snapgenshin.com", StringComparison.OrdinalIgnoreCase)) // These headers are only available for our own api
.Get();
using (HttpRequestMessage requestMessage = requestMessageBuilder.HttpRequestMessage)
while (retryCount < 3)
{
using (HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
if (responseMessage.RequestMessage is { RequestUri: { } target } && target != uri)
{
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
}
requestMessageBuilder.Resurrect();
if (responseMessage.IsSuccessStatusCode)
using (HttpRequestMessage requestMessage = requestMessageBuilder.HttpRequestMessage)
{
using (HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
if (responseMessage.Content.Headers.ContentType?.MediaType is "application/json")
// Redirect detection
if (responseMessage.RequestMessage is { RequestUri: { } target } && target != uri)
{
#if DEBUG
DebugTrack(uri);
#endif
string raw = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
logger.LogColorizedCritical("Failed to download '{Uri}' with unexpected body '{Raw}'", (uri, ConsoleColor.Red), (raw, ConsoleColor.DarkYellow));
return;
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
}
using (Stream httpStream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false))
if (responseMessage.IsSuccessStatusCode)
{
using (FileStream fileStream = File.Create(baseFile))
if (responseMessage.Content.Headers.ContentType?.MediaType is "application/json")
{
await httpStream.CopyToAsync(fileStream).ConfigureAwait(false);
DebugTrackFailedUri(uri);
string raw = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
logger.LogColorizedCritical("Failed to download '{Uri}' with unexpected body '{Raw}'", (uri, ConsoleColor.Red), (raw, ConsoleColor.DarkYellow));
return;
}
}
}
switch (responseMessage.StatusCode)
{
case HttpStatusCode.TooManyRequests:
using (Stream httpStream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false))
{
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;
using (FileStream fileStream = File.Create(baseFile))
{
await httpStream.CopyToAsync(fileStream).ConfigureAwait(false);
return;
}
}
}
default:
#if DEBUG
DebugTrack(uri);
#endif
logger.LogColorizedCritical("Failed to download '{Uri}' with status code '{StatusCode}'", (uri, ConsoleColor.Red), (responseMessage.StatusCode, ConsoleColor.DarkYellow));
return;
switch (responseMessage.StatusCode)
{
case HttpStatusCode.TooManyRequests:
{
retryCount++;
TimeSpan delay = responseMessage.Headers.RetryAfter?.Delta ?? DelayFromRetryCount[retryCount];
logger.LogInformation("Retry download '{Uri}' after {Delay}.", uri, delay);
await Task.Delay(delay).ConfigureAwait(false);
break;
}
default:
DebugTrackFailedUri(uri);
logger.LogColorizedCritical("Failed to download '{Uri}' with status code '{StatusCode}'", (uri, ConsoleColor.Red), (responseMessage.StatusCode, ConsoleColor.DarkYellow));
return;
}
}
}
}
}
}
}
#if DEBUG
internal partial class ImageCache
{
private void DebugTrack(Uri uri)
[Conditional("DEBUG")]
private void DebugTrackFailedUri(Uri uri)
{
HashSet<string>? set = memoryCache.GetOrCreate(CacheFailedDownloadTasksName, entry => entry.Value ??= new HashSet<string>()) as HashSet<string>;
HashSet<string>? set = memoryCache.GetOrCreate(CacheFailedDownloadTasksName, entry => new HashSet<string>());
set?.Add(uri.ToString());
}
}
#endif
}

View File

@@ -70,7 +70,7 @@ internal sealed class ObservableReorderableDbCollection<TEntity> : ObservableCol
[SuppressMessage("", "SA1402")]
internal sealed class ObservableReorderableDbCollection<TEntityOnly, TEntity> : ObservableCollection<TEntityOnly>
where TEntityOnly : class, IEntityOnly<TEntity>
where TEntityOnly : class, IEntityAccess<TEntity>
where TEntity : class, IReorderable
{
private readonly IServiceProvider serviceProvider;

View File

@@ -73,7 +73,7 @@ internal sealed partial class ScopedDbCurrent<TEntity, TMessage>
[ConstructorGenerated]
internal sealed partial class ScopedDbCurrent<TEntityOnly, TEntity, TMessage>
where TEntityOnly : class, IEntityOnly<TEntity>
where TEntityOnly : class, IEntityAccess<TEntity>
where TEntity : class, ISelectable
where TMessage : Message.ValueChangedMessage<TEntityOnly>, new()
{

View File

@@ -41,7 +41,7 @@ internal static class DependencyInjection
.AddJsonOptions()
.AddDatabase()
.AddInjections()
.AddAllHttpClients()
.AddConfiguredHttpClients()
// Discrete services
.AddSingleton<IMessenger, WeakReferenceMessenger>()

View File

@@ -34,27 +34,27 @@ internal static class IocConfiguration
.AddTransient(typeof(Database.ScopedDbCurrent<,>))
.AddTransient(typeof(Database.ScopedDbCurrent<,,>))
.AddDbContextPool<AppDbContext>(AddDbContextCore);
}
private static void AddDbContextCore(IServiceProvider serviceProvider, DbContextOptionsBuilder builder)
{
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
string dbFile = System.IO.Path.Combine(runtimeOptions.DataFolder, "Userdata.db");
string sqlConnectionString = $"Data Source={dbFile}";
// Temporarily create a context
using (AppDbContext context = AppDbContext.Create(serviceProvider, sqlConnectionString))
static void AddDbContextCore(IServiceProvider serviceProvider, DbContextOptionsBuilder builder)
{
if (context.Database.GetPendingMigrations().Any())
{
System.Diagnostics.Debug.WriteLine("[Database] Performing AppDbContext Migrations");
context.Database.Migrate();
}
}
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
string dbFile = System.IO.Path.Combine(runtimeOptions.DataFolder, "Userdata.db");
string sqlConnectionString = $"Data Source={dbFile}";
builder
.EnableSensitiveDataLogging()
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.UseSqlite(sqlConnectionString);
// Temporarily create a context
using (AppDbContext context = AppDbContext.Create(serviceProvider, sqlConnectionString))
{
if (context.Database.GetPendingMigrations().Any())
{
System.Diagnostics.Debug.WriteLine("[Database] Performing AppDbContext Migrations");
context.Database.Migrate();
}
}
builder
.EnableSensitiveDataLogging()
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.UseSqlite(sqlConnectionString);
}
}
}

View File

@@ -15,7 +15,7 @@ internal static partial class IocHttpClientConfiguration
{
private const string ApplicationJson = "application/json";
public static IServiceCollection AddAllHttpClients(this IServiceCollection services)
public static IServiceCollection AddConfiguredHttpClients(this IServiceCollection services)
{
services
.ConfigureHttpClientDefaults(clientBuilder =>
@@ -27,7 +27,7 @@ internal static partial class IocHttpClientConfiguration
HttpClientHandler clientHandler = (HttpClientHandler)handler;
clientHandler.AllowAutoRedirect = true;
clientHandler.UseProxy = true;
clientHandler.Proxy = provider.GetRequiredService<DynamicHttpProxy>();
clientHandler.Proxy = provider.GetRequiredService<HttpProxyUsingSystemProxy>();
});
})
.AddHttpClients();

View File

@@ -1,22 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Core.ExceptionService;
/// <summary>
/// 帮助更好的抛出异常
/// </summary>
[HighQuality]
[System.Diagnostics.StackTraceHidden]
[Obsolete("Use HutaoException instead")]
internal static class ThrowHelper
{
[DoesNotReturn]
[MethodImpl(MethodImplOptions.NoInlining)]
public static ArgumentException Argument(string message, string? paramName)
{
throw new ArgumentException(message, paramName);
}
}

View File

@@ -2,7 +2,12 @@
// Licensed under the MIT license.
using Microsoft.VisualBasic.FileIO;
using Snap.Hutao.Win32.System.Com;
using Snap.Hutao.Win32.UI.Shell;
using System.IO;
using static Snap.Hutao.Win32.Macros;
using static Snap.Hutao.Win32.Ole32;
using static Snap.Hutao.Win32.Shell32;
namespace Snap.Hutao.Core.IO;
@@ -18,4 +23,29 @@ internal static class DirectoryOperation
FileSystem.MoveDirectory(sourceDirName, destDirName, true);
return true;
}
public static unsafe bool UnsafeRename(string path, string name, FILEOPERATION_FLAGS flags = FILEOPERATION_FLAGS.FOF_ALLOWUNDO | FILEOPERATION_FLAGS.FOF_NOCONFIRMMKDIR)
{
bool result = false;
if (SUCCEEDED(CoCreateInstance(in Win32.UI.Shell.FileOperation.CLSID, default, CLSCTX.CLSCTX_INPROC_SERVER, in IFileOperation.IID, out IFileOperation* pFileOperation)))
{
if (SUCCEEDED(SHCreateItemFromParsingName(path, default, in IShellItem.IID, out IShellItem* pShellItem)))
{
pFileOperation->SetOperationFlags(flags);
pFileOperation->RenameItem(pShellItem, name, default);
if (SUCCEEDED(pFileOperation->PerformOperations()))
{
result = true;
}
IUnknownMarshal.Release(pShellItem);
}
IUnknownMarshal.Release(pFileOperation);
}
return result;
}
}

View File

@@ -45,6 +45,30 @@ internal static class FileOperation
return true;
}
public static unsafe bool UnsafeDelete(string path)
{
bool result = false;
if (SUCCEEDED(CoCreateInstance(in Win32.UI.Shell.FileOperation.CLSID, default, CLSCTX.CLSCTX_INPROC_SERVER, in IFileOperation.IID, out IFileOperation* pFileOperation)))
{
if (SUCCEEDED(SHCreateItemFromParsingName(path, default, in IShellItem.IID, out IShellItem* pShellItem)))
{
pFileOperation->DeleteItem(pShellItem, default);
if (SUCCEEDED(pFileOperation->PerformOperations()))
{
result = true;
}
IUnknownMarshal.Release(pShellItem);
}
IUnknownMarshal.Release(pFileOperation);
}
return result;
}
public static unsafe bool UnsafeMove(string sourceFileName, string destFileName)
{
bool result = false;
@@ -73,28 +97,4 @@ internal static class FileOperation
return result;
}
public static unsafe bool UnsafeDelete(string path)
{
bool result = false;
if (SUCCEEDED(CoCreateInstance(in Win32.UI.Shell.FileOperation.CLSID, default, CLSCTX.CLSCTX_INPROC_SERVER, in IFileOperation.IID, out IFileOperation* pFileOperation)))
{
if (SUCCEEDED(SHCreateItemFromParsingName(path, default, in IShellItem.IID, out IShellItem* pShellItem)))
{
pFileOperation->DeleteItem(pShellItem, default);
if (SUCCEEDED(pFileOperation->PerformOperations()))
{
result = true;
}
IUnknownMarshal.Release(pShellItem);
}
IUnknownMarshal.Release(pFileOperation);
}
return result;
}
}

View File

@@ -6,6 +6,9 @@ using System.Text;
namespace Snap.Hutao.Core.IO.Hashing;
#if NET9_0_OR_GREATER
[Obsolete]
#endif
internal static class Hash
{
public static unsafe string SHA1HexString(string input)

View File

@@ -3,13 +3,14 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Win32.Registry;
using System.Linq.Expressions;
using System.Net;
using System.Reflection;
namespace Snap.Hutao.Core.IO.Http.Proxy;
[Injection(InjectAs.Singleton)]
internal sealed partial class DynamicHttpProxy : ObservableObject, IWebProxy, IDisposable
internal sealed partial class HttpProxyUsingSystemProxy : ObservableObject, IWebProxy, IDisposable
{
private const string ProxySettingPath = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections";
@@ -20,7 +21,7 @@ internal sealed partial class DynamicHttpProxy : ObservableObject, IWebProxy, ID
private IWebProxy innerProxy = default!;
public DynamicHttpProxy(IServiceProvider serviceProvider)
public HttpProxyUsingSystemProxy(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
UpdateInnerProxy();

View File

@@ -27,4 +27,11 @@ internal static class RuntimeOptionsExtension
Directory.CreateDirectory(directory);
return directory;
}
public static string GetLocalCacheImageCacheFolder(this RuntimeOptions options)
{
string directory = Path.Combine(options.LocalCache, "ImageCache");
Directory.CreateDirectory(directory);
return directory;
}
}

View File

@@ -67,7 +67,7 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
IUnknownMarshal.Release(pPersistFile);
}
uint value = IUnknownMarshal.Release(pShellLink);
IUnknownMarshal.Release(pShellLink);
}
return result;

View File

@@ -1,19 +1,18 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.CompilerServices;
using Windows.Graphics;
namespace Snap.Hutao.Core.Windowing;
internal readonly struct CompactRect
internal readonly struct RectInt16
{
private readonly short x;
private readonly short y;
private readonly short width;
private readonly short height;
private CompactRect(int x, int y, int width, int height)
private RectInt16(int x, int y, int width, int height)
{
this.x = (short)x;
this.y = (short)y;
@@ -21,24 +20,22 @@ internal readonly struct CompactRect
this.height = (short)height;
}
public static implicit operator RectInt32(CompactRect rect)
public static implicit operator RectInt32(RectInt16 rect)
{
return new(rect.x, rect.y, rect.width, rect.height);
}
public static explicit operator CompactRect(RectInt32 rect)
public static explicit operator RectInt16(RectInt32 rect)
{
return new(rect.X, rect.Y, rect.Width, rect.Height);
}
public static unsafe explicit operator CompactRect(ulong value)
public static unsafe explicit operator RectInt16(ulong value)
{
Unsafe.SkipInit(out CompactRect rect);
*(ulong*)&rect = value;
return rect;
return *(RectInt16*)&value;
}
public static unsafe implicit operator ulong(CompactRect rect)
public static unsafe implicit operator ulong(RectInt16 rect)
{
return *(ulong*)&rect;
}

View File

@@ -241,7 +241,7 @@ internal sealed class XamlWindowController
if (window is IXamlWindowRectPersisted rectPersisted)
{
RectInt32 nonDpiPersistedRect = (CompactRect)LocalSetting.Get(rectPersisted.PersistRectKey, (CompactRect)rect);
RectInt32 nonDpiPersistedRect = (RectInt16)LocalSetting.Get(rectPersisted.PersistRectKey, (RectInt16)rect);
RectInt32 persistedRect = nonDpiPersistedRect.Scale(scale);
// If the persisted size is less than min size, we want to reset to the init size.
@@ -266,7 +266,7 @@ internal sealed class XamlWindowController
{
// We save the non-dpi rect here
double scale = 1.0 / window.GetRasterizationScale();
LocalSetting.Set(rectPersisted.PersistRectKey, (CompactRect)window.AppWindow.GetRect().Scale(scale));
LocalSetting.Set(rectPersisted.PersistRectKey, (RectInt16)window.AppWindow.GetRect().Scale(scale));
}
}
#endregion

View File

@@ -104,7 +104,7 @@ internal static partial class EnumerableExtension
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ObservableReorderableDbCollection<TEntityOnly, TEntity> ToObservableReorderableDbCollection<TEntityOnly, TEntity>(this IEnumerable<TEntityOnly> source, IServiceProvider serviceProvider)
where TEntityOnly : class, IEntityOnly<TEntity>
where TEntityOnly : class, IEntityAccess<TEntity>
where TEntity : class, IReorderable
{
return source is List<TEntityOnly> list

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model;
internal interface IEntityAccessWithMetadata<out TEntity, out TMetadata> : IEntityAccess<TEntity>
{
TMetadata Inner { get; }
}
internal interface IEntityAccess<out TEntity>
{
TEntity Entity { get; }
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model;
/// <summary>
/// 实体与元数据
/// </summary>
/// <typeparam name="TEntity">实体</typeparam>
/// <typeparam name="TMetadata">元数据</typeparam>
[HighQuality]
internal interface IEntityWithMetadata<out TEntity, out TMetadata> : IEntityOnly<TEntity>
{
/// <summary>
/// 元数据
/// </summary>
TMetadata Inner { get; }
}
internal interface IEntityOnly<out TEntity>
{
/// <summary>
/// 实体
/// </summary>
TEntity Entity { get; }
}

View File

@@ -82,31 +82,10 @@ internal abstract partial class DbStoreOptions : ObservableObject
return storage.Value;
}
[return: NotNull]
protected T GetOption<T>(ref T? storage, string key, Func<string, T> deserializer, [DisallowNull] T defaultValue)
[return: NotNullIfNotNull(nameof(defaultValue))]
protected T GetOption<T>(ref T? storage, string key, Func<string, T> deserializer, T defaultValue)
{
if (storage is not null)
{
return storage;
}
using (IServiceScope scope = serviceProvider.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == key)?.Value;
if (value is null)
{
storage = defaultValue;
}
else
{
T targetValue = deserializer(value);
ArgumentNullException.ThrowIfNull(targetValue);
storage = targetValue;
}
}
return storage;
return GetOption(ref storage, key, deserializer, () => defaultValue);
}
protected T GetOption<T>(ref T? storage, string key, Func<string, T> deserializer, Func<T> defaultValueFactory)

View File

@@ -32,6 +32,6 @@ internal sealed partial class DailyNoteWebhookOperation
.SetHeader("x-uid", $"{playerUid}")
.PostJson(dailyNote);
await builder.TryCatchSendAsync(httpClient, logger, token).ConfigureAwait(false);
await builder.SendAsync(httpClient, logger, token).ConfigureAwait(false);
}
}

View File

@@ -80,7 +80,6 @@ internal static class DirectX
return false;
}
//IUnknownMarshal.Release(swapChain);
return true;
}
}

View File

@@ -122,7 +122,8 @@ internal sealed class GameScreenCaptureSession : IDisposable
try
{
captureContext.UpdatePreview(previewWindow, frame.Surface);
//UnsafeProcessFrameSurface(frame.Surface);
// UnsafeProcessFrameSurface(frame.Surface);
}
catch (Exception ex)
{

View File

@@ -49,7 +49,7 @@ internal sealed partial class LoginHoyoverseUserPage : Microsoft.UI.Xaml.Control
HttpClient httpClient = serviceProvider.GetRequiredService<HttpClient>();
WebApiResponse<AccountInfoWrapper>? resp = await builder
.TryCatchSendAsync<WebApiResponse<AccountInfoWrapper>>(httpClient, logger, token)
.SendAsync<WebApiResponse<AccountInfoWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return $"{resp?.Data?.AccountInfo?.AccountId}";

View File

@@ -124,6 +124,11 @@
Header="Screen Capture Test"
IsClickEnabled="True"/>
<cwc:SettingsCard
Command="{Binding FileOperationRenameCommand}"
Header="Rename Desktop TestFolder"
IsClickEnabled="True"/>
<cwc:SettingsCard Header="Crash">
<StackPanel Orientation="Horizontal">
<Button Command="{Binding ExceptionCommand}" Content="Activate"/>

View File

@@ -11,7 +11,7 @@ namespace Snap.Hutao.ViewModel.Achievement;
/// 用于视图绑定的成就
/// </summary>
[HighQuality]
internal sealed class AchievementView : ObservableObject, IEntityWithMetadata<Model.Entity.Achievement, Model.Metadata.Achievement.Achievement>
internal sealed class AchievementView : ObservableObject, IEntityAccessWithMetadata<Model.Entity.Achievement, Model.Metadata.Achievement.Achievement>
{
/// <summary>
/// 满进度占位符

View File

@@ -11,7 +11,7 @@ namespace Snap.Hutao.ViewModel.Cultivation;
/// 养成物品
/// </summary>
[HighQuality]
internal sealed class CultivateItemView : ObservableObject, IEntityWithMetadata<Model.Entity.CultivateItem, Material>
internal sealed class CultivateItemView : ObservableObject, IEntityAccessWithMetadata<Model.Entity.CultivateItem, Material>
{
/// <summary>
/// 养成物品

View File

@@ -11,7 +11,7 @@ namespace Snap.Hutao.ViewModel.Cultivation;
/// 背包物品
/// </summary>
[HighQuality]
internal sealed class InventoryItemView : ObservableObject, IEntityWithMetadata<Model.Entity.InventoryItem, Material>
internal sealed class InventoryItemView : ObservableObject, IEntityAccessWithMetadata<Model.Entity.InventoryItem, Material>
{
/// <summary>
/// 创建一个新的背包物品

View File

@@ -25,7 +25,7 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel
private readonly HutaoDocumentationClient hutaoDocumentationClient;
private readonly IContentDialogFactory contentDialogFactory;
private readonly IClipboardProvider clipboardProvider;
private readonly DynamicHttpProxy dynamicHttpProxy;
private readonly HttpProxyUsingSystemProxy dynamicHttpProxy;
private readonly LoopbackManager loopbackManager;
private readonly IInfoBarService infoBarService;
private readonly CultureOptions cultureOptions;
@@ -38,7 +38,7 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel
public RuntimeOptions RuntimeOptions { get => runtimeOptions; }
public DynamicHttpProxy DynamicHttpProxy { get => dynamicHttpProxy; }
public HttpProxyUsingSystemProxy DynamicHttpProxy { get => dynamicHttpProxy; }
public LoopbackManager LoopbackManager { get => loopbackManager; }

View File

@@ -12,7 +12,7 @@ namespace Snap.Hutao.ViewModel.SpiralAbyss;
/// 深渊视图
/// </summary>
[HighQuality]
internal sealed class SpiralAbyssView : IEntityOnly<SpiralAbyssEntry?>,
internal sealed class SpiralAbyssView : IEntityAccess<SpiralAbyssEntry?>,
IMappingFrom<SpiralAbyssView, SpiralAbyssEntry, SpiralAbyssMetadataContext>,
IMappingFrom<SpiralAbyssView, SpiralAbyssEntry?, TowerSchedule, SpiralAbyssMetadataContext>
{

View File

@@ -4,6 +4,7 @@
using Microsoft.Extensions.Caching.Memory;
using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.IO;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Core.Windowing;
@@ -13,6 +14,7 @@ using Snap.Hutao.View.Converter;
using Snap.Hutao.ViewModel.Guide;
using Snap.Hutao.Web.Hutao.HutaoAsAService;
using Snap.Hutao.Win32.Foundation;
using System.IO;
namespace Snap.Hutao.ViewModel;
@@ -163,4 +165,12 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
}
}
}
[Command("FileOperationRenameCommand")]
private void FileOperationRename()
{
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string source = Path.Combine(desktop, "TestFolder");
DirectoryOperation.UnsafeRename(source, "TestFolder1");
}
}

View File

@@ -18,7 +18,7 @@ namespace Snap.Hutao.ViewModel.User;
/// 用于视图绑定的用户
/// </summary>
[HighQuality]
internal sealed class User : ObservableObject, IEntityOnly<EntityUser>, IMappingFrom<User, EntityUser, IServiceProvider>, ISelectable
internal sealed class User : ObservableObject, IEntityAccess<EntityUser>, IMappingFrom<User, EntityUser, IServiceProvider>, ISelectable
{
private readonly EntityUser inner;
private readonly IServiceProvider serviceProvider;

View File

@@ -32,7 +32,7 @@ internal sealed partial class AccountClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.K2, false).ConfigureAwait(false);
Response<GameAuthKey>? resp = await builder
.TryCatchSendAsync<Response<GameAuthKey>>(httpClient, logger, token)
.SendAsync<Response<GameAuthKey>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -28,7 +28,7 @@ internal sealed partial class UserClient : IUserClient
.Get();
Response<UserFullInfoWrapper>? resp = await builder
.TryCatchSendAsync<Response<UserFullInfoWrapper>>(httpClient, logger, token)
.SendAsync<Response<UserFullInfoWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -27,7 +27,7 @@ internal sealed partial class UserClientOversea : IUserClient
.Get();
Response<UserFullInfoWrapper>? resp = await builder
.TryCatchSendAsync<Response<UserFullInfoWrapper>>(httpClient, logger, token)
.SendAsync<Response<UserFullInfoWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -38,7 +38,7 @@ internal sealed partial class AnnouncementClient
.Get();
Response<AnnouncementWrapper>? resp = await builder
.TryCatchSendAsync<Response<AnnouncementWrapper>>(httpClient, logger, token)
.SendAsync<Response<AnnouncementWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -62,7 +62,7 @@ internal sealed partial class AnnouncementClient
.Get();
Response<ListWrapper<AnnouncementContent>>? resp = await builder
.TryCatchSendAsync<Response<ListWrapper<AnnouncementContent>>>(httpClient, logger, token)
.SendAsync<Response<ListWrapper<AnnouncementContent>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -40,7 +40,7 @@ internal sealed partial class GachaInfoClient
.Get();
Response<GachaLogPage>? resp = await builder
.TryCatchSendAsync<Response<GachaLogPage>>(httpClient, logger, token)
.SendAsync<Response<GachaLogPage>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -26,7 +26,7 @@ internal sealed partial class PandaClient
.PostJson(options);
Response<UrlWrapper>? resp = await builder
.TryCatchSendAsync<Response<UrlWrapper>>(httpClient, logger, token)
.SendAsync<Response<UrlWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -41,7 +41,7 @@ internal sealed partial class PandaClient
.PostJson(options);
Response<GameLoginResult>? resp = await builder
.TryCatchSendAsync<Response<GameLoginResult>>(httpClient, logger, token)
.SendAsync<Response<GameLoginResult>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -30,7 +30,7 @@ internal sealed partial class PassportClient : IPassportClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.PROD, true).ConfigureAwait(false);
Response<UidCookieToken>? resp = await builder
.TryCatchSendAsync<Response<UidCookieToken>>(httpClient, logger, token)
.SendAsync<Response<UidCookieToken>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -46,7 +46,7 @@ internal sealed partial class PassportClient : IPassportClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.PROD, true).ConfigureAwait(false);
Response<LTokenWrapper>? resp = await builder
.TryCatchSendAsync<Response<LTokenWrapper>>(httpClient, logger, token)
.SendAsync<Response<LTokenWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -29,7 +29,7 @@ internal sealed partial class PassportClient2
.PostJson(new Timestamp());
Response<UserInfoWrapper>? resp = await builder
.TryCatchSendAsync<Response<UserInfoWrapper>>(httpClient, logger, token)
.SendAsync<Response<UserInfoWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -45,7 +45,7 @@ internal sealed partial class PassportClient2
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.PROD, true).ConfigureAwait(false);
Response<LoginResult>? resp = await builder
.TryCatchSendAsync<Response<LoginResult>>(httpClient, logger, token)
.SendAsync<Response<LoginResult>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -64,7 +64,7 @@ internal sealed partial class PassportClient2
.PostJson(data);
Response<LoginResult>? resp = await builder
.TryCatchSendAsync<Response<LoginResult>>(httpClient, logger, token)
.SendAsync<Response<LoginResult>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -31,7 +31,7 @@ internal sealed partial class PassportClientOversea : IPassportClient
.PostJson(data);
Response<UidCookieToken>? resp = await builder
.TryCatchSendAsync<Response<UidCookieToken>>(httpClient, logger, token)
.SendAsync<Response<UidCookieToken>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -50,7 +50,7 @@ internal sealed partial class PassportClientOversea : IPassportClient
.PostJson(data);
Response<LTokenWrapper>? resp = await builder
.TryCatchSendAsync<Response<LTokenWrapper>>(httpClient, logger, token)
.SendAsync<Response<LTokenWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -24,7 +24,7 @@ internal sealed partial class DeviceFpClient
.PostJson(data);
Response<DeviceFpWrapper>? resp = await builder
.TryCatchSendAsync<Response<DeviceFpWrapper>>(httpClient, logger, token)
.SendAsync<Response<DeviceFpWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -41,7 +41,7 @@ internal sealed partial class ResourceClient
.Get();
Response<GameResource>? resp = await builder
.TryCatchSendAsync<Response<GameResource>>(httpClient, logger, token)
.SendAsync<Response<GameResource>>(httpClient, logger, token)
.ConfigureAwait(false);
// 最新版完整包
@@ -70,7 +70,7 @@ internal sealed partial class ResourceClient
.Get();
Response<GameContent>? resp = await builder
.TryCatchSendAsync<Response<GameContent>>(httpClient, logger, token)
.SendAsync<Response<GameContent>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -34,7 +34,7 @@ internal sealed partial class AuthClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.K2, true).ConfigureAwait(false);
Response<ActionTicketWrapper>? resp = await builder
.TryCatchSendAsync<Response<ActionTicketWrapper>>(httpClient, logger, token)
.SendAsync<Response<ActionTicketWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -57,7 +57,7 @@ internal sealed partial class AuthClient
.Get();
resp = await builder
.TryCatchSendAsync<Response<ListWrapper<NameToken>>>(httpClient, logger, token)
.SendAsync<Response<ListWrapper<NameToken>>>(httpClient, logger, token)
.ConfigureAwait(false);
}

View File

@@ -52,7 +52,7 @@ internal sealed partial class BindingClient
.Get();
Response<ListWrapper<UserGameRole>>? resp = await builder
.TryCatchSendAsync<Response<ListWrapper<UserGameRole>>>(httpClient, logger, token)
.SendAsync<Response<ListWrapper<UserGameRole>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -66,7 +66,7 @@ internal sealed partial class BindingClient
.Get();
Response<ListWrapper<UserGameRole>>? resp = await builder
.TryCatchSendAsync<Response<ListWrapper<UserGameRole>>>(httpClient, logger, token)
.SendAsync<Response<ListWrapper<UserGameRole>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -32,7 +32,7 @@ internal sealed partial class BindingClient2
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
Response<ListWrapper<UserGameRole>>? resp = await builder
.TryCatchSendAsync<Response<ListWrapper<UserGameRole>>>(httpClient, logger, token)
.SendAsync<Response<ListWrapper<UserGameRole>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -49,7 +49,7 @@ internal sealed partial class BindingClient2
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
Response<GameAuthKey>? resp = await builder
.TryCatchSendAsync<Response<GameAuthKey>>(httpClient, logger, token)
.SendAsync<Response<GameAuthKey>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -38,7 +38,7 @@ internal sealed partial class SignInClient : ISignInClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
Response<ExtraAwardInfo>? resp = await builder
.TryCatchSendAsync<Response<ExtraAwardInfo>>(httpClient, logger, token)
.SendAsync<Response<ExtraAwardInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -55,7 +55,7 @@ internal sealed partial class SignInClient : ISignInClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
Response<SignInRewardInfo>? resp = await builder
.TryCatchSendAsync<Response<SignInRewardInfo>>(httpClient, logger, token)
.SendAsync<Response<SignInRewardInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -72,7 +72,7 @@ internal sealed partial class SignInClient : ISignInClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
Response<SignInRewardReSignInfo>? resp = await builder
.TryCatchSendAsync<Response<SignInRewardReSignInfo>>(httpClient, logger, token)
.SendAsync<Response<SignInRewardReSignInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -87,7 +87,7 @@ internal sealed partial class SignInClient : ISignInClient
.Get();
Response<Reward>? resp = await builder
.TryCatchSendAsync<Response<Reward>>(httpClient, logger, token)
.SendAsync<Response<Reward>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -104,7 +104,7 @@ internal sealed partial class SignInClient : ISignInClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
Response<SignInResult>? resp = await builder
.TryCatchSendAsync<Response<SignInResult>>(httpClient, logger, token)
.SendAsync<Response<SignInResult>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -121,7 +121,7 @@ internal sealed partial class SignInClient : ISignInClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
Response<SignInResult>? resp = await builder
.TryCatchSendAsync<Response<SignInResult>>(httpClient, logger, token)
.SendAsync<Response<SignInResult>>(httpClient, logger, token)
.ConfigureAwait(false);
if (resp is { Data: { Success: 1, Gt: string gt, Challenge: string originChallenge } })
@@ -140,7 +140,7 @@ internal sealed partial class SignInClient : ISignInClient
await verifiedBuilder.SignDataAsync(DataSignAlgorithmVersion.Gen1, SaltType.LK2, true).ConfigureAwait(false);
resp = await verifiedBuilder
.TryCatchSendAsync<Response<SignInResult>>(httpClient, logger, token)
.SendAsync<Response<SignInResult>>(httpClient, logger, token)
.ConfigureAwait(false);
}
else

View File

@@ -32,7 +32,7 @@ internal sealed partial class SignInClientOversea : ISignInClient
.Get();
Response<SignInRewardInfo>? resp = await builder
.TryCatchSendAsync<Response<SignInRewardInfo>>(httpClient, logger, token)
.SendAsync<Response<SignInRewardInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -46,7 +46,7 @@ internal sealed partial class SignInClientOversea : ISignInClient
.Get();
Response<Reward>? resp = await builder
.TryCatchSendAsync<Response<Reward>>(httpClient, logger, token)
.SendAsync<Response<Reward>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -60,7 +60,7 @@ internal sealed partial class SignInClientOversea : ISignInClient
.PostJson(new SignInData(userAndUid.Uid, true));
Response<SignInResult>? resp = await builder
.TryCatchSendAsync<Response<SignInResult>>(httpClient, logger, token)
.SendAsync<Response<SignInResult>>(httpClient, logger, token)
.ConfigureAwait(false);
if (resp is { Data: { Success: 1, Gt: string gt, Challenge: string originChallenge } })
@@ -76,7 +76,7 @@ internal sealed partial class SignInClientOversea : ISignInClient
.PostJson(new SignInData(userAndUid.Uid, true));
resp = await verifiedBuilder
.TryCatchSendAsync<Response<SignInResult>>(httpClient, logger, token)
.SendAsync<Response<SignInResult>>(httpClient, logger, token)
.ConfigureAwait(false);
}
else

View File

@@ -28,7 +28,7 @@ internal sealed partial class CalculateClient
.PostJson(delta);
Response<Consumption>? resp = await builder
.TryCatchSendAsync<Response<Consumption>>(httpClient, logger, token)
.SendAsync<Response<Consumption>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -52,7 +52,7 @@ internal sealed partial class CalculateClient
.PostJson(data);
Response<BatchConsumption>? resp = await builder
.TryCatchSendAsync<Response<BatchConsumption>>(httpClient, logger, token)
.SendAsync<Response<BatchConsumption>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -77,7 +77,7 @@ internal sealed partial class CalculateClient
.PostJson(filter);
resp = await builder
.TryCatchSendAsync<Response<ListWrapper<Avatar>>>(httpClient, logger, token)
.SendAsync<Response<ListWrapper<Avatar>>>(httpClient, logger, token)
.ConfigureAwait(false);
if (resp is not null && resp.IsOk())
@@ -110,7 +110,7 @@ internal sealed partial class CalculateClient
.Get();
Response<AvatarDetail>? resp = await builder
.TryCatchSendAsync<Response<AvatarDetail>>(httpClient, logger, token)
.SendAsync<Response<AvatarDetail>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -125,7 +125,7 @@ internal sealed partial class CalculateClient
.Get();
Response<FurnitureListWrapper>? resp = await builder
.TryCatchSendAsync<Response<FurnitureListWrapper>>(httpClient, logger, token)
.SendAsync<Response<FurnitureListWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -142,7 +142,7 @@ internal sealed partial class CalculateClient
.PostJson(data);
Response<ListWrapper<Item>>? resp = await builder
.TryCatchSendAsync<Response<ListWrapper<Item>>>(httpClient, logger, token)
.SendAsync<Response<ListWrapper<Item>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -33,7 +33,7 @@ internal sealed partial class CardClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
Response<VerificationRegistration>? resp = await builder
.TryCatchSendAsync<Response<VerificationRegistration>>(httpClient, logger, token)
.SendAsync<Response<VerificationRegistration>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -51,7 +51,7 @@ internal sealed partial class CardClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
Response<VerificationResult>? resp = await builder
.TryCatchSendAsync<Response<VerificationResult>>(httpClient, logger, token)
.SendAsync<Response<VerificationResult>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -67,7 +67,7 @@ internal sealed partial class CardClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X6, false).ConfigureAwait(false);
Response<DailyNote.WidgetDailyNote>? resp = await builder
.TryCatchSendAsync<Response<DailyNote.WidgetDailyNote>>(httpClient, logger, token)
.SendAsync<Response<DailyNote.WidgetDailyNote>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -35,7 +35,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
Response<DailyNote.DailyNote>? resp = await builder
.TryCatchSendAsync<Response<DailyNote.DailyNote>>(httpClient, logger, token)
.SendAsync<Response<DailyNote.DailyNote>>(httpClient, logger, token)
.ConfigureAwait(false);
// We have a verification procedure to handle
@@ -59,7 +59,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await verifiedbuilder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
resp = await verifiedbuilder
.TryCatchSendAsync<Response<DailyNote.DailyNote>>(httpClient, logger, token)
.SendAsync<Response<DailyNote.DailyNote>>(httpClient, logger, token)
.ConfigureAwait(false);
}
}
@@ -78,7 +78,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
Response<PlayerInfo>? resp = await builder
.TryCatchSendAsync<Response<PlayerInfo>>(httpClient, logger, token)
.SendAsync<Response<PlayerInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
// We have a verification procedure to handle
@@ -102,7 +102,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await verifiedbuilder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
resp = await verifiedbuilder
.TryCatchSendAsync<Response<PlayerInfo>>(httpClient, logger, token)
.SendAsync<Response<PlayerInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
}
}
@@ -121,7 +121,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
Response<SpiralAbyss.SpiralAbyss>? resp = await builder
.TryCatchSendAsync<Response<SpiralAbyss.SpiralAbyss>>(httpClient, logger, token)
.SendAsync<Response<SpiralAbyss.SpiralAbyss>>(httpClient, logger, token)
.ConfigureAwait(false);
// We have a verification procedure to handle
@@ -145,7 +145,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await verifiedbuilder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
resp = await verifiedbuilder
.TryCatchSendAsync<Response<SpiralAbyss.SpiralAbyss>>(httpClient, logger, token)
.SendAsync<Response<SpiralAbyss.SpiralAbyss>>(httpClient, logger, token)
.ConfigureAwait(false);
}
}
@@ -164,7 +164,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
Response<BasicRoleInfo>? resp = await builder
.TryCatchSendAsync<Response<BasicRoleInfo>>(httpClient, logger, token)
.SendAsync<Response<BasicRoleInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -181,7 +181,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
Response<CharacterWrapper>? resp = await builder
.TryCatchSendAsync<Response<CharacterWrapper>>(httpClient, logger, token)
.SendAsync<Response<CharacterWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
// We have a verification procedure to handle
@@ -205,7 +205,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
await verifiedBuilder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
resp = await verifiedBuilder
.TryCatchSendAsync<Response<CharacterWrapper>>(httpClient, logger, token)
.SendAsync<Response<CharacterWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
}
}

View File

@@ -31,7 +31,7 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.OSX4, false).ConfigureAwait(false);
Response<DailyNote.DailyNote>? resp = await builder
.TryCatchSendAsync<Response<DailyNote.DailyNote>>(httpClient, logger, token)
.SendAsync<Response<DailyNote.DailyNote>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -47,7 +47,7 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.OSX4, false).ConfigureAwait(false);
Response<PlayerInfo>? resp = await builder
.TryCatchSendAsync<Response<PlayerInfo>>(httpClient, logger, token)
.SendAsync<Response<PlayerInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -63,7 +63,7 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.OSX4, false).ConfigureAwait(false);
Response<SpiralAbyss.SpiralAbyss>? resp = await builder
.TryCatchSendAsync<Response<SpiralAbyss.SpiralAbyss>>(httpClient, logger, token)
.SendAsync<Response<SpiralAbyss.SpiralAbyss>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -79,7 +79,7 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
await builder.SignDataAsync(DataSignAlgorithmVersion.Gen2, SaltType.OSX4, false).ConfigureAwait(false);
Response<CharacterWrapper>? resp = await builder
.TryCatchSendAsync<Response<CharacterWrapper>>(httpClient, logger, token)
.SendAsync<Response<CharacterWrapper>>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);

View File

@@ -41,6 +41,6 @@ internal sealed partial class HutaoDocumentationClient
.SetHeader("x-algolia-application-id", AlgoliaApplicationId)
.PostJson(data);
return await builder.TryCatchSendAsync<AlgoliaResponse>(httpClient, logger, token).ConfigureAwait(false);
return await builder.SendAsync<AlgoliaResponse>(httpClient, logger, token).ConfigureAwait(false);
}
}

View File

@@ -36,7 +36,7 @@ internal sealed partial class HomaGachaLogClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse<GachaEventStatistics>? resp = await builder
.TryCatchSendAsync<HutaoResponse<GachaEventStatistics>>(httpClient, logger, token)
.SendAsync<HutaoResponse<GachaEventStatistics>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -57,7 +57,7 @@ internal sealed partial class HomaGachaLogClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse<GachaDistribution>? resp = await builder
.TryCatchSendAsync<HutaoResponse<GachaDistribution>>(httpClient, logger, token)
.SendAsync<HutaoResponse<GachaDistribution>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -77,7 +77,7 @@ internal sealed partial class HomaGachaLogClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse<List<GachaEntry>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<GachaEntry>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<GachaEntry>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -98,7 +98,7 @@ internal sealed partial class HomaGachaLogClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse<EndIds>? resp = await builder
.TryCatchSendAsync<HutaoResponse<EndIds>>(httpClient, logger, token)
.SendAsync<HutaoResponse<EndIds>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -122,7 +122,7 @@ internal sealed partial class HomaGachaLogClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse<List<GachaItem>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<GachaItem>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<GachaItem>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -146,7 +146,7 @@ internal sealed partial class HomaGachaLogClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -167,7 +167,7 @@ internal sealed partial class HomaGachaLogClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);

View File

@@ -43,7 +43,7 @@ internal sealed partial class HomaGeetestClient
.Get();
GeetestResponse? resp = await builder
.TryCatchSendAsync<GeetestResponse>(httpClient, logger, token)
.SendAsync<GeetestResponse>(httpClient, logger, token)
.ConfigureAwait(false);
if (resp is null)

View File

@@ -31,7 +31,7 @@ internal sealed partial class HutaoAsAServiceClient
.PostJson(excluedeIds);
HutaoResponse<List<Announcement>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<Announcement>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<Announcement>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -46,7 +46,7 @@ internal sealed partial class HutaoAsAServiceClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -61,7 +61,7 @@ internal sealed partial class HutaoAsAServiceClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -76,7 +76,7 @@ internal sealed partial class HutaoAsAServiceClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);

View File

@@ -25,7 +25,7 @@ internal sealed partial class HutaoInfrastructureClient
.SetRequestUri(HutaoEndpoints.StaticSize)
.Get();
HutaoResponse<StaticResourceSizeInformation>? resp = await builder.TryCatchSendAsync<HutaoResponse<StaticResourceSizeInformation>>(httpClient, logger, token).ConfigureAwait(false);
HutaoResponse<StaticResourceSizeInformation>? resp = await builder.SendAsync<HutaoResponse<StaticResourceSizeInformation>>(httpClient, logger, token).ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
}
@@ -35,7 +35,7 @@ internal sealed partial class HutaoInfrastructureClient
.SetRequestUri(HutaoEndpoints.Ip)
.Get();
HutaoResponse<IPInformation>? resp = await builder.TryCatchSendAsync<HutaoResponse<IPInformation>>(httpClient, logger, token).ConfigureAwait(false);
HutaoResponse<IPInformation>? resp = await builder.SendAsync<HutaoResponse<IPInformation>>(httpClient, logger, token).ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
}
@@ -46,7 +46,7 @@ internal sealed partial class HutaoInfrastructureClient
.SetHeader("x-hutao-device-id", runtimeOptions.DeviceId)
.Get();
HutaoResponse<HutaoVersionInformation>? resp = await builder.TryCatchSendAsync<HutaoResponse<HutaoVersionInformation>>(httpClient, logger, token).ConfigureAwait(false);
HutaoResponse<HutaoVersionInformation>? resp = await builder.SendAsync<HutaoResponse<HutaoVersionInformation>>(httpClient, logger, token).ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
}
@@ -56,7 +56,7 @@ internal sealed partial class HutaoInfrastructureClient
.SetRequestUri(HutaoEndpoints.PatchYaeAchievement)
.Get();
HutaoResponse<YaeVersionInformation>? resp = await builder.TryCatchSendAsync<HutaoResponse<YaeVersionInformation>>(httpClient, logger, token).ConfigureAwait(false);
HutaoResponse<YaeVersionInformation>? resp = await builder.SendAsync<HutaoResponse<YaeVersionInformation>>(httpClient, logger, token).ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
}
}

View File

@@ -64,7 +64,7 @@ internal sealed partial class HutaoPassportClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -92,7 +92,7 @@ internal sealed partial class HutaoPassportClient
.PostJson(data);
HutaoResponse<string>? resp = await builder
.TryCatchSendAsync<HutaoResponse<string>>(httpClient, logger, token)
.SendAsync<HutaoResponse<string>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -114,7 +114,7 @@ internal sealed partial class HutaoPassportClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -142,7 +142,7 @@ internal sealed partial class HutaoPassportClient
.PostJson(data);
HutaoResponse<string>? resp = await builder
.TryCatchSendAsync<HutaoResponse<string>>(httpClient, logger, token)
.SendAsync<HutaoResponse<string>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -168,7 +168,7 @@ internal sealed partial class HutaoPassportClient
.PostJson(data);
HutaoResponse<string>? resp = await builder
.TryCatchSendAsync<HutaoResponse<string>>(httpClient, logger, token)
.SendAsync<HutaoResponse<string>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -188,7 +188,7 @@ internal sealed partial class HutaoPassportClient
await builder.TrySetTokenAsync(hutaoUserOptions).ConfigureAwait(false);
HutaoResponse<UserInfo>? resp = await builder
.TryCatchSendAsync<HutaoResponse<UserInfo>>(httpClient, logger, token)
.SendAsync<HutaoResponse<UserInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);

View File

@@ -35,7 +35,7 @@ internal sealed partial class HutaoLogUploadClient
.PostJson(BuildFromException(exception));
Response<string>? resp = await builder
.TryCatchSendAsync<Response<string>>(httpClient, logger, default)
.SendAsync<Response<string>>(httpClient, logger, default)
.ConfigureAwait(false);
return resp?.Data;

View File

@@ -44,7 +44,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<bool>? resp = await builder
.TryCatchSendAsync<HutaoResponse<bool>>(httpClient, logger, token)
.SendAsync<HutaoResponse<bool>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -64,7 +64,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<RankInfo>? resp = await builder
.TryCatchSendAsync<HutaoResponse<RankInfo>>(httpClient, logger, token)
.SendAsync<HutaoResponse<RankInfo>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -83,7 +83,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<Overview>? resp = await builder
.TryCatchSendAsync<HutaoResponse<Overview>>(httpClient, logger, token)
.SendAsync<HutaoResponse<Overview>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -102,7 +102,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<List<AvatarAppearanceRank>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<AvatarAppearanceRank>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<AvatarAppearanceRank>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -121,7 +121,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<List<AvatarUsageRank>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<AvatarUsageRank>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<AvatarUsageRank>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -140,7 +140,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<List<AvatarCollocation>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<AvatarCollocation>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<AvatarCollocation>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -159,7 +159,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<List<WeaponCollocation>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<WeaponCollocation>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<WeaponCollocation>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -178,7 +178,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<List<AvatarConstellationInfo>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<AvatarConstellationInfo>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<AvatarConstellationInfo>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -197,7 +197,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.Get();
HutaoResponse<List<TeamAppearance>>? resp = await builder
.TryCatchSendAsync<HutaoResponse<List<TeamAppearance>>>(httpClient, logger, token)
.SendAsync<HutaoResponse<List<TeamAppearance>>>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
@@ -256,7 +256,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.PostJson(playerRecord);
HutaoResponse? resp = await builder
.TryCatchSendAsync<HutaoResponse>(httpClient, logger, token)
.SendAsync<HutaoResponse>(httpClient, logger, token)
.ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);

View File

@@ -38,7 +38,7 @@ internal sealed partial class HutaoWallpaperClient
.SetRequestUri(url)
.Get();
Response<Wallpaper>? resp = await builder.TryCatchSendAsync<Response<Wallpaper>>(httpClient, logger, token).ConfigureAwait(false);
Response<Wallpaper>? resp = await builder.SendAsync<Response<Wallpaper>>(httpClient, logger, token).ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
}
}

View File

@@ -13,7 +13,12 @@ internal static class HttpRequestMessageBuilderExtension
{
private const string RequestErrorMessage = "请求异常已忽略: {Uri}";
internal static async ValueTask<TResult?> TryCatchSendAsync<TResult>(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger, CancellationToken token)
internal static void Resurrect(this HttpRequestMessageBuilder builder)
{
builder.HttpRequestMessage.Resurrect();
}
internal static async ValueTask<TResult?> SendAsync<TResult>(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger, CancellationToken token)
where TResult : class
{
try
@@ -70,7 +75,7 @@ internal static class HttpRequestMessageBuilderExtension
}
}
internal static async ValueTask TryCatchSendAsync(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger, CancellationToken token)
internal static async ValueTask SendAsync(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger, CancellationToken token)
{
try
{

View File

@@ -0,0 +1,30 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Net.Http;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Web.Request.Builder;
internal static class HttpRequestMessageExtension
{
private const int MessageNotYetSent = 0;
public static void Resurrect(this HttpRequestMessage httpRequestMessage)
{
Interlocked.Exchange(ref GetPrivateSendStatus(httpRequestMessage), MessageNotYetSent);
if (httpRequestMessage.Content is { } content)
{
Volatile.Write(ref GetPrivatedDisposed(content), false);
}
}
// private int _sendStatus
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_sendStatus")]
private static extern ref int GetPrivateSendStatus(HttpRequestMessage message);
// private bool _disposed
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_disposed")]
private static extern ref bool GetPrivatedDisposed(HttpContent content);
}

View File

@@ -22,7 +22,8 @@ internal unsafe struct IPersistFile
}
}
public HRESULT Save(string szFileName, bool fRemember)
[SuppressMessage("", "SH002")]
public HRESULT Save(ReadOnlySpan<char> szFileName, bool fRemember)
{
fixed (char* pszFileName = szFileName)
{

View File

@@ -24,7 +24,22 @@ internal unsafe struct IFileOperation
}
}
public HRESULT MoveItem(IShellItem* psiItem, IShellItem* psiDestinationFolder, [AllowNull] string szNewName, IFileOperationProgressSink* pfopsItem)
public HRESULT SetOperationFlags(FILEOPERATION_FLAGS dwOperationFlags)
{
return ThisPtr->SetOperationFlags((IFileOperation*)Unsafe.AsPointer(ref this), dwOperationFlags);
}
[SuppressMessage("", "SH002")]
public HRESULT RenameItem(IShellItem* psiItem, ReadOnlySpan<char> szNewName, IFileOperationProgressSink* pfopsItem)
{
fixed (char* pszNewName = szNewName)
{
return ThisPtr->RenameItem((IFileOperation*)Unsafe.AsPointer(ref this), psiItem, pszNewName, pfopsItem);
}
}
[SuppressMessage("", "SH002")]
public HRESULT MoveItem(IShellItem* psiItem, IShellItem* psiDestinationFolder, [AllowNull] ReadOnlySpan<char> szNewName, IFileOperationProgressSink* pfopsItem)
{
fixed (char* pszNewName = szNewName)
{

View File

@@ -26,7 +26,8 @@ internal unsafe struct IShellLinkW
}
}
public HRESULT SetArguments(string szArgs)
[SuppressMessage("", "SH002")]
public HRESULT SetArguments(ReadOnlySpan<char> szArgs)
{
fixed (char* pszArgs = szArgs)
{
@@ -39,7 +40,8 @@ internal unsafe struct IShellLinkW
return ThisPtr->SetShowCmd((IShellLinkW*)Unsafe.AsPointer(ref this), iShowCmd);
}
public HRESULT SetIconLocation(string szIconPath, int iIcon)
[SuppressMessage("", "SH002")]
public HRESULT SetIconLocation(ReadOnlySpan<char> szIconPath, int iIcon)
{
fixed (char* pszIconPath = szIconPath)
{
@@ -47,7 +49,8 @@ internal unsafe struct IShellLinkW
}
}
public HRESULT SetPath(string szFile)
[SuppressMessage("", "SH002")]
public HRESULT SetPath(ReadOnlySpan<char> szFile)
{
fixed (char* pszFile = szFile)
{