CI / Go Backend (push) Canceled after 0s
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
242 lines
8.9 KiB
C#
242 lines
8.9 KiB
C#
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
using PCL.Core.App;
|
|
using PCL.Core.App.Localization;
|
|
using PCL.Core.UI.Controls;
|
|
using PCL.Core.Utils;
|
|
using PCL.Core.IO.Net.Http;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace PCL;
|
|
|
|
public partial class MyMsgLogin
|
|
{
|
|
private readonly JsonObject data;
|
|
private string deviceCode; // 用于轮询的设备代码
|
|
private string oAuthUrl = ""; // OAuth 轮询验证地址
|
|
private string userCode; // 需要用户在网页上输入的设备代码
|
|
private string website; // 验证网页的网址
|
|
private Task? workingThread;
|
|
|
|
public MyMsgLogin()
|
|
{
|
|
InitializeComponent();
|
|
// Handles
|
|
Loaded += Load;
|
|
Btn1.Click += Btn1_Click;
|
|
Btn3.Click += Btn3_Click;
|
|
PanBorder.MouseLeftButtonDown += Drag;
|
|
LabTitle.MouseLeftButtonDown += Drag;
|
|
}
|
|
|
|
private void Finished(object result)
|
|
{
|
|
if (myConverter.IsExited)
|
|
return;
|
|
myConverter.IsExited = true;
|
|
myConverter.Result = result;
|
|
ModBase.RunInUi(Close);
|
|
Thread.Sleep(200);
|
|
ModMain.frmMain.ShowWindowToTop();
|
|
}
|
|
|
|
private void Init()
|
|
{
|
|
userCode = (string)data["user_code"];
|
|
deviceCode = (string)data["device_code"];
|
|
ModBase.ClipboardSet(deviceCode);
|
|
if (data["verification_uri_complete"] is not null)
|
|
{
|
|
website = (string)data["verification_uri_complete"];
|
|
LabCaption.Text = Lang.Text("Launch.Account.LoginDialog.MicrosoftInstructions.WithAutoFill", userCode, website);
|
|
}
|
|
else
|
|
{
|
|
website = (string)data["verification_uri"];
|
|
LabCaption.Text = Lang.Text("Launch.Account.LoginDialog.MicrosoftInstructions", userCode, website);
|
|
}
|
|
|
|
// 设置 UI
|
|
LabTitle.Text = Lang.Text("Launch.Account.LoginDialog.MinecraftLogin");
|
|
CustomEventService.SetEventData(Btn1, website);
|
|
CustomEventService.SetEventData(Btn2, userCode);
|
|
// 启动工作线程
|
|
workingThread = WorkThreadAsync();
|
|
}
|
|
|
|
private record ErrorBody(
|
|
[property: JsonPropertyName("error")] string Error,
|
|
[property: JsonPropertyName("error_description")] string Desc);
|
|
|
|
private async Task WorkThreadAsync()
|
|
{
|
|
await Task.Delay(2000).ConfigureAwait(false);
|
|
if (myConverter.IsExited)
|
|
return;
|
|
ModBase.OpenWebsite(website);
|
|
ModBase.ClipboardSet(userCode);
|
|
var delayTime = (data["interval"].ToObject<int>() - 1) * 1000;
|
|
// 轮询
|
|
var unknownFailureCount = 0;
|
|
while (!myConverter.IsExited)
|
|
{
|
|
try
|
|
{
|
|
var bodyData = $"grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id={Secrets.MSOAuthClientId}&device_code={deviceCode}&scope=XboxLive.signin%20offline_access";
|
|
using var result = await HttpRequest
|
|
.Create("https://login.microsoftonline.com/consumers/oauth2/v2.0/token")
|
|
.WithFormContent(bodyData)
|
|
.SendAsync(enableLogging: false)
|
|
.ConfigureAwait(false);
|
|
if (!result.IsSuccess)
|
|
{
|
|
var error = await result.AsJsonAsync<ErrorBody>()
|
|
.ConfigureAwait(false);
|
|
switch(error?.Error)
|
|
{
|
|
case "authorization_pending":
|
|
{
|
|
await Task.Delay(delayTime)
|
|
.ConfigureAwait(false);
|
|
continue;
|
|
}
|
|
default:
|
|
{
|
|
throw new Exception(error?.Error ?? "Unable to get body");
|
|
}
|
|
}
|
|
}
|
|
// 获取结果
|
|
var ctx = await result.AsStringAsync().ConfigureAwait(false);
|
|
var resultJson = (JsonObject)ModBase.GetJson(ctx);
|
|
ModProfile.ProfileLog($"令牌过期时间:{resultJson["expires_in"]} 秒");
|
|
HintService.Hint(Lang.Text("Launch.Account.LoginDialog.Success"), HintType.Success);
|
|
Finished(new[] { resultJson["access_token"].ToString(), resultJson["refresh_token"].ToString() });
|
|
return;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (unknownFailureCount <= 2)
|
|
{
|
|
unknownFailureCount += 1;
|
|
ModBase.Log(ex, $"正版验证轮询第 {unknownFailureCount} 次失败");
|
|
ModBase.Log(ex.Message);
|
|
await Task.Delay(2000).ConfigureAwait(false);
|
|
}
|
|
else
|
|
{
|
|
Finished(new Exception(Lang.Text("Launch.Account.LoginDialog.PollingFailed"), ex));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#region 弹窗
|
|
|
|
private readonly ModMain.MyMsgBoxConverter myConverter;
|
|
private readonly int uuid = ModBase.GetUuid();
|
|
|
|
public MyMsgLogin(ModMain.MyMsgBoxConverter converter)
|
|
{
|
|
try
|
|
{
|
|
InitializeComponent();
|
|
Btn1.Name += ModBase.GetUuid();
|
|
Btn2.Name += ModBase.GetUuid();
|
|
Btn3.Name += ModBase.GetUuid();
|
|
myConverter = converter;
|
|
ShapeLine.StrokeThickness = ModBase.GetWPFSize(1d);
|
|
data = (JsonObject)converter.Content;
|
|
oAuthUrl = converter.AuthUrl?.ToString() ?? "";
|
|
Init();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ModBase.Log(
|
|
ex,
|
|
Lang.Text("Launch.Account.LoginDialog.Error.Init"),
|
|
ModBase.LogLevel.Hint,
|
|
userSummary: Lang.Text("Launch.Account.LoginDialog.Error.Init"));
|
|
}
|
|
|
|
Loaded += Load;
|
|
}
|
|
|
|
private void Load(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// 动画
|
|
Opacity = 0d;
|
|
ModAnimation.AniStart(
|
|
ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty,
|
|
(myConverter.IsWarn
|
|
? new ModBase.MyColor(140d, 80d, 0d, 0d)
|
|
: new ModBase.MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200),
|
|
"PanMsgBackground Background");
|
|
ModAnimation.AniStart(
|
|
new[]
|
|
{
|
|
ModAnimation.AaOpacity(this, 1d, 120, 60),
|
|
ModAnimation.AaDouble(i => TransformPos.Y += (double)i,
|
|
-TransformPos.Y, 300, 60, new ModAnimation.AniEaseOutBack(ModAnimation.AniEasePower.Weak)),
|
|
ModAnimation.AaDouble(i => TransformRotate.Angle += (double)i,
|
|
-TransformRotate.Angle, 300, 60,
|
|
new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))
|
|
}, "MyMsgBox " + uuid);
|
|
// 记录日志
|
|
ModBase.Log($"[Control] 正版验证弹窗:{LabTitle.Text}\r\n{LabCaption.Text}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ModBase.Log(
|
|
ex,
|
|
Lang.Text("Launch.Account.LoginDialog.Error.Load"),
|
|
ModBase.LogLevel.Hint,
|
|
userSummary: Lang.Text("Launch.Account.LoginDialog.Error.Load"));
|
|
}
|
|
}
|
|
|
|
private void Close()
|
|
{
|
|
// 动画
|
|
ModAnimation.AniStart(new[]
|
|
{
|
|
ModAnimation.AaCode(() =>
|
|
{
|
|
if (!ModMain.WaitingMyMsgBox.Any())
|
|
ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground,
|
|
BlurBorder.BackgroundProperty,
|
|
new ModBase.MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200,
|
|
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)));
|
|
}, 30),
|
|
ModAnimation.AaOpacity(this, -Opacity, 80, 20),
|
|
ModAnimation.AaDouble(i => TransformPos.Y += (double)i, 20d - TransformPos.Y,
|
|
150, 0, new ModAnimation.AniEaseOutFluent()),
|
|
ModAnimation.AaDouble(i => TransformRotate.Angle += (double)i,
|
|
6d - TransformRotate.Angle, 150, 0, new ModAnimation.AniEaseInFluent(ModAnimation.AniEasePower.Weak)),
|
|
ModAnimation.AaCode(() => ((Grid)Parent).Children.Remove(this), after: true)
|
|
}, "MyMsgBox " + uuid);
|
|
}
|
|
|
|
// 实现回车和 Esc 的接口(#4857)
|
|
public void Btn1_Click(object sender, MouseButtonEventArgs e)
|
|
{
|
|
}
|
|
|
|
public void Btn3_Click(object sender, MouseButtonEventArgs e)
|
|
{
|
|
Finished(new ThreadInterruptedException());
|
|
}
|
|
|
|
private void Drag(object sender, MouseButtonEventArgs e)
|
|
{
|
|
// On Error Resume Next
|
|
if (e.GetPosition(ShapeLine).Y <= 2d)
|
|
ModMain.frmMain.DragMove();
|
|
}
|
|
|
|
#endregion
|
|
} |