using System; using System.Collections.Generic; using System.Linq; using Aitex.Core.RT.Event; using Aitex.Core.Util; namespace Aitex.Core.Account; /// /// 登录凭据管理器。 /// public class CredentialManager : Singleton { #region Variables private readonly object _syncRoot = new(); private readonly Dictionary _dictLoginCredentials = new (); private readonly PeriodicJob _threadMonitorCred; private bool _isInitialized; private int _maxCredentialAllowed; #endregion #region Constructors /// /// 登录凭据管理的构造函数。 /// public CredentialManager() { _threadMonitorCred = new(1000, OnTimer, "CredentialAliveMonitorThread", true, true); } #endregion #region Properties /// /// 返回当前凭据管理器是否支持多用户登录。 /// public bool IsSupportMultiUserLogin => _maxCredentialAllowed > 1; /// /// 返回已登录的凭据。 /// public IReadOnlyDictionary Credentials => _dictLoginCredentials; #endregion #region Methods /// /// 初始化登录凭据管理器。 /// /// 是否支持多用户同时登录。 public void Initialize(bool isSupportMultiUsersLogin) { if (_isInitialized) throw new InvalidOperationException($"{nameof(CredentialManager)} has been initialized."); _isInitialized = true; _maxCredentialAllowed = isSupportMultiUsersLogin ? int.MaxValue : 1; } private bool OnTimer() { lock (_syncRoot) { foreach (var kvp in _dictLoginCredentials) { var cred = kvp.Value; if ((DateTime.Now - cred.LastAliveTime).TotalSeconds > 60) { // 如果当前凭据超过60s未激活一次,表示客户端可能已经离线,移除 cred.State = CredentialState.Expired; EV.PostLoginBySameUser(cred); } } } return true; } /// /// 检查指定的用户名是否已经登录。 /// /// /// internal bool CheckHasLoggedIn(string userName) { lock (_syncRoot) { return _dictLoginCredentials.Values.FirstOrDefault(x => x.AccountInfo.LoginName == userName) != null; } } /// /// 检查指定令牌的登录凭据是否存在。 /// /// /// internal bool CheckHasLoggedInByToken(string token) { lock (_syncRoot) { return _dictLoginCredentials.ContainsKey(token); } } /// /// 报告客户端处于活动状态。 /// /// 客户端登录凭据令牌。 /// public CredentialKeepAliveResults KeepAlive(string token) { lock (_syncRoot) { if (_dictLoginCredentials.TryGetValue(token, out var cred)) { if (cred.State == CredentialState.Expired) return CredentialKeepAliveResults.Expired; cred.LastAliveTime = DateTime.Now; // 刷新时间 return CredentialKeepAliveResults.Alive; } return CredentialKeepAliveResults.NotFound; } } /// /// 将指定的凭据加入字典。 /// /// /// public void Add(Credential cred) { if (CheckHasLoggedIn(cred.AccountInfo.LoginName)) throw new Exception($"user {cred.AccountInfo.LoginName} has been logged in."); lock (_syncRoot) { if (_dictLoginCredentials.Count >= _maxCredentialAllowed) throw new InvalidOperationException("maximum number of login credentials reached"); _dictLoginCredentials[cred.Token] = cred; } } /// /// 移除指定令牌的凭据。 /// /// public void Remove(string token) { lock (_syncRoot) { _dictLoginCredentials.Remove(token); } } /// /// 获取指定用户名的登录凭据。 /// /// /// public Credential GetCredentialByUserName(string userName) { lock (_syncRoot) { return _dictLoginCredentials.Values.FirstOrDefault(x => x.AccountInfo.LoginName == userName); } } /// /// 校验指定令牌的凭据是否有效。 /// /// /// public bool ValidateCredential(string token) { lock (_syncRoot) { if (_dictLoginCredentials.TryGetValue(token, out var cred)) { return cred.State == CredentialState.Alive; } return false; } } #endregion #region Static Methods /// /// 创建一个令牌。 /// /// public static string GenerateToken() { return Guid.NewGuid().ToString("N"); } #endregion }