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