diff --git a/src/Snap.Hutao/Snap.Hutao.Test/BaseClassLibrary/JsonSerializeTest.cs b/src/Snap.Hutao/Snap.Hutao.Test/BaseClassLibrary/JsonSerializeTest.cs
index 309ef2bb..c9b65c17 100644
--- a/src/Snap.Hutao/Snap.Hutao.Test/BaseClassLibrary/JsonSerializeTest.cs
+++ b/src/Snap.Hutao/Snap.Hutao.Test/BaseClassLibrary/JsonSerializeTest.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -65,6 +66,20 @@ public sealed class JsonSerializeTest
Assert.AreEqual(result, """{"Array":"AQIDBAU="}""");
}
+ [TestMethod]
+ public void InterfaceDefaultMethodCanSerializeActualInstanceMember()
+ {
+ ISampleInterface sample = new SampleClassImplementedInterface()
+ {
+ A = 1,
+ B = 2,
+ };
+
+ string result = sample.ToJson();
+ Console.WriteLine(result);
+ Assert.AreEqual(result, """{"A":1,"B":2}""");
+ }
+
private sealed class SampleDelegatePropertyClass
{
public int A { get => B; set => B = value; }
@@ -81,4 +96,22 @@ public sealed class JsonSerializeTest
{
public byte[]? Array { get; set; }
}
+
+ private sealed class SampleClassImplementedInterface : ISampleInterface
+ {
+ public int A { get; set; }
+
+ public int B { get; set; }
+ }
+
+ [JsonDerivedType(typeof(SampleClassImplementedInterface))]
+ private interface ISampleInterface
+ {
+ int A { get; set; }
+
+ string ToJson()
+ {
+ return JsonSerializer.Serialize(this);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao.Win32/NativeMethods.txt b/src/Snap.Hutao/Snap.Hutao.Win32/NativeMethods.txt
index 3a8308d4..688a3f50 100644
--- a/src/Snap.Hutao/Snap.Hutao.Win32/NativeMethods.txt
+++ b/src/Snap.Hutao/Snap.Hutao.Win32/NativeMethods.txt
@@ -21,6 +21,7 @@ K32EnumProcessModules
K32GetModuleBaseNameW
K32GetModuleInformation
ReadProcessMemory
+SetConsoleTitle
SetEvent
VirtualAlloc
VirtualAllocEx
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Logging/ConsoleWindowLifeTime.cs b/src/Snap.Hutao/Snap.Hutao/Core/Logging/ConsoleWindowLifeTime.cs
index 66f4ceaf..7869b4ea 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Logging/ConsoleWindowLifeTime.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Logging/ConsoleWindowLifeTime.cs
@@ -15,6 +15,7 @@ internal sealed class ConsoleWindowLifeTime : IDisposable
if (LocalSetting.Get(SettingKeys.IsAllocConsoleDebugModeEnabled, false))
{
consoleWindowAllocated = AllocConsole();
+ SetConsoleTitle("Snap Hutao Debug Console");
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs
index 3466901d..6ebf6013 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs
@@ -86,7 +86,7 @@ internal class MiHoYoJSBridge
///
/// 参数
/// 响应
- protected virtual async ValueTask ClosePageAsync(JsParam param)
+ protected virtual async ValueTask ClosePageAsync(JsParam param)
{
await taskContext.SwitchToMainThreadAsync();
if (coreWebView2.CanGoBack)
@@ -106,7 +106,7 @@ internal class MiHoYoJSBridge
///
/// 参数
/// 响应
- protected virtual IJsResult? ConfigureShare(JsParam param)
+ protected virtual IJsBridgeResult? ConfigureShare(JsParam param)
{
return null;
}
@@ -116,7 +116,7 @@ internal class MiHoYoJSBridge
///
/// 参数
/// 响应
- protected virtual async ValueTask GetActionTicketAsync(JsParam jsParam)
+ protected virtual async ValueTask GetActionTicketAsync(JsParam jsParam)
{
return await serviceProvider
.GetRequiredService()
@@ -299,7 +299,7 @@ internal class MiHoYoJSBridge
}
}
- protected virtual async ValueTask PushPageAsync(JsParam param)
+ protected virtual async ValueTask PushPageAsync(JsParam param)
{
const string bbsSchema = "mihoyobbs://";
string pageUrl = param.Payload.Page;
@@ -323,7 +323,7 @@ internal class MiHoYoJSBridge
return null;
}
- protected virtual IJsResult? Share(JsParam param)
+ protected virtual IJsBridgeResult? Share(JsParam param)
{
return new JsResult>()
{
@@ -334,47 +334,47 @@ internal class MiHoYoJSBridge
};
}
- protected virtual ValueTask ShowAlertDialogAsync(JsParam param)
+ protected virtual ValueTask ShowAlertDialogAsync(JsParam param)
{
- return ValueTask.FromException(new NotSupportedException());
+ return ValueTask.FromException(new NotSupportedException());
}
- protected virtual IJsResult? StartRealPersonValidation(JsParam param)
+ protected virtual IJsBridgeResult? StartRealPersonValidation(JsParam param)
{
throw new NotImplementedException();
}
- protected virtual IJsResult? StartRealnameAuth(JsParam param)
+ protected virtual IJsBridgeResult? StartRealnameAuth(JsParam param)
{
throw new NotImplementedException();
}
- protected virtual IJsResult? GenAuthKey(JsParam param)
+ protected virtual IJsBridgeResult? GenAuthKey(JsParam param)
{
throw new NotImplementedException();
}
- protected virtual IJsResult? GenAppAuthKey(JsParam param)
+ protected virtual IJsBridgeResult? GenAppAuthKey(JsParam param)
{
throw new NotImplementedException();
}
- protected virtual IJsResult? OpenSystemBrowser(JsParam param)
+ protected virtual IJsBridgeResult? OpenSystemBrowser(JsParam param)
{
throw new NotImplementedException();
}
- protected virtual IJsResult? SaveLoginTicket(JsParam param)
+ protected virtual IJsBridgeResult? SaveLoginTicket(JsParam param)
{
throw new NotImplementedException();
}
- protected virtual ValueTask GetNotificationSettingsAsync(JsParam param)
+ protected virtual ValueTask GetNotificationSettingsAsync(JsParam param)
{
throw new NotImplementedException();
}
- protected virtual IJsResult? ShowToast(JsParam param)
+ protected virtual IJsBridgeResult? ShowToast(JsParam param)
{
throw new NotImplementedException();
}
@@ -430,7 +430,7 @@ internal class MiHoYoJSBridge
logger.LogInformation("[OnMessage]\nMethod : {method}\nPayload : {payload}\nCallback: {callback}", param.Method, param.Payload, param.Callback);
using (await webMessageSemaphore.EnterAsync().ConfigureAwait(false))
{
- IJsResult? result = await TryGetJsResultFromJsParamAsync(param).ConfigureAwait(false);
+ IJsBridgeResult? result = await TryGetJsResultFromJsParamAsync(param).ConfigureAwait(false);
if (result is not null && param.Callback is not null)
{
@@ -440,13 +440,13 @@ internal class MiHoYoJSBridge
}
[SuppressMessage("", "CA2254")]
- private IJsResult? LogUnhandledMessage(string message, params object?[] param)
+ private IJsBridgeResult? LogUnhandledMessage(string message, params object?[] param)
{
logger.LogWarning(message, param);
return default;
}
- private async ValueTask TryGetJsResultFromJsParamAsync(JsParam param)
+ private async ValueTask TryGetJsResultFromJsParamAsync(JsParam param)
{
if (coreWebView2.IsDisposed())
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/IJsResult.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/IJsBridgeResult.cs
similarity index 54%
rename from src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/IJsResult.cs
rename to src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/IJsBridgeResult.cs
index a677586a..4d1be414 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/IJsResult.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/IJsBridgeResult.cs
@@ -7,11 +7,10 @@ namespace Snap.Hutao.Web.Bridge.Model;
/// 指示此为Js结果
///
[HighQuality]
-internal interface IJsResult
+internal interface IJsBridgeResult
{
- ///
- /// 转换到Json字符串表示
- ///
- /// JSON字符串
- string ToJson();
-}
+ string ToJson()
+ {
+ return JsonSerializer.Serialize(this);
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsResult.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsResult.cs
index 1c4e5b6e..0e817860 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsResult.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsResult.cs
@@ -9,7 +9,7 @@ namespace Snap.Hutao.Web.Bridge.Model;
///
/// 内部数据类型
[HighQuality]
-internal sealed class JsResult : IJsResult
+internal sealed class JsResult : IJsBridgeResult
{
///
/// 代码
@@ -28,10 +28,4 @@ internal sealed class JsResult : IJsResult
///
[JsonPropertyName("data")]
public TData Data { get; set; } = default!;
-
- ///
- string IJsResult.ToJson()
- {
- return JsonSerializer.Serialize(this);
- }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs
index bc057241..c02f6736 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs
@@ -50,10 +50,8 @@ internal sealed partial class BindingClient
string actionTicket = actionTicketResponse.Data.Ticket;
return await GetUserGameRolesByActionTicketAsync(actionTicket, user, token).ConfigureAwait(false);
}
- else
- {
- return Response.Response.DefaultIfNull, ActionTicketWrapper>(actionTicketResponse);
- }
+
+ return Response.Response.CloneReturnCodeAndMessage, ActionTicketWrapper>(actionTicketResponse);
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs
index a85f2acc..503a7c2f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/HomaGachaLogClient.cs
@@ -39,7 +39,7 @@ internal sealed partial class HomaGachaLogClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -60,7 +60,7 @@ internal sealed partial class HomaGachaLogClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -80,7 +80,7 @@ internal sealed partial class HomaGachaLogClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -101,7 +101,7 @@ internal sealed partial class HomaGachaLogClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -125,7 +125,7 @@ internal sealed partial class HomaGachaLogClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -149,7 +149,7 @@ internal sealed partial class HomaGachaLogClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -170,7 +170,7 @@ internal sealed partial class HomaGachaLogClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
private sealed class UidAndEndIds
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs
index c1290fb4..3251df1e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoAsAService/HutaoAsAServiceClient.cs
@@ -34,7 +34,7 @@ internal sealed partial class HutaoAsAServiceClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
public async ValueTask UploadAnnouncementAsync(UploadAnnouncement uploadAnnouncement, CancellationToken token = default)
@@ -49,7 +49,7 @@ internal sealed partial class HutaoAsAServiceClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
public async ValueTask GachaLogCompensationAsync(int days, CancellationToken token = default)
@@ -64,7 +64,7 @@ internal sealed partial class HutaoAsAServiceClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
public async ValueTask GachaLogDesignationAsync(string userName, int days, CancellationToken token = default)
@@ -79,6 +79,6 @@ internal sealed partial class HutaoAsAServiceClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoInfrastructureClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoInfrastructureClient.cs
index 7a1c3e55..a588e507 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoInfrastructureClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoInfrastructureClient.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
+using Snap.Hutao.Web.Hutao.Response;
using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
using Snap.Hutao.Web.Response;
@@ -17,7 +18,7 @@ internal sealed partial class HutaoInfrastructureClient
private readonly ILogger logger;
private readonly HttpClient httpClient;
- public async ValueTask> GetIPInformationAsync(CancellationToken token = default)
+ public async ValueTask> GetIPInformationAsync(CancellationToken token = default)
{
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
.SetRequestUri(HutaoEndpoints.Ip)
@@ -26,4 +27,24 @@ internal sealed partial class HutaoInfrastructureClient
Response? resp = await builder.TryCatchSendAsync>(httpClient, logger, token).ConfigureAwait(false);
return Web.Response.Response.DefaultIfNull(resp);
}
+
+ public async ValueTask> GetHutaoVersionInfomationAsync(CancellationToken token = default)
+ {
+ HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
+ .SetRequestUri(HutaoEndpoints.PatchSnapHutao)
+ .Get();
+
+ Response? resp = await builder.TryCatchSendAsync>(httpClient, logger, token).ConfigureAwait(false);
+ return Web.Response.Response.DefaultIfNull(resp);
+ }
+
+ public async ValueTask> GetYaeVersionInformationAsync(CancellationToken token = default)
+ {
+ HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
+ .SetRequestUri(HutaoEndpoints.PatchYaeAchievement)
+ .Get();
+
+ Response? resp = await builder.TryCatchSendAsync>(httpClient, logger, token).ConfigureAwait(false);
+ return Web.Response.Response.DefaultIfNull(resp);
+ }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoPassportClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoPassportClient.cs
index f3be6276..e19ef3ad 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoPassportClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoPassportClient.cs
@@ -67,7 +67,7 @@ internal sealed partial class HutaoPassportClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -95,7 +95,7 @@ internal sealed partial class HutaoPassportClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
public async ValueTask UnregisterAsync(string email, string password, string verifyCode, CancellationToken token = default)
@@ -117,7 +117,7 @@ internal sealed partial class HutaoPassportClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -145,7 +145,7 @@ internal sealed partial class HutaoPassportClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -171,7 +171,7 @@ internal sealed partial class HutaoPassportClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -191,7 +191,7 @@ internal sealed partial class HutaoPassportClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
private static string Encrypt(string text)
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoVersionInformation.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoVersionInformation.cs
new file mode 100644
index 00000000..729019c5
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoVersionInformation.cs
@@ -0,0 +1,10 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Hutao;
+
+internal sealed class HutaoVersionInformation
+{
+ [JsonPropertyName("version")]
+ public Version Version { get; set; } = default!;
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Response/HutaoResponse.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Response/HutaoResponse.cs
index 906a7845..2eb2cf2e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Response/HutaoResponse.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Response/HutaoResponse.cs
@@ -1,11 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using System.Runtime.CompilerServices;
+using Snap.Hutao.Web.Response;
namespace Snap.Hutao.Web.Hutao.Response;
-internal sealed class HutaoResponse : Web.Response.Response, ILocalizableResponse
+internal sealed class HutaoResponse : Web.Response.Response, ILocalizableResponse, ICommonResponse
{
[JsonConstructor]
public HutaoResponse(int returnCode, string message, string? localizationKey)
@@ -17,18 +17,9 @@ internal sealed class HutaoResponse : Web.Response.Response, ILocalizableRespons
[JsonPropertyName("l10nKey")]
public string? LocalizationKey { get; set; }
- public static HutaoResponse DefaultIfNull(HutaoResponse? response, [CallerMemberName] string callerName = default!)
+ static HutaoResponse ICommonResponse.CreateDefault(int returnCode, string message)
{
- // 0x26F19335 is a magic number that hashed from "Snap.Hutao"
- response ??= new(InternalFailure, SH.FormatWebResponseRequestExceptionFormat(callerName, null), default);
- return response;
- }
-
- public static HutaoResponse DefaultIfNull(HutaoResponse? response, [CallerMemberName] string callerName = default!)
- {
- // 0x26F19335 is a magic number that hashed from "Snap.Hutao"
- response ??= new(InternalFailure, SH.FormatWebResponseRequestExceptionFormat(callerName, typeof(TData).Name), default, default);
- return response ?? new(InternalFailure, SH.FormatWebResponseRequestExceptionFormat(callerName, typeof(TData).Name), default, default);
+ return new(returnCode, message, default);
}
public override string ToString()
@@ -38,7 +29,7 @@ internal sealed class HutaoResponse : Web.Response.Response, ILocalizableRespons
}
[SuppressMessage("", "SA1402")]
-internal sealed class HutaoResponse : Web.Response.Response, ILocalizableResponse
+internal sealed class HutaoResponse : Response, ILocalizableResponse, ICommonResponse>
{
[JsonConstructor]
public HutaoResponse(int returnCode, string message, TData? data, string? localizationKey)
@@ -50,6 +41,11 @@ internal sealed class HutaoResponse : Web.Response.Response, ILoca
[JsonPropertyName("l10nKey")]
public string? LocalizationKey { get; set; }
+ static HutaoResponse ICommonResponse>.CreateDefault(int returnCode, string message)
+ {
+ return new(returnCode, message, default, default);
+ }
+
public override string ToString()
{
return SH.FormatWebResponseFormat(ReturnCode, this.GetLocalizationMessageOrDefault());
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HutaoSpiralAbyssClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HutaoSpiralAbyssClient.cs
index 427575a2..db2937af 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HutaoSpiralAbyssClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/SpiralAbyss/HutaoSpiralAbyssClient.cs
@@ -47,7 +47,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -67,7 +67,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -86,7 +86,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -105,7 +105,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -124,7 +124,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -143,7 +143,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -162,7 +162,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -181,7 +181,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -200,7 +200,7 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync>>(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
///
@@ -259,6 +259,6 @@ internal sealed partial class HutaoSpiralAbyssClient
.TryCatchSendAsync(httpClient, logger, token)
.ConfigureAwait(false);
- return HutaoResponse.DefaultIfNull(resp);
+ return Web.Response.Response.DefaultIfNull(resp);
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/YaeVersionInformation.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/YaeVersionInformation.cs
new file mode 100644
index 00000000..76b82049
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/YaeVersionInformation.cs
@@ -0,0 +1,19 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Hutao;
+
+internal sealed class YaeVersionInformation
+{
+ [JsonPropertyName("tagName")]
+ public Version Version { get; set; } = default!;
+
+ [JsonPropertyName("url")]
+ public string Url { get; set; } = default!;
+
+ [JsonPropertyName("source")]
+ public string Source { get; set; } = default!;
+
+ [JsonPropertyName("frameworkUrl")]
+ public string FrameworkUrl { get; set; } = default!;
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs
index c6867f9e..6253cfd9 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs
@@ -15,24 +15,7 @@ namespace Snap.Hutao.Web;
[SuppressMessage("", "SA1124")]
internal static class HutaoEndpoints
{
- #region Hutao as a Service
- public static string Announcement(string locale)
- {
- return $"{HomaSnapGenshinApi}/Announcement/List?locale={locale}";
- }
-
- public const string AnnouncementUpload = $"{HomaSnapGenshinApi}/Service/Announcement/Upload";
-
- public static string GachaLogCompensation(int days)
- {
- return $"{HomaSnapGenshinApi}/Service/GachaLog/Compensation?days={days}";
- }
-
- public static string GachaLogDesignation(string userName, int days)
- {
- return $"{HomaSnapGenshinApi}/Service/GachaLog/Designation?userName={userName}&days={days}";
- }
- #endregion
+ #region HomaAPI
#region GachaLog
@@ -43,28 +26,28 @@ internal static class HutaoEndpoints
/// 获取末尾Id Url
public static string GachaLogEndIds(string uid)
{
- return $"{HomaSnapGenshinApi}/GachaLog/EndIds?Uid={uid}";
+ return $"{HomaSnapGenshin}/GachaLog/EndIds?Uid={uid}";
}
///
/// 获取祈愿记录
///
- public const string GachaLogRetrieve = $"{HomaSnapGenshinApi}/GachaLog/Retrieve";
+ public const string GachaLogRetrieve = $"{HomaSnapGenshin}/GachaLog/Retrieve";
///
/// 上传祈愿记录
///
- public const string GachaLogUpload = $"{HomaSnapGenshinApi}/GachaLog/Upload";
+ public const string GachaLogUpload = $"{HomaSnapGenshin}/GachaLog/Upload";
///
/// 获取Uid列表
///
- public const string GachaLogUids = $"{HomaSnapGenshinApi}/GachaLog/Uids";
+ public const string GachaLogUids = $"{HomaSnapGenshin}/GachaLog/Uids";
///
/// 获取Uid列表
///
- public const string GachaLogEntries = $"{HomaSnapGenshinApi}/GachaLog/Entries";
+ public const string GachaLogEntries = $"{HomaSnapGenshin}/GachaLog/Entries";
///
/// 删除祈愿记录
@@ -73,13 +56,13 @@ internal static class HutaoEndpoints
/// 删除祈愿记录 Url
public static string GachaLogDelete(string uid)
{
- return $"{HomaSnapGenshinApi}/GachaLog/Delete?Uid={uid}";
+ return $"{HomaSnapGenshin}/GachaLog/Delete?Uid={uid}";
}
///
/// 获取祈愿统计信息
///
- public const string GachaLogStatisticsCurrentEvents = $"{HomaSnapGenshinApi}/GachaLog/Statistics/CurrentEventStatistics";
+ public const string GachaLogStatisticsCurrentEvents = $"{HomaSnapGenshin}/GachaLog/Statistics/CurrentEventStatistics";
///
/// 获取祈愿统计信息
@@ -88,41 +71,27 @@ internal static class HutaoEndpoints
/// 祈愿统计信息Url
public static string GachaLogStatisticsDistribution(GachaDistributionType distributionType)
{
- return $"{HomaSnapGenshinApi}/GachaLog/Statistics/Distribution/{distributionType}";
+ return $"{HomaSnapGenshin}/GachaLog/Statistics/Distribution/{distributionType}";
}
#endregion
- #region Passport
+ #region Hutao as a Service
+ public static string Announcement(string locale)
+ {
+ return $"{HomaSnapGenshin}/Announcement/List?locale={locale}";
+ }
- ///
- /// 获取注册验证码
- ///
- public const string PassportVerify = $"{HomaSnapGenshinApi}/Passport/Verify";
+ public const string AnnouncementUpload = $"{HomaSnapGenshin}/Service/Announcement/Upload";
- ///
- /// 注册账号
- ///
- public const string PassportRegister = $"{HomaSnapGenshinApi}/Passport/Register";
+ public static string GachaLogCompensation(int days)
+ {
+ return $"{HomaSnapGenshin}/Service/GachaLog/Compensation?days={days}";
+ }
- ///
- /// 注销账号
- ///
- public const string PassportCancel = $"{HomaSnapGenshinApi}/Passport/Cancel";
-
- ///
- /// 重设密码
- ///
- public const string PassportResetPassword = $"{HomaSnapGenshinApi}/Passport/ResetPassword";
-
- ///
- /// 登录
- ///
- public const string PassportLogin = $"{HomaSnapGenshinApi}/Passport/Login";
-
- ///
- /// 用户信息
- ///
- public const string PassportUserInfo = $"{HomaSnapGenshinApi}/Passport/UserInfo";
+ public static string GachaLogDesignation(string userName, int days)
+ {
+ return $"{HomaSnapGenshin}/Service/GachaLog/Designation?userName={userName}&days={days}";
+ }
#endregion
#region LogUpload
@@ -130,7 +99,40 @@ internal static class HutaoEndpoints
///
/// 上传日志
///
- public const string HutaoLogUpload = $"{HomaSnapGenshinApi}/HutaoLog/Upload";
+ public const string HutaoLogUpload = $"{HomaSnapGenshin}/HutaoLog/Upload";
+ #endregion
+
+ #region Passport
+
+ ///
+ /// 获取注册验证码
+ ///
+ public const string PassportVerify = $"{HomaSnapGenshin}/Passport/Verify";
+
+ ///
+ /// 注册账号
+ ///
+ public const string PassportRegister = $"{HomaSnapGenshin}/Passport/Register";
+
+ ///
+ /// 注销账号
+ ///
+ public const string PassportCancel = $"{HomaSnapGenshin}/Passport/Cancel";
+
+ ///
+ /// 重设密码
+ ///
+ public const string PassportResetPassword = $"{HomaSnapGenshin}/Passport/ResetPassword";
+
+ ///
+ /// 登录
+ ///
+ public const string PassportLogin = $"{HomaSnapGenshin}/Passport/Login";
+
+ ///
+ /// 用户信息
+ ///
+ public const string PassportUserInfo = $"{HomaSnapGenshin}/Passport/UserInfo";
#endregion
#region SpiralAbyss
@@ -142,7 +144,7 @@ internal static class HutaoEndpoints
/// 路径
public static string RecordCheck(string uid)
{
- return $"{HomaSnapGenshinApi}/Record/Check?uid={uid}";
+ return $"{HomaSnapGenshin}/Record/Check?uid={uid}";
}
///
@@ -152,50 +154,66 @@ internal static class HutaoEndpoints
/// 路径
public static string RecordRank(string uid)
{
- return $"{HomaSnapGenshinApi}/Record/Rank?uid={uid}";
+ return $"{HomaSnapGenshin}/Record/Rank?uid={uid}";
}
///
/// 上传记录
///
- public const string RecordUpload = $"{HomaSnapGenshinApi}/Record/Upload";
+ public const string RecordUpload = $"{HomaSnapGenshin}/Record/Upload";
///
/// 统计信息
///
- public const string StatisticsOverview = $"{HomaSnapGenshinApi}/Statistics/Overview";
+ public const string StatisticsOverview = $"{HomaSnapGenshin}/Statistics/Overview";
///
/// 出场率
///
- public const string StatisticsAvatarAttendanceRate = $"{HomaSnapGenshinApi}/Statistics/Avatar/AttendanceRate";
+ public const string StatisticsAvatarAttendanceRate = $"{HomaSnapGenshin}/Statistics/Avatar/AttendanceRate";
///
/// 使用率
///
- public const string StatisticsAvatarUtilizationRate = $"{HomaSnapGenshinApi}/Statistics/Avatar/UtilizationRate";
+ public const string StatisticsAvatarUtilizationRate = $"{HomaSnapGenshin}/Statistics/Avatar/UtilizationRate";
///
/// 角色搭配
///
- public const string StatisticsAvatarAvatarCollocation = $"{HomaSnapGenshinApi}/Statistics/Avatar/AvatarCollocation";
+ public const string StatisticsAvatarAvatarCollocation = $"{HomaSnapGenshin}/Statistics/Avatar/AvatarCollocation";
///
/// 角色持有率
///
- public const string StatisticsAvatarHoldingRate = $"{HomaSnapGenshinApi}/Statistics/Avatar/HoldingRate";
+ public const string StatisticsAvatarHoldingRate = $"{HomaSnapGenshin}/Statistics/Avatar/HoldingRate";
///
/// 武器搭配
///
- public const string StatisticsWeaponWeaponCollocation = $"{HomaSnapGenshinApi}/Statistics/Weapon/WeaponCollocation";
+ public const string StatisticsWeaponWeaponCollocation = $"{HomaSnapGenshin}/Statistics/Weapon/WeaponCollocation";
///
/// 持有率
///
- public const string StatisticsTeamCombination = $"{HomaSnapGenshinApi}/Statistics/Team/Combination";
+ public const string StatisticsTeamCombination = $"{HomaSnapGenshin}/Statistics/Team/Combination";
#endregion
+ public static string Website(string path)
+ {
+ return $"{HomaSnapGenshin}/{path}";
+ }
+
+ #endregion
+
+ #region Infrasturcture
+
+ public static string Enka(in PlayerUid uid)
+ {
+ return $"{ApiSnapGenshinEnka}/{uid}";
+ }
+
+ public const string Ip = $"{ApiSnapGenshin}/ip";
+
#region Metadata
///
@@ -210,7 +228,12 @@ internal static class HutaoEndpoints
}
#endregion
- #region Static & Zip
+ #region Patch
+ public const string PatchYaeAchievement = $"{ApiSnapGenshinPatch}/yae";
+ public const string PatchSnapHutao = $"{ApiSnapGenshinPatch}/hutao";
+ #endregion
+
+ #region StaticResources
///
/// UI_Icon_None
@@ -249,21 +272,13 @@ internal static class HutaoEndpoints
}
#endregion
- public static string Website(string path)
- {
- return $"{HomaSnapGenshinApi}/{path}";
- }
+ #endregion
- public static string Enka(in PlayerUid uid)
- {
- return $"{ApiSnapGenshinEnka}/{uid}";
- }
-
- public const string Ip = $"{ApiSnapGenshin}/ip";
private const string ApiSnapGenshin = "https://api.snapgenshin.com";
private const string ApiSnapGenshinMetadata = $"{ApiSnapGenshin}/metadata";
+ private const string ApiSnapGenshinPatch = $"{ApiSnapGenshin}/patch";
private const string ApiSnapGenshinStaticRaw = $"{ApiSnapGenshin}/static/raw";
private const string ApiSnapGenshinStaticZip = $"{ApiSnapGenshin}/static/zip";
private const string ApiSnapGenshinEnka = $"{ApiSnapGenshin}/enka";
- private const string HomaSnapGenshinApi = "https://homa.snapgenshin.com";
+ private const string HomaSnapGenshin = "https://homa.snapgenshin.com";
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/ICommonResponse.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/ICommonResponse.cs
new file mode 100644
index 00000000..b40061c6
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/ICommonResponse.cs
@@ -0,0 +1,14 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Response;
+
+internal interface ICommonResponse
+ where TResponse : ICommonResponse
+{
+ int ReturnCode { get; }
+
+ string Message { get; set; }
+
+ static abstract TResponse CreateDefault(int returnCode, string message);
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs
index 4f0bc8b8..8a316442 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs
@@ -1,25 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using Snap.Hutao.Core;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Web.Bridge.Model;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Web.Response;
-///
-/// 提供 的非泛型基类
-///
-[HighQuality]
-internal class Response
+internal class Response : ICommonResponse
{
public const int InternalFailure = 0x26F19335;
- ///
- /// 构造一个新的响应
- ///
- /// 返回代码
- /// 消息
[JsonConstructor]
public Response(int returnCode, string message)
{
@@ -30,15 +22,9 @@ internal class Response
#endif
}
- ///
- /// 返回代码
- ///
[JsonPropertyName("retcode")]
public int ReturnCode { get; set; }
- ///
- /// 消息
- ///
[JsonPropertyName("message")]
public string Message { get; set; } = default!;
@@ -47,16 +33,16 @@ internal class Response
return new(response.ReturnCode == 0, response.Message);
}
- ///
- /// 返回本体或带有消息提示的默认值
- ///
- /// 本体
- /// 调用方法名称
- /// 本体或默认值,当本体为 null 时 返回默认值
- public static Response DefaultIfNull(Response? response, [CallerMemberName] string callerName = default!)
+ static Response ICommonResponse.CreateDefault(int returnCode, string message)
{
- // 0x26F19335 is a magic number that hashed from "Snap.Hutao"
- response ??= new(InternalFailure, SH.FormatWebResponseRequestExceptionFormat(callerName, null));
+ return new(returnCode, message);
+ }
+
+ public static TResponse DefaultIfNull(TResponse? response, [CallerMemberName] string callerName = default!)
+ where TResponse : ICommonResponse
+ {
+ string message = SH.FormatWebResponseRequestExceptionFormat(callerName, TypeNameHelper.GetTypeDisplayName(typeof(TResponse)));
+ response ??= TResponse.CreateDefault(InternalFailure, message);
if (((KnownReturnCode)response.ReturnCode) is KnownReturnCode.PleaseLogin or KnownReturnCode.RET_TOKEN_INVALID)
{
@@ -66,46 +52,9 @@ internal class Response
return response;
}
- ///
- /// 返回本体或带有消息提示的默认值
- ///
- /// 类型
- /// 本体
- /// 调用方法名称
- /// 本体或默认值,当本体为 null 时 返回默认值
- public static Response DefaultIfNull(Response? response, [CallerMemberName] string callerName = default!)
+ public static Response CloneReturnCodeAndMessage(Response response, [CallerMemberName] string callerName = default!)
{
- // 0x26F19335 is a magic number that hashed from "Snap.Hutao"
- response ??= new(InternalFailure, SH.FormatWebResponseRequestExceptionFormat(callerName, typeof(TData).Name), default);
-
- if (((KnownReturnCode)response.ReturnCode) is KnownReturnCode.PleaseLogin or KnownReturnCode.RET_TOKEN_INVALID)
- {
- response.Message = SH.FormatWebResponseRefreshCookieHintFormat(response.Message);
- }
-
- return response ?? new(InternalFailure, SH.FormatWebResponseRequestExceptionFormat(callerName, typeof(TData).Name), default);
- }
-
- ///
- /// 返回本体或带有消息提示的默认值
- ///
- /// 类型
- /// 其他类型
- /// 本体
- /// 调用方法名称
- /// 本体或默认值,当本体为 null 时 返回默认值
- public static Response DefaultIfNull(Response? response, [CallerMemberName] string callerName = default!)
- {
- if (response is not null)
- {
- Must.Argument(response.ReturnCode != 0, "RetCode has to be 0");
- return new(response.ReturnCode, response.Message, default);
- }
- else
- {
- // Magic number that hashed from "Snap.Hutao"
- return new(InternalFailure, SH.FormatWebResponseRequestExceptionFormat(callerName, typeof(TData).Name), default);
- }
+ return new(response.ReturnCode, response.Message, default);
}
public virtual bool IsOk(bool showInfoBar = true, IServiceProvider? serviceProvider = null)
@@ -126,27 +75,15 @@ internal class Response
}
}
- ///
public override string ToString()
{
return SH.FormatWebResponseFormat(ReturnCode, Message);
}
}
-///
-/// Mihoyo 标准API响应
-///
-/// 数据类型
[SuppressMessage("", "SA1402")]
-[HighQuality]
-internal class Response : Response, IJsResult
+internal class Response : Response, ICommonResponse>, IJsBridgeResult
{
- ///
- /// 构造一个新的 Mihoyo 标准API响应
- ///
- /// 返回代码
- /// 消息
- /// 数据
[JsonConstructor]
public Response(int returnCode, string message, TData? data)
: base(returnCode, message)
@@ -154,18 +91,14 @@ internal class Response : Response, IJsResult
Data = data;
}
- ///
- /// 数据
- ///
[JsonPropertyName("data")]
public TData? Data { get; set; }
- ///
- /// 响应是否正常
- ///
- /// 是否显示错误信息
- /// 服务提供器
- /// 是否Ok
+ static Response ICommonResponse>.CreateDefault(int returnCode, string message)
+ {
+ return new(returnCode, message, default);
+ }
+
[MemberNotNullWhen(true, nameof(Data))]
public override bool IsOk(bool showInfoBar = true, IServiceProvider? serviceProvider = null)
{
@@ -185,28 +118,4 @@ internal class Response : Response, IJsResult
return false;
}
}
-
- public bool TryGetData([NotNullWhen(true)] out TData? data, IInfoBarService? infoBarService = null, IServiceProvider? serviceProvider = null)
- {
- if (ReturnCode == 0)
- {
- ArgumentNullException.ThrowIfNull(Data);
- data = Data;
- return true;
- }
- else
- {
- serviceProvider ??= Ioc.Default;
- infoBarService ??= serviceProvider.GetRequiredService();
- infoBarService.Error(ToString());
- data = default;
- return false;
- }
- }
-
- ///
- public string ToJson()
- {
- return JsonSerializer.Serialize(this);
- }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/ResponseExtension.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/ResponseExtension.cs
new file mode 100644
index 00000000..a88cd6ae
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/ResponseExtension.cs
@@ -0,0 +1,27 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Service.Notification;
+
+namespace Snap.Hutao.Web.Response;
+
+internal static class ResponseExtension
+{
+ public static bool TryGetData(this Response response, [NotNullWhen(true)] out TData? data, IInfoBarService? infoBarService = null, IServiceProvider? serviceProvider = null)
+ {
+ if (response.ReturnCode == 0)
+ {
+ ArgumentNullException.ThrowIfNull(response.Data);
+ data = response.Data;
+ return true;
+ }
+ else
+ {
+ serviceProvider ??= Ioc.Default;
+ infoBarService ??= serviceProvider.GetRequiredService();
+ infoBarService.Error(response.ToString());
+ data = default;
+ return false;
+ }
+ }
+}
\ No newline at end of file