mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
impl #1720
This commit is contained in:
@@ -3,26 +3,12 @@
|
|||||||
|
|
||||||
namespace Snap.Hutao.Model.Calculable;
|
namespace Snap.Hutao.Model.Calculable;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 可计算物品选项
|
|
||||||
/// </summary>
|
|
||||||
internal readonly struct CalculableOptions
|
internal readonly struct CalculableOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 角色
|
|
||||||
/// </summary>
|
|
||||||
public readonly ICalculableAvatar? Avatar;
|
public readonly ICalculableAvatar? Avatar;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 武器
|
|
||||||
/// </summary>
|
|
||||||
public readonly ICalculableWeapon? Weapon;
|
public readonly ICalculableWeapon? Weapon;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的可计算物品选项
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="avatar">角色</param>
|
|
||||||
/// <param name="weapon">武器</param>
|
|
||||||
public CalculableOptions(ICalculableAvatar? avatar, ICalculableWeapon? weapon)
|
public CalculableOptions(ICalculableAvatar? avatar, ICalculableWeapon? weapon)
|
||||||
{
|
{
|
||||||
Avatar = avatar;
|
Avatar = avatar;
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// We have a verification procedure to handle
|
// We have a verification procedure to handle
|
||||||
if (resp?.ReturnCode == (int)KnownReturnCode.CODE1034)
|
if (resp?.ReturnCode is (int)KnownReturnCode.CODE1034)
|
||||||
{
|
{
|
||||||
// Replace message
|
// Replace message
|
||||||
resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
|
resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Net.Http.Headers;
|
|||||||
|
|
||||||
namespace Snap.Hutao.Web.Request.Builder;
|
namespace Snap.Hutao.Web.Request.Builder;
|
||||||
|
|
||||||
internal class HttpRequestMessageBuilder :
|
internal sealed class HttpRequestMessageBuilder :
|
||||||
IBuilder,
|
IBuilder,
|
||||||
IHttpRequestMessageBuilder,
|
IHttpRequestMessageBuilder,
|
||||||
IHttpHeadersBuilder<HttpHeaders>,
|
IHttpHeadersBuilder<HttpHeaders>,
|
||||||
@@ -22,12 +22,14 @@ internal class HttpRequestMessageBuilder :
|
|||||||
IHttpMethodBuilder
|
IHttpMethodBuilder
|
||||||
{
|
{
|
||||||
private readonly HttpContentSerializer httpContentSerializer;
|
private readonly HttpContentSerializer httpContentSerializer;
|
||||||
|
private readonly IServiceProvider serviceProvider;
|
||||||
private HttpRequestMessage httpRequestMessage;
|
private HttpRequestMessage httpRequestMessage;
|
||||||
|
|
||||||
public HttpRequestMessageBuilder(HttpContentSerializer httpContentSerializer, HttpRequestMessage? httpRequestMessage = default)
|
public HttpRequestMessageBuilder(IServiceProvider serviceProvider, HttpContentSerializer httpContentSerializer, HttpRequestMessage? httpRequestMessage = default)
|
||||||
{
|
{
|
||||||
|
this.serviceProvider = serviceProvider;
|
||||||
this.httpContentSerializer = httpContentSerializer;
|
this.httpContentSerializer = httpContentSerializer;
|
||||||
this.httpRequestMessage = httpRequestMessage ?? new HttpRequestMessage();
|
this.httpRequestMessage = httpRequestMessage ?? new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequestMessage HttpRequestMessage
|
public HttpRequestMessage HttpRequestMessage
|
||||||
@@ -40,6 +42,8 @@ internal class HttpRequestMessageBuilder :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IServiceProvider ServiceProvider { get => serviceProvider; }
|
||||||
|
|
||||||
public HttpContentSerializer HttpContentSerializer { get => httpContentSerializer; }
|
public HttpContentSerializer HttpContentSerializer { get => httpContentSerializer; }
|
||||||
|
|
||||||
HttpContentHeaders IHttpHeadersBuilder<HttpContentHeaders>.Headers
|
HttpContentHeaders IHttpHeadersBuilder<HttpContentHeaders>.Headers
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Service.Notification;
|
||||||
using Snap.Hutao.Web.Hutao.Response;
|
using Snap.Hutao.Web.Hutao.Response;
|
||||||
|
using Snap.Hutao.Web.Response;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Request.Builder;
|
namespace Snap.Hutao.Web.Request.Builder;
|
||||||
|
|
||||||
@@ -22,6 +25,10 @@ internal static class HttpRequestMessageBuilderExtension
|
|||||||
internal static async ValueTask<TResult?> SendAsync<TResult>(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger, CancellationToken token)
|
internal static async ValueTask<TResult?> SendAsync<TResult>(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger, CancellationToken token)
|
||||||
where TResult : class
|
where TResult : class
|
||||||
{
|
{
|
||||||
|
StringBuilder messageBuilder = new();
|
||||||
|
messageBuilder.AppendLine(System.Globalization.CultureInfo.CurrentCulture, $"Host: {builder.RequestUri?.Host}");
|
||||||
|
bool showInfo = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (builder.HttpRequestMessage)
|
using (builder.HttpRequestMessage)
|
||||||
@@ -29,51 +36,50 @@ internal static class HttpRequestMessageBuilderExtension
|
|||||||
using (HttpResponseMessage message = await httpClient.SendAsync(builder.HttpRequestMessage, token).ConfigureAwait(false))
|
using (HttpResponseMessage message = await httpClient.SendAsync(builder.HttpRequestMessage, token).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
message.EnsureSuccessStatusCode();
|
message.EnsureSuccessStatusCode();
|
||||||
return await builder.HttpContentSerializer.DeserializeAsync<TResult>(message.Content, token).ConfigureAwait(false);
|
showInfo = false;
|
||||||
|
return result = await builder.HttpContentSerializer.DeserializeAsync<TResult>(message.Content, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
catch (HttpRequestException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
if (TryHandleHttp502HutaoResponseSpecialCase(ex, out TResult? result))
|
||||||
|
|
||||||
if (ex.StatusCode is HttpStatusCode.BadGateway)
|
|
||||||
{
|
{
|
||||||
Type resultType = typeof(TResult);
|
return result;
|
||||||
|
|
||||||
if (resultType == typeof(HutaoResponse))
|
|
||||||
{
|
|
||||||
return Activator.CreateInstance(resultType, 502, SH.WebHutaoServiceUnAvailable, default) as TResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultType.IsConstructedGenericType && resultType.GetGenericTypeDefinition() == typeof(HutaoResponse<>))
|
ProcessException(messageBuilder, ex);
|
||||||
{
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
return Activator.CreateInstance(resultType, 502, SH.WebHutaoServiceUnAvailable, default, default) as TResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
ProcessException(messageBuilder, ex);
|
||||||
return default;
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
catch (JsonException ex)
|
catch (JsonException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
ProcessException(messageBuilder, ex);
|
||||||
return default;
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
catch (HttpContentSerializationException ex)
|
catch (HttpContentSerializationException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
ProcessException(messageBuilder, ex);
|
||||||
return default;
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (SocketException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
ProcessException(messageBuilder, ex);
|
||||||
return default;
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (showInfo)
|
||||||
|
{
|
||||||
|
builder.ServiceProvider.GetRequiredService<IInfoBarService>().Error(messageBuilder.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Send(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger)
|
internal static void Send(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger)
|
||||||
@@ -86,23 +92,95 @@ internal static class HttpRequestMessageBuilderExtension
|
|||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
catch (HttpRequestException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
catch (JsonException ex)
|
catch (JsonException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
catch (HttpContentSerializationException ex)
|
catch (HttpContentSerializationException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (SocketException ex)
|
||||||
{
|
{
|
||||||
logger.LogWarning(ex, RequestErrorMessage, builder.HttpRequestMessage.RequestUri);
|
logger.LogWarning(ex, RequestErrorMessage, builder.RequestUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryHandleHttp502HutaoResponseSpecialCase<TResult>(HttpRequestException ex, out TResult? result)
|
||||||
|
where TResult : class
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
|
||||||
|
if (ex.StatusCode is HttpStatusCode.BadGateway)
|
||||||
|
{
|
||||||
|
Type resultType = typeof(TResult);
|
||||||
|
|
||||||
|
if (resultType == typeof(HutaoResponse))
|
||||||
|
{
|
||||||
|
// HutaoResponse(int returnCode, string message, string? localizationKey)
|
||||||
|
result = Activator.CreateInstance(resultType, 502, SH.WebHutaoServiceUnAvailable, default) as TResult;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultType.IsConstructedGenericType && resultType.GetGenericTypeDefinition() == typeof(HutaoResponse<>))
|
||||||
|
{
|
||||||
|
// HutaoResponse<TData>(int returnCode, string message, TData? data, string? localizationKey)
|
||||||
|
result = Activator.CreateInstance(resultType, 502, SH.WebHutaoServiceUnAvailable, default, default) as TResult;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("", "CA1305")]
|
||||||
|
private static void ProcessException(StringBuilder builder, Exception exception)
|
||||||
|
{
|
||||||
|
if (exception is HttpRequestException hre)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AppendLine($"{nameof(HttpRequestException)}: Status Code: {hre.StatusCode} Error: {hre.HttpRequestError}")
|
||||||
|
.AppendLine(hre.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception is IOException ioe)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AppendLine($"{nameof(IOException)}: 0x{ioe.HResult:X8}")
|
||||||
|
.AppendLine(ioe.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception is JsonException je)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AppendLine($"{nameof(JsonException)}: Path: {je.Path} at Line: {je.LineNumber} Position: {je.BytePositionInLine}")
|
||||||
|
.AppendLine(je.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception is HttpContentSerializationException hcse)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AppendLine($"{nameof(HttpContentSerializationException)}:")
|
||||||
|
.AppendLine(hcse.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception is SocketException se)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AppendLine($"{nameof(SocketException)}: Error: {se.SocketErrorCode}")
|
||||||
|
.AppendLine(se.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception.InnerException is { } inner)
|
||||||
|
{
|
||||||
|
builder.AppendLine(new string('-', 40));
|
||||||
|
ProcessException(builder, inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,10 @@ namespace Snap.Hutao.Web.Request.Builder;
|
|||||||
internal sealed partial class HttpRequestMessageBuilderFactory : IHttpRequestMessageBuilderFactory
|
internal sealed partial class HttpRequestMessageBuilderFactory : IHttpRequestMessageBuilderFactory
|
||||||
{
|
{
|
||||||
private readonly JsonHttpContentSerializer jsonHttpContentSerializer;
|
private readonly JsonHttpContentSerializer jsonHttpContentSerializer;
|
||||||
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
public HttpRequestMessageBuilder Create()
|
public HttpRequestMessageBuilder Create()
|
||||||
{
|
{
|
||||||
return new(jsonHttpContentSerializer);
|
return new(serviceProvider, jsonHttpContentSerializer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user