diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/IQrCodeFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/IQrCodeFactory.cs
index 3381dc01..0ab732fa 100644
--- a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/IQrCodeFactory.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/IQrCodeFactory.cs
@@ -5,5 +5,5 @@ namespace Snap.Hutao.Factory.QrCode;
internal interface IQrCodeFactory
{
- byte[] CreateByteArr(string source);
+ byte[] CreateQrCodeByteArray(string source);
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/QrCodeFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/QrCodeFactory.cs
index b16d0d29..4ee567fc 100644
--- a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/QrCodeFactory.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/QrCodeFactory.cs
@@ -9,7 +9,7 @@ namespace Snap.Hutao.Factory.QrCode;
[Injection(InjectAs.Singleton, typeof(IQrCodeFactory))]
internal class QrCodeFactory : IQrCodeFactory
{
- public byte[] CreateByteArr(string source)
+ public byte[] CreateQrCodeByteArray(string source)
{
using (QRCodeGenerator generator = new())
{
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml
index bc8e44cb..177a814c 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml
@@ -5,7 +5,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
- xmlns:shvd="using:Snap.Hutao.View.Dialog"
Title="{shcm:ResourceString Name=ViewDialogQrCodeTitle}"
CloseButtonText="{shcm:ResourceString Name=ContentDialogCancelCloseButtonText}"
DefaultButton="Close"
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml.cs
index e14bf962..235f766b 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml.cs
@@ -3,10 +3,10 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Snap.Hutao.Factory.QrCode;
using Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
+using Snap.Hutao.Web.Hoyolab.Passport;
using Snap.Hutao.Web.Response;
using System.IO;
using System.Text.RegularExpressions;
@@ -20,10 +20,10 @@ namespace Snap.Hutao.View.Dialog;
internal sealed partial class QrCodeDialog : ContentDialog
{
private readonly ITaskContext taskContext;
- private readonly QrCodeClient qrCodeClient;
+ private readonly PassportClient2 passportClient2;
private readonly IQrCodeFactory qrCodeFactory;
- private QrCodeAccount? account;
+ private UidGameToken? account;
///
/// 构造一个新的扫描二维码对话框
@@ -34,26 +34,27 @@ internal sealed partial class QrCodeDialog : ContentDialog
InitializeComponent();
taskContext = serviceProvider.GetRequiredService();
- qrCodeClient = serviceProvider.GetRequiredService();
+ passportClient2 = serviceProvider.GetRequiredService();
qrCodeFactory = serviceProvider.GetRequiredService();
- Initialize().SafeForget();
+ FetchQrCodeAsync().SafeForget();
}
///
/// 获取登录的用户
///
/// QrCodeAccount
- public async ValueTask> GetAccountAsync()
+ [SuppressMessage("", "SH007")]
+ public async ValueTask> GetAccountAsync()
{
await taskContext.SwitchToMainThreadAsync();
ContentDialogResult result = await ShowAsync();
return new(account is not null, account!);
}
- private async ValueTask Initialize()
+ private async ValueTask FetchQrCodeAsync()
{
- Response fetch = await qrCodeClient.PostQrCodeFetchAsync().ConfigureAwait(false);
+ Response fetch = await passportClient2.PostQrCodeFetchAsync().ConfigureAwait(false);
if (fetch.IsOk())
{
string url = Regex.Unescape(fetch.Data.Url);
@@ -61,7 +62,7 @@ internal sealed partial class QrCodeDialog : ContentDialog
await taskContext.SwitchToMainThreadAsync();
BitmapImage bitmap = new();
- await bitmap.SetSourceAsync(new MemoryStream(qrCodeFactory.CreateByteArr(url)).AsRandomAccessStream());
+ await bitmap.SetSourceAsync(new MemoryStream(qrCodeFactory.CreateQrCodeByteArray(url)).AsRandomAccessStream());
ImageView.Source = bitmap;
if (bitmap is BitmapSource { PixelHeight: > 0, PixelWidth: > 0 })
@@ -70,37 +71,41 @@ internal sealed partial class QrCodeDialog : ContentDialog
}
await taskContext.SwitchToBackgroundAsync();
+ await CheckStatusAsync(ticket).ConfigureAwait(false);
+ }
+ }
- using (PeriodicTimer timer = new(TimeSpan.FromSeconds(3)))
+ private async ValueTask CheckStatusAsync(string ticket)
+ {
+ using (PeriodicTimer timer = new(TimeSpan.FromSeconds(3)))
+ {
+ while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
{
- while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
+ Response query = await passportClient2.PostQrCodeQueryAsync(ticket).ConfigureAwait(false);
+ if (query.IsOk(false))
{
- Response query = await qrCodeClient.PostQrCodeQueryAsync(ticket).ConfigureAwait(false);
- if (query.IsOk(false))
+ switch (query.Data.Stat)
{
- switch (query.Data.Stat)
- {
- case QrCodeQueryStatus.INIT:
- case QrCodeQueryStatus.SCANNED:
- break; // @switch
- case QrCodeQueryStatus.CONFIRMED:
- if (query.Data.Payload.Proto == QrCodeQueryPayload.ACCOUNT)
- {
- account = JsonSerializer.Deserialize(query.Data.Payload.Raw);
- await taskContext.SwitchToMainThreadAsync();
- Hide();
- return;
- }
+ case GameLoginResultStatus.Init:
+ case GameLoginResultStatus.Scanned:
+ break; // @switch
+ case GameLoginResultStatus.Confirmed:
+ if (query.Data.Payload.Proto == GameLoginResultPayload.ACCOUNT)
+ {
+ account = JsonSerializer.Deserialize(query.Data.Payload.Raw);
+ await taskContext.SwitchToMainThreadAsync();
+ Hide();
+ return; // Stop timer
+ }
- break; // @switch
- }
- }
- else if (query.ReturnCode == (int)KnownReturnCode.QrCodeExpired)
- {
- Initialize().SafeForget();
- break; // @while
+ break; // @switch
}
}
+ else if (query.ReturnCode == (int)KnownReturnCode.QrCodeExpired)
+ {
+ FetchQrCodeAsync().SafeForget();
+ break; // @while
+ }
}
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
index fe59a7b2..d58233b3 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
@@ -158,7 +158,7 @@
Width="{StaticResource LargeAppBarButtonWidth}"
MaxWidth="{StaticResource LargeAppBarButtonWidth}"
Margin="2,-4"
- Command="{Binding LoginQrCodeCommand}"
+ Command="{Binding LoginByQrCodeCommand}"
Icon="{shcm:FontIcon Glyph={StaticResource FontIconContentQrCode}}"
Label="{shcm:ResourceString Name=ViewUserCookieOperationLoginQrCodeAction}"/>
().ConfigureAwait(false);
- ValueResult result = await dialog.GetAccountAsync().ConfigureAwait(false);
+ ValueResult result = await dialog.GetAccountAsync().ConfigureAwait(false);
- if (result.TryGetValue(out QrCodeAccount account))
+ if (result.TryGetValue(out UidGameToken account))
{
Response gameTokenResp = await sessionAppClient.PostSTokenByGameTokenAsync(account).ConfigureAwait(false);
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
index e19db0fc..95032e1f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
@@ -16,15 +16,6 @@ namespace Snap.Hutao.Web;
[SuppressMessage("", "SA1124")]
internal static class ApiEndpoints
{
- #region ApiTakumiAccountSessionApp
-
- ///
- /// 通过 GameToken 获取 SToken (V2)
- ///
- public const string STokenByGameToken = $"{ApiTakumiAccountSessionApp}/getTokenByGameToken";
-
- #endregion
-
#region ApiTakumiAuthApi
///
@@ -304,6 +295,11 @@ internal static class ApiEndpoints
///
public const string AccountGetLTokenBySToken = $"{PassportApiAuthApi}/getLTokenBySToken";
+ ///
+ /// 通过GameToken获取V2SToken
+ ///
+ public const string AccountGetSTokenByGameToken = $"{PassportApi}/account/ma-cn-session/app/getTokenByGameToken";
+
///
/// 获取V2SToken
///
@@ -378,7 +374,6 @@ internal static class ApiEndpoints
#region Hosts | Queries
private const string ApiTakumi = "https://api-takumi.mihoyo.com";
private const string ApiTakumiAuthApi = $"{ApiTakumi}/auth/api";
- private const string ApiTakumiAccountSessionApp = $"{ApiTakumi}/account/ma-cn-session/app";
private const string ApiTaKumiBindingApi = $"{ApiTakumi}/binding/api";
private const string ApiTakumiCardApi = $"{ApiTakumiRecord}/game_record/app/card/api";
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeClient.cs
deleted file mode 100644
index 7c5d5020..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeClient.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
-using Snap.Hutao.Web.Request.Builder;
-using Snap.Hutao.Web.Request.Builder.Abstraction;
-using Snap.Hutao.Web.Response;
-using System.Net.Http;
-
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
-
-[HighQuality]
-[ConstructorGenerated(ResolveHttpClient = true)]
-[HttpClient(HttpClientConfiguration.Default)]
-internal sealed partial class QrCodeClient
-{
- private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
- private readonly ILogger logger;
- private readonly HttpClient httpClient;
-
- private readonly string device = Core.Random.GetLetterAndNumberString(64);
-
- ///
- /// 异步获取扫码链接
- ///
- /// 取消令牌
- /// login url
- public async ValueTask> PostQrCodeFetchAsync(CancellationToken token = default)
- {
- QrCodeFetchOptions options = new(4, device);
-
- HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
- .SetRequestUri(ApiEndpoints.QrCodeFetch)
- .PostJson(options);
-
- Response? resp = await builder
- .TryCatchSendAsync>(httpClient, logger, token)
- .ConfigureAwait(false);
-
- return Response.Response.DefaultIfNull(resp);
- }
-
- ///
- /// 异步获取扫码状态
- ///
- /// 扫码链接中的ticket
- /// 取消令牌/param>
- /// 扫码状态
- public async ValueTask> PostQrCodeQueryAsync(string ticket, CancellationToken token = default)
- {
- QrCodeQueryOptions options = new(4, device, ticket);
-
- HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
- .SetRequestUri(ApiEndpoints.QrCodeQuery)
- .PostJson(options);
-
- Response? resp = await builder
- .TryCatchSendAsync>(httpClient, logger, token)
- .ConfigureAwait(false);
-
- return Response.Response.DefaultIfNull(resp);
- }
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeFetchOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeFetchOptions.cs
deleted file mode 100644
index df689141..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeFetchOptions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
-
-[HighQuality]
-internal sealed class QrCodeFetchOptions
-{
- public QrCodeFetchOptions(int appId, string device)
- {
- AppId = appId;
- Device = device;
- }
-
- [JsonPropertyName("app_id")]
- public int AppId { get; set; }
-
- [JsonPropertyName("device")]
- public string Device { get; set; } = default!;
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQuery.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQuery.cs
deleted file mode 100644
index 3091ec4e..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQuery.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
-
-[HighQuality]
-internal sealed class QrCodeQuery
-{
- [JsonPropertyName("stat")]
- public string Stat { get; set; } = default!;
-
- [JsonPropertyName("payload")]
- public QrCodeQueryPayload Payload { get; set; } = default!;
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryOptions.cs
deleted file mode 100644
index 9f2806d8..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryOptions.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
-
-[HighQuality]
-internal sealed class QrCodeQueryOptions
-{
- public QrCodeQueryOptions(int appId, string device, string ticket)
- {
- AppId = appId;
- Device = device;
- Ticket = ticket;
- }
-
- [JsonPropertyName("app_id")]
- public int AppId { get; set; }
-
- [JsonPropertyName("device")]
- public string Device { get; set; } = default!;
-
- [JsonPropertyName("ticket")]
- public string Ticket { get; set; } = default!;
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryStatus.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryStatus.cs
deleted file mode 100644
index ce0e9813..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryStatus.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
-
-///
-/// 扫码状态
-///
-internal sealed partial class QrCodeQueryStatus
-{
- public const string INIT = "Init";
- public const string SCANNED = "Scanned";
- public const string CONFIRMED = "Confirmed";
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs
index f5e391a6..4610b2c9 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs
@@ -37,6 +37,11 @@ internal sealed class HoyolabOptions : IOptions
///
public static string DeviceId { get; } = Guid.NewGuid().ToString();
+ ///
+ /// 扫码登录设备Id
+ ///
+ public static string Device { get; } = Core.Random.GetLetterAndNumberString(64);
+
///
/// 盐
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestOptions.cs
new file mode 100644
index 00000000..fb3b77a4
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestOptions.cs
@@ -0,0 +1,26 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Hoyolab.Passport;
+
+///
+/// 扫码登录请求配置
+///
+[HighQuality]
+internal sealed class GameLoginRequestOptions
+{
+ [JsonPropertyName("app_id")]
+ public int AppId { get; set; }
+
+ [JsonPropertyName("device")]
+ public string Device { get; set; } = default!;
+
+ public static GameLoginRequestOptions Create(int appId, string device)
+ {
+ return new GameLoginRequestOptions
+ {
+ AppId = appId,
+ Device = device,
+ };
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeFetch.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestResult.cs
similarity index 56%
rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeFetch.cs
rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestResult.cs
index bac70add..13f067b2 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeFetch.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestResult.cs
@@ -1,10 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
+namespace Snap.Hutao.Web.Hoyolab.Passport;
+///
+/// 扫码登录请求结果
+///
[HighQuality]
-internal sealed class QrCodeFetch
+internal sealed class GameLoginRequestResult
{
[JsonPropertyName("url")]
public string Url { get; set; } = default!;
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs
new file mode 100644
index 00000000..c3757f69
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs
@@ -0,0 +1,21 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Core.Json.Annotation;
+using Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
+
+namespace Snap.Hutao.Web.Hoyolab.Passport;
+
+///
+/// 扫码登录结果
+///
+[HighQuality]
+internal sealed class GameLoginResult
+{
+ [JsonPropertyName("stat")]
+ [JsonEnum(JsonSerializeType.String)]
+ public GameLoginResultStatus Stat { get; set; } = default!;
+
+ [JsonPropertyName("payload")]
+ public GameLoginResultPayload Payload { get; set; } = default!;
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultOptions.cs
new file mode 100644
index 00000000..d5f17cd6
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultOptions.cs
@@ -0,0 +1,30 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Hoyolab.Passport;
+
+///
+/// 扫码登录结果请求配置
+///
+[HighQuality]
+internal sealed class GameLoginResultOptions
+{
+ [JsonPropertyName("app_id")]
+ public int AppId { get; set; }
+
+ [JsonPropertyName("device")]
+ public string Device { get; set; } = default!;
+
+ [JsonPropertyName("ticket")]
+ public string Ticket { get; set; } = default!;
+
+ public static GameLoginResultOptions Create(int appId, string device, string ticket)
+ {
+ return new GameLoginResultOptions
+ {
+ AppId = appId,
+ Device = device,
+ Ticket = ticket,
+ };
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryPayload.Constant.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.ProtoTypes.cs
similarity index 76%
rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryPayload.Constant.cs
rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.ProtoTypes.cs
index d71edfd4..179b7501 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryPayload.Constant.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.ProtoTypes.cs
@@ -4,9 +4,9 @@
namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
///
-/// Proto 常量
+/// Proto 类型常量
///
-internal sealed partial class QrCodeQueryPayload
+internal sealed partial class GameLoginResultPayload
{
public const string ACCOUNT = "Account";
public const string RAW = "Raw";
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryPayload.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.cs
similarity index 77%
rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryPayload.cs
rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.cs
index e66b64ba..8d7cd653 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeQueryPayload.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.cs
@@ -3,8 +3,11 @@
namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
+///
+/// 扫码登录结果Payload
+///
[HighQuality]
-internal sealed partial class QrCodeQueryPayload
+internal sealed partial class GameLoginResultPayload
{
[JsonPropertyName("proto")]
public string Proto { get; set; } = default!;
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultStatus.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultStatus.cs
new file mode 100644
index 00000000..9f95988f
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultStatus.cs
@@ -0,0 +1,14 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Hoyolab.Passport;
+
+///
+/// 扫码状态
+///
+internal enum GameLoginResultStatus
+{
+ Init,
+ Scanned,
+ Confirmed,
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
index f6e3713f..be261a77 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
@@ -68,6 +68,47 @@ internal sealed partial class PassportClient2
return Response.Response.DefaultIfNull(resp);
}
+ ///
+ /// 异步获取扫码链接
+ ///
+ /// 取消令牌
+ /// 二维码原始链接
+ public async ValueTask> PostQrCodeFetchAsync(CancellationToken token = default)
+ {
+ GameLoginRequestOptions options = GameLoginRequestOptions.Create(4, HoyolabOptions.Device);
+
+ HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
+ .SetRequestUri(ApiEndpoints.QrCodeFetch)
+ .PostJson(options);
+
+ Response? resp = await builder
+ .TryCatchSendAsync>(httpClient, logger, token)
+ .ConfigureAwait(false);
+
+ return Response.Response.DefaultIfNull(resp);
+ }
+
+ ///
+ /// 异步获取扫码状态
+ ///
+ /// 扫码链接中的ticket
+ /// 取消令牌
+ /// 扫码结果
+ public async ValueTask> PostQrCodeQueryAsync(string ticket, CancellationToken token = default)
+ {
+ GameLoginResultOptions options = GameLoginResultOptions.Create(4, HoyolabOptions.Device, ticket);
+
+ HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
+ .SetRequestUri(ApiEndpoints.QrCodeQuery)
+ .PostJson(options);
+
+ Response? resp = await builder
+ .TryCatchSendAsync>(httpClient, logger, token)
+ .ConfigureAwait(false);
+
+ return Response.Response.DefaultIfNull(resp);
+ }
+
private class Timestamp
{
[JsonPropertyName("t")]
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeAccount.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UidGameToken.cs
similarity index 63%
rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeAccount.cs
rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UidGameToken.cs
index 9c48cd45..7f2ffc47 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/QrCode/QrCodeAccount.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UidGameToken.cs
@@ -1,13 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
+namespace Snap.Hutao.Web.Hoyolab.Passport;
[HighQuality]
-internal sealed class QrCodeAccount
+internal sealed class UidGameToken
{
[JsonPropertyName("uid")]
- public string Stuid { get; set; } = default!;
+ public string Uid { get; set; } = default!;
[JsonPropertyName("token")]
public string GameToken { get; set; } = default!;
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/SessionAppClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/SessionAppClient.cs
index 6cd5b0bf..57f1c63d 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/SessionAppClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/SessionAppClient.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
-using Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
using Snap.Hutao.Web.Hoyolab.Passport;
using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
@@ -27,16 +26,16 @@ internal sealed partial class SessionAppClient
/// 扫码获得的账户信息
/// 取消令牌
/// 登录结果
- public async ValueTask> PostSTokenByGameTokenAsync(QrCodeAccount account, CancellationToken token = default)
+ public async ValueTask> PostSTokenByGameTokenAsync(UidGameToken account, CancellationToken token = default)
{
GameTokenWrapper wrapper = new()
{
- Stuid = int.Parse(account.Stuid, CultureInfo.CurrentCulture),
+ Stuid = int.Parse(account.Uid, CultureInfo.CurrentCulture),
GameToken = account.GameToken,
};
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
- .SetRequestUri(ApiEndpoints.STokenByGameToken)
+ .SetRequestUri(ApiEndpoints.AccountGetSTokenByGameToken)
.PostJson(wrapper);
Response? resp = await builder
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs
index d1f701b1..5725680a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs
@@ -84,6 +84,11 @@ internal enum KnownReturnCode
///
AppIdError = -109,
+ ///
+ /// 二维码已过期
+ ///
+ QrCodeExpired = -106,
+
///
/// 验证密钥过期
///
@@ -138,9 +143,4 @@ internal enum KnownReturnCode
/// 实时便笺
///
CODE10104 = 10104,
-
- ///
- /// 二维码已过期
- ///
- QrCodeExpired = -106,
}