diff --git a/MECF.Framework.Common/Aitex/Core/Account/CredentialManager.cs b/MECF.Framework.Common/Aitex/Core/Account/CredentialManager.cs index 757aa0a..274cd35 100644 --- a/MECF.Framework.Common/Aitex/Core/Account/CredentialManager.cs +++ b/MECF.Framework.Common/Aitex/Core/Account/CredentialManager.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using Aitex.Core.RT.DBCore; -using Aitex.Core.RT.Event; using Aitex.Core.Util; namespace Aitex.Core.Account; @@ -113,10 +112,7 @@ public class CredentialManager : Singleton { var cred = kvp.Value; if ((DateTime.Now - cred.LastAliveTime).TotalSeconds > LOGIN_CRED_KEEP_ALIVE_TIMEOUT_SEC) - { loginRemovableList.Add(cred.Token); - EV.PostLoginBySameUser(cred.Token, new Credential()); - } } if (loginRemovableList.Count > 0) @@ -138,13 +134,30 @@ public class CredentialManager : Singleton var cred = kvp.Value; if ((DateTime.Now - cred.LastAliveTime).TotalSeconds > REQ_LOGIN_CRED_LIFT_TIME_SEC) requestRemovableList.Add(kvp.Key); + + // 移除被取消或拒绝的凭据 + if(cred.State is CredentialState.RequestCanceled or CredentialState.Reject) + requestRemovableList.Add(kvp.Key); } if (requestRemovableList.Count > 0) { foreach (var loginName in requestRemovableList) { - WriteHistory(_dictCredentialsRequesting[loginName], "REQ EXPIRED"); + var reason = ""; + switch (_dictCredentialsRequesting[loginName].State) + { + case CredentialState.RequestCanceled: + reason = "REQ CANCELED"; + break; + case CredentialState.Reject: + reason = "REQ REJECTED"; + break; + default: + reason = "REQ EXPIRED"; + break; + } + WriteHistory(_dictCredentialsRequesting[loginName], reason); _dictCredentialsRequesting.Remove(loginName); } } @@ -197,7 +210,7 @@ public class CredentialManager : Singleton /// /// 报告客户端处于活动状态。 /// - /// 客户端登录凭据 + /// 客户端登录凭据 /// public CredentialKeepAliveResults KeepAlive(Guid myToken) { @@ -209,9 +222,13 @@ public class CredentialManager : Singleton // 如果当前用户名在请求登录列表中,则返回CredentialKeepAliveResults.RequestingLogin,通知 // 已登录的客户端,当前用户正在请求异地登录。 - return _dictCredentialsRequesting.ContainsKey(loginCred.AccountInfo.LoginName) - ? CredentialKeepAliveResults.RequestingLogin - : CredentialKeepAliveResults.Alive; + if (_dictCredentialsRequesting.TryGetValue(loginCred.AccountInfo.LoginName, + out var requestingLoginCred) && requestingLoginCred.State == CredentialState.Requesting) + { + return CredentialKeepAliveResults.RequestingLogin; + } + + return CredentialKeepAliveResults.Alive; } return CredentialKeepAliveResults.NotFound; @@ -282,21 +299,6 @@ public class CredentialManager : Singleton } } - /// - /// 从登录请求列表中移除指定的凭据。 - /// - /// - public void RemoveRequesting(Credential cred) - { - lock (_syncRoot) - { - if(_dictCredentialsRequesting.TryGetValue(cred.AccountInfo.LoginName, out var reqCredential)) - WriteHistory(reqCredential, "REQ CANCEL"); - - _dictCredentialsRequesting.Remove(cred.AccountInfo.LoginName); - } - } - /// /// 获取指定用户名的登录凭据。 /// diff --git a/MECF.Framework.Common/Aitex/Core/Account/Misc.cs b/MECF.Framework.Common/Aitex/Core/Account/Misc.cs index c634f4f..c22624a 100644 --- a/MECF.Framework.Common/Aitex/Core/Account/Misc.cs +++ b/MECF.Framework.Common/Aitex/Core/Account/Misc.cs @@ -24,6 +24,11 @@ public enum CredentialState /// 等待系统校验登录请求。 /// Requesting, + + /// + /// 登录请求被取消。 + /// + RequestCanceled, /// /// 凭据有效。 diff --git a/MECF.Framework.Common/Aitex/Core/RT/Event/EV.cs b/MECF.Framework.Common/Aitex/Core/RT/Event/EV.cs index 76535de..12b495f 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/Event/EV.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/Event/EV.cs @@ -81,14 +81,6 @@ namespace Aitex.Core.RT.Event } } - public static void PostLoginBySameUser(Guid token, Credential requestedCredential) - { - if (InnerEventManager != null) - { - InnerEventManager.PostLoginBySameUser(token, requestedCredential); - } - } - public static void PostSoundMessage(string message) { if (InnerEventManager != null) diff --git a/MECF.Framework.Common/Aitex/Core/RT/Event/EventManager.cs b/MECF.Framework.Common/Aitex/Core/RT/Event/EventManager.cs index 34b076a..b48b0bf 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/Event/EventManager.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/Event/EventManager.cs @@ -231,17 +231,6 @@ namespace Aitex.Core.RT.Event return true; }); - OP.Subscribe("System.Diagnosis.GenLoginBySameUserEvent", (s, args) => - { - var token = (Guid)args[0]; - var cred = CredentialManager.Instance.GetCredential(token); - if(cred != null) - PostLoginBySameUser(cred.Token, new Credential()); - else - EV.PostWarningLog("Diagnosis", $"The credential with token {token} does not found."); - return true; - }); - #endregion } @@ -473,19 +462,6 @@ namespace Aitex.Core.RT.Event _writerToLog.WriteEvent(eventItem); } - public void PostLoginBySameUser(Guid token, Credential requestedCredential) - { - var eventItem = new EventItem - { - Type = EventType.LoginBySameUser_Notify, - Description = token.ToString(), - OccuringTime = DateTime.Now, - Tag = requestedCredential - }; - _eventQueue.Enqueue(eventItem); - _writerToLog.WriteEvent(eventItem); - } - public void PostSoundMessage(string message) { var eventItem = new EventItem diff --git a/MECF.Framework.Common/Aitex/Core/RT/Event/EventType.cs b/MECF.Framework.Common/Aitex/Core/RT/Event/EventType.cs index 355d12f..b33537d 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/Event/EventType.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/Event/EventType.cs @@ -50,12 +50,6 @@ namespace Aitex.Core.RT.Event /// RT通知消息事件。 /// [EnumMember] - HostNotification = 6, - - /// - /// 用户异地登录通知。 - /// - [EnumMember] - LoginBySameUser_Notify = 7 + HostNotification = 6 } } diff --git a/MECF.Framework.Common/Aitex/Core/RT/Event/ICommonEvent.cs b/MECF.Framework.Common/Aitex/Core/RT/Event/ICommonEvent.cs index f98a3f5..67de1e0 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/Event/ICommonEvent.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/Event/ICommonEvent.cs @@ -23,8 +23,6 @@ namespace Aitex.Core.RT.Event void PostKickoutMessage(string message); - void PostLoginBySameUser(Guid token, Credential requestedCredential); - void PostSoundMessage(string message); List GetAlarmEvent(); diff --git a/MECF.Framework.Common/MECF/Framework/Common/Account/AccountExManager.cs b/MECF.Framework.Common/MECF/Framework/Common/Account/AccountExManager.cs index 18c678b..dcd812b 100644 --- a/MECF.Framework.Common/MECF/Framework/Common/Account/AccountExManager.cs +++ b/MECF.Framework.Common/MECF/Framework/Common/Account/AccountExManager.cs @@ -12,6 +12,7 @@ using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.Util; using Aitex.Core.WCF; +using DocumentFormat.OpenXml.Wordprocessing; using MECF.Framework.Common.Account.Extends; using MECF.Framework.Common.Equipment; @@ -122,8 +123,6 @@ namespace MECF.Framework.Common.Account return await Task.Run(async () => { // 通知已登录的用户,其它客户端使用该用户名登录,是否允许登录 - EV.PostLoginBySameUser(userLoggedIn.Token, userRequesting); - var ct = userRequesting.LoginRequestCancellationTokenSource.Token; // 等待已登录的凭据被移除(客户端注销) @@ -132,27 +131,33 @@ namespace MECF.Framework.Common.Account while (true) { - if (userRequesting.State == CredentialState.Confirmed) - { - // 客户端已注销,可以放行新的凭据 - CredentialManager.Instance.Grant(userRequesting); - EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn, - userLoggedIn.AccountInfo.LoginName); - return await Task.FromResult(LoginRequestResults.Confirmed); - } + switch (userRequesting.State) + { + case CredentialState.Confirmed: + // 客户端已注销,可以放行新的凭据 + CredentialManager.Instance.Grant(userRequesting); + EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn, + userLoggedIn.AccountInfo.LoginName); + return await Task.FromResult(LoginRequestResults.Confirmed); - if (userRequesting.State == CredentialState.Reject) - { - // 已登录用户拒绝了登录请求 - EV.PostInfoLog(ModuleName.System.ToString(), - $"User {userRequesting.AccountInfo.LoginName}'s login request from {userRequesting.LoginIP}:{userRequesting.LoginPort} is rejected"); + case CredentialState.Reject or CredentialState.RequestCanceled: + if(userRequesting.State == CredentialState.Reject) + // 已登录用户拒绝了登录请求 + EV.PostInfoLog(ModuleName.System.ToString(), + $"User {userRequesting.AccountInfo.LoginName}'s login request from {userRequesting.LoginIP}:{userRequesting.LoginPort} is rejected"); - CredentialManager.Instance.RemoveRequesting(userRequesting); - return await Task.FromResult(LoginRequestResults.Rejected); - } + return await Task.FromResult(LoginRequestResults.Rejected); - Thread.Sleep(1000); - ct.ThrowIfCancellationRequested(); + case CredentialState.Requesting: + case CredentialState.Alive: + + break; + } + + + Thread.Sleep(200); + if (ct.IsCancellationRequested) + break; // 等待指定的时间,然后向申请端发送超时 if (sw.Elapsed.TotalSeconds > 40) @@ -279,8 +284,9 @@ namespace MECF.Framework.Common.Account if (cred != null) { cred.LoginRequestCancellationTokenSource.Cancel(); - } - } + cred.State = CredentialState.RequestCanceled; + } + } /// /// 确认登录请求。 diff --git a/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml b/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml index 52a2bd0..68aa3a6 100644 --- a/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml +++ b/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml @@ -10,8 +10,7 @@ Title="Login Request" ResizeMode="CanResize" WindowStyle="None" - WindowStartupLocation="CenterScreen" - Closing="LoginRequestWaitDialog_OnClosing"> + WindowStartupLocation="CenterScreen"> diff --git a/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml.cs b/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml.cs index 2d01fcc..3b50c44 100644 --- a/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml.cs +++ b/MECF.Framework.UI.Client/ClientBase/Dialog/LoginRequestWaitDialog.xaml.cs @@ -1,6 +1,5 @@ using Aitex.Core.Account; using System; -using System.ComponentModel; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -27,10 +26,12 @@ namespace MECF.Framework.UI.Client.ClientBase.Dialog _progCountDown = new Progress(countDown => { + // 更新Cancel按钮倒计时数值 + // 如果倒计时为0,则关闭当前窗口 if (countDown > 0) BtnCancel.Content = $"Cancel ({countDown:F0}s)"; else - DialogResult = false; + DialogResult = false; // canceled }); } @@ -39,6 +40,7 @@ namespace MECF.Framework.UI.Client.ClientBase.Dialog base.OnSourceInitialized(e); var closeTime = DateTime.Now.Add(TimeSpan.FromSeconds(CredentialManager.REQ_LOGIN_DIALOG_LIFT_TIME__SEC)); + var ct = _ctsCountDownTask?.Token; Task.Run(() => { while (true) @@ -46,15 +48,17 @@ namespace MECF.Framework.UI.Client.ClientBase.Dialog var timeRemained = (closeTime - DateTime.Now).TotalSeconds; if (timeRemained <= 0) { - // force to reject + // force to cancel _progCountDown.Report(0); break; } _progCountDown.Report(timeRemained); + Thread.Sleep(500); - if (_ctsCountDownTask.Token.IsCancellationRequested) + // 操作被取消 + if (ct is { IsCancellationRequested: true }) break; } }); @@ -62,17 +66,16 @@ namespace MECF.Framework.UI.Client.ClientBase.Dialog private void BtnCancel_OnClick(object sender, RoutedEventArgs e) { - _ctsCountDownTask.Cancel(); - DialogResult = false; + Cancel(); } public void Accepted() { - _ctsCountDownTask.Cancel(); + _ctsCountDownTask.Cancel(); DialogResult = true; } - private void LoginRequestWaitDialog_OnClosing(object sender, CancelEventArgs e) + public void Cancel() { _ctsCountDownTask.Cancel(); DialogResult = false; diff --git a/UIDebug/UserLoginTester/Program.cs b/UIDebug/UserLoginTester/Program.cs index d4b1276..ddc1080 100644 --- a/UIDebug/UserLoginTester/Program.cs +++ b/UIDebug/UserLoginTester/Program.cs @@ -124,33 +124,6 @@ namespace UserLoginTester case EventType.KickOut_Notify: break; - case EventType.LoginBySameUser_Notify: - if (Guid.TryParse(evt.Description, out var token) && evt.Tag is Credential requestingCred) - { - if (_loginCred != null && token == _loginCred.Token) - { - Console.WriteLine( - @"Some users is requesting to login the system, you will be forced to switch to read-only mode, do you agree?"); - - __prompt: - Console.Write("[Y]es/[N]o: "); - var ack = Console.ReadLine(); - switch (ack) - { - case "Y": - AccountClient.Instance.Service.ConfirmLoginRequest(requestingCred.AccountInfo.LoginName); - AccountClient.Instance.Service.LogoutEx(_loginCred.Token); - break; - case "N": - AccountClient.Instance.Service.RejectLoginRequest(requestingCred.AccountInfo.LoginName); - break; - default: - goto __prompt; - } - } - } - break; - case EventType.Sound_Notify: break; case EventType.UIMessage_Notify: