XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

HaloPixelToolBox

【WinUI3】基于USB HID通讯的花再音响工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using HaloPixelToolBox.Backend.Profiles.CacheProfiles;
using HaloPixelToolBox.Backend.Profiles.CrossVersionProfiles;
using HaloPixelToolBox.Core.Models.User;
using HaloPixelToolBox.Core.Utilities;
using System.Net;
using XFEExtension.NetCore.ServerInteractive.Models.RequesterModels;

namespace HaloPixelToolBox.Backend.Utilities;

/// <summary>
/// 统一维护管理端登录状态,并负责启动时恢复或重新创建管理员会话。
/// </summary>
public static class AdministratorSessionManager
{
    private static readonly SemaphoreSlim s_authenticationLock = new(1, 1);

    public static event EventHandler? StateChanged;

    public static MyUserFaceInfo? CurrentUser { get; private set; }

    public static bool IsLoggedIn { get; private set; }

    public static bool IsBusy { get; private set; }

    public static string StatusText { get; private set; } = "正在准备自动登录...";

    public static string DisplayName => CurrentUser?.NickName ?? (IsLoggedIn ? CacheProfile.Account : "未登录");

    /// <summary>
    /// 优先恢复现有会话;会话失效时,使用本机保存的账号密码自动重新登录。
    /// </summary>
    public static async Task<bool> InitializeAsync(bool forceReconnect = false)
    {
        await s_authenticationLock.WaitAsync();
        try
        {
            if (IsLoggedIn && !forceReconnect)
                return true;

            SetBusy(true, forceReconnect ? "正在重新连接服务器..." : "正在自动登录...");
            if (!await ConnectAsync(forceReconnect))
            {
                SetLoggedOut("服务器连接失败,请在设置中检查服务器地址");
                return false;
            }

            if (!string.IsNullOrWhiteSpace(CacheProfile.Session))
            {
                DataManager.ClientRequester.Session = CacheProfile.Session;
                var restoredUser = await RestoreSessionCoreAsync();
                if (restoredUser is not null)
                {
                    CompleteLogin(restoredUser, CacheProfile.Session, "已自动恢复登录");
                    return true;
                }

                ClearSession();
                StatusText = "登录会话已过期,正在使用保存的凭据重新登录...";
                NotifyStateChanged();
            }

            if (string.IsNullOrWhiteSpace(CacheProfile.Account) || string.IsNullOrWhiteSpace(CacheProfile.Password))
            {
                SetLoggedOut("请输入管理员账号和密码,成功后将自动登录");
                return false;
            }

            return await LoginCoreAsync(CacheProfile.Account, CacheProfile.Password, "已自动登录");
        }
        catch (Exception ex)
        {
            SetLoggedOut($"自动登录失败:{ex.Message}");
            return false;
        }
        finally
        {
            SetBusy(false);
            s_authenticationLock.Release();
        }
    }

    /// <summary>
    /// 使用用户输入的管理员凭据登录,并在成功后保存用于下次自动登录。
    /// </summary>
    public static async Task<bool> LoginAsync(string account, string password)
    {
        account = account.Trim();
        if (string.IsNullOrWhiteSpace(account) || string.IsNullOrWhiteSpace(password))
        {
            SetLoggedOut("请输入管理员账号和密码");
            return false;
        }

        await s_authenticationLock.WaitAsync();
        try
        {
            SetBusy(true, "正在登录管理员账号...");
            if (!await ConnectAsync(true))
            {
                SetLoggedOut("服务器连接失败,请在设置中检查服务器地址");
                return false;
            }

            return await LoginCoreAsync(account, password, "已登录");
        }
        catch (Exception ex)
        {
            SetLoggedOut($"登录失败:{ex.Message}");
            return false;
        }
        finally
        {
            SetBusy(false);
            s_authenticationLock.Release();
        }
    }

    /// <summary>
    /// 退出管理端,并清除本机保存的密码,防止随后再次自动登录。
    /// </summary>
    public static async Task LogoutAsync()
    {
        await s_authenticationLock.WaitAsync();
        try
        {
            ClearSession();
            CacheProfile.Password = string.Empty;
            SetLoggedOut("已退出登录;下次需要重新输入密码");
        }
        finally
        {
            s_authenticationLock.Release();
        }
    }

    private static async Task<bool> ConnectAsync(bool forceReconnect)
    {
        var serverAddress = SystemProfile.ServerAddress.Trim();
        if (!Uri.TryCreate(serverAddress, UriKind.Absolute, out var uri) ||
            (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
        {
            StatusText = "服务器地址无效,请输入完整的 HTTP 或 HTTPS 地址";
            NotifyStateChanged();
            return false;
        }

        return await DataManager.InitializeAsync([serverAddress], forceReconnect);
    }

    private static async Task<MyUserFaceInfo?> RestoreSessionCoreAsync()
    {
        var response = await DataManager.ClientRequester.Request<MyUserFaceInfo>("relogin");
        return response.StatusCode == HttpStatusCode.OK && IsAdministrator(response.Result)
            ? response.Result
            : null;
    }

    private static async Task<bool> LoginCoreAsync(string account, string password, string successMessage)
    {
        ClearSession();
        var response = await DataManager.ClientRequester.Request<UserLoginResult<MyUserFaceInfo>>("login", account, password);
        if (response.StatusCode != HttpStatusCode.OK || response.Result?.UserInfo is null)
        {
            SetLoggedOut("登录失败,请检查账号或密码");
            return false;
        }

        if (!IsAdministrator(response.Result.UserInfo))
        {
            ClearSession();
            SetLoggedOut("该账号没有管理员权限");
            return false;
        }

        CacheProfile.Account = account;
        CacheProfile.Password = password;
        CompleteLogin(response.Result.UserInfo, response.Result.Session, successMessage);
        return true;
    }

    private static bool IsAdministrator(MyUserFaceInfo? user) =>
        user is not null && user.PermissionLevel >= (int)UserRole.管理员;

    private static void CompleteLogin(MyUserFaceInfo user, string session, string successMessage)
    {
        DataManager.ClientRequester.Session = session;
        CacheProfile.Session = session;
        CurrentUser = user;
        IsLoggedIn = true;
        StatusText = $"{successMessage}:{user.NickName}({(UserRole)user.PermissionLevel})";
        NotifyStateChanged();
    }

    private static void ClearSession()
    {
        DataManager.ClientRequester.Session = string.Empty;
        CacheProfile.Session = string.Empty;
        CurrentUser = null;
        IsLoggedIn = false;
    }

    private static void SetLoggedOut(string statusText)
    {
        CurrentUser = null;
        IsLoggedIn = false;
        StatusText = statusText;
        NotifyStateChanged();
    }

    private static void SetBusy(bool isBusy, string? statusText = null)
    {
        IsBusy = isBusy;
        if (statusText is not null)
            StatusText = statusText;
        NotifyStateChanged();
    }

    private static void NotifyStateChanged() => StateChanged?.Invoke(null, EventArgs.Empty);
}