CI / Go Backend (push) Canceled after 0s
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
151 lines
6.2 KiB
C#
151 lines
6.2 KiB
C#
using PCL.Core.App;
|
|
using PCL.Core.App.Localization;
|
|
using PCL.Core.Logging;
|
|
using PCL.Core.UI;
|
|
using PCL.Core.Utils.OS;
|
|
using System;
|
|
using System.Net.Http;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using PCL.Core.IO.Net.Http;
|
|
using PCL.Core.Utils;
|
|
|
|
namespace PCL.Core.Link.Natayark;
|
|
|
|
public class NaidUser
|
|
{
|
|
public int Id { get; set; }
|
|
public string? Email { get; set; }
|
|
public string? Username { get; set; }
|
|
public string? AccessToken { get; set; }
|
|
public string? RefreshToken { get; set; }
|
|
/// <summary>
|
|
/// Natayark ID 状态,1 为正常
|
|
/// </summary>
|
|
public int Status { get; set; }
|
|
public bool IsRealNamed { get; set; }
|
|
public string? LastIp { get; set; }
|
|
|
|
}
|
|
|
|
public static class NatayarkProfileManager
|
|
{
|
|
private const string LogModule = "Link";
|
|
|
|
public static NaidUser NaidProfile { get; private set; } = new();
|
|
|
|
private static Task? _getNaidData;
|
|
|
|
public static async Task GetNaidDataAsync(string token, bool isRefresh = false, bool isRetry = false, ushort port = 0)
|
|
{
|
|
if (_getNaidData is not null && !_getNaidData.IsCompleted)
|
|
{
|
|
await _getNaidData;
|
|
return;
|
|
}
|
|
_getNaidData = Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
// 获取 AccessToken 和 RefreshToken
|
|
var requestData =
|
|
$"grant_type={(isRefresh ? "refresh_token" : "authorization_code")}" +
|
|
$"&client_id={EnvironmentInterop.GetSecret("NAID_CLIENT_ID")}" +
|
|
$"&client_secret={EnvironmentInterop.GetSecret("NAID_CLIENT_SECRET")}" +
|
|
$"&{(isRefresh ? "refresh_token" : "code")}={token}" +
|
|
(isRefresh ? "" : $"&redirect_uri=http://localhost:{port}/callback");
|
|
|
|
var httpContent = new StringContent(requestData, Encoding.UTF8, "application/x-www-form-urlencoded");
|
|
|
|
using var oauthResponse = await HttpRequest
|
|
.CreatePost("https://account.naids.com/api/oauth2/token")
|
|
.WithContent(httpContent)
|
|
.SendAsync()
|
|
.ConfigureAwait(false);
|
|
oauthResponse.EnsureSuccessStatusCode();
|
|
|
|
var result = await oauthResponse.AsStringAsync().ConfigureAwait(false)
|
|
?? throw new Exception(Lang.Text("Link.Natayark.TokenFetchEmpty"));
|
|
var data = JsonCompat.ParseNode(result);
|
|
var accessToken = data?["access_token"]?.ToString();
|
|
var refreshToken = data?["refresh_token"]?.ToString();
|
|
|
|
if (data is null || accessToken is null || refreshToken is null)
|
|
throw new Exception(Lang.Text("Link.Natayark.TokenParseFailed"));
|
|
|
|
NaidProfile.AccessToken = accessToken;
|
|
NaidProfile.RefreshToken = refreshToken;
|
|
|
|
var expiresAt = data["refresh_token_expires_at"]!.ToString();
|
|
|
|
// 获取用户信息
|
|
using var userDataResponse = await HttpRequest
|
|
.Create("https://account.naids.com/api/api/user/data")
|
|
.WithBearerToken(NaidProfile.AccessToken)
|
|
.SendAsync()
|
|
.ConfigureAwait(false);
|
|
userDataResponse.EnsureSuccessStatusCode();
|
|
|
|
var receivedUserData = await userDataResponse.AsStringAsync()
|
|
?? throw new Exception(Lang.Text("Link.Natayark.UserInfoFetchEmpty"));
|
|
var userData = (JsonCompat.ParseNode(receivedUserData)?["data"])
|
|
?? throw new Exception(Lang.Text("Link.Natayark.UserInfoParseFailed"));
|
|
|
|
NaidProfile.Id = JsonCompat.ToObject<int>(userData["id"]);
|
|
NaidProfile.Username = userData["username"]?.ToString() ?? string.Empty;
|
|
NaidProfile.Email = userData["email"]?.ToString() ?? string.Empty;
|
|
NaidProfile.Status = JsonCompat.ToObject<int>(userData["status"]);
|
|
NaidProfile.IsRealNamed = JsonCompat.ToObject<bool>(userData["realname"]);
|
|
NaidProfile.LastIp = userData["last_ip"]?.ToString() ?? string.Empty;
|
|
|
|
// 保存数据
|
|
States.Link.NaidRefreshToken = NaidProfile.RefreshToken;
|
|
States.Link.NaidRefreshExpireTime = expiresAt;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (isRetry)
|
|
{
|
|
NaidProfile = new NaidUser();
|
|
States.Link.NaidRefreshToken = string.Empty;
|
|
WarnLog(Lang.Text("Tools.GameLink.Natayark.ProfileLoadFailed"));
|
|
}
|
|
else
|
|
{
|
|
if (ex.Message.Contains("invalid access token"))
|
|
{
|
|
WarnLog(Lang.Text("Tools.GameLink.Natayark.TokenInvalid"));
|
|
await Task.Delay(TimeSpan.FromMilliseconds(50)).ConfigureAwait(false); // 搁这让电脑休息半秒吗
|
|
await GetNaidDataAsync(States.Link.NaidRefreshToken, true, true).ConfigureAwait(false);
|
|
}
|
|
else if (ex.Message.Contains("invalid_grant"))
|
|
{
|
|
WarnLog(Lang.Text("Tools.GameLink.Natayark.InvalidAuthCode"));
|
|
}
|
|
else if (ex is HttpRequestException { StatusCode: System.Net.HttpStatusCode.Unauthorized })
|
|
{
|
|
NaidProfile = new NaidUser();
|
|
States.Link.NaidRefreshToken = string.Empty;
|
|
WarnLog(Lang.Text("Tools.GameLink.Natayark.AccountExpired"));
|
|
}
|
|
else
|
|
{
|
|
NaidProfile = new NaidUser();
|
|
States.Link.NaidRefreshToken = string.Empty;
|
|
WarnLog(Lang.Text("Tools.GameLink.Natayark.LoginFailed"));
|
|
}
|
|
}
|
|
throw;
|
|
|
|
void WarnLog(string msg)
|
|
{
|
|
LogWrapper.Warn(ex, LogModule, msg);
|
|
HintWrapper.Show(msg, HintTheme.Error);
|
|
}
|
|
}
|
|
});
|
|
|
|
await _getNaidData;
|
|
}
|
|
}
|