using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Vinno.IUS.Common.Log; using Vinno.IUS.Common.Network; using Vinno.IUS.Common.Network.Leaf; using Vinno.IUS.Common.Network.Tcp; using Vinno.IUS.Common.Network.Transfer; using Vinno.vCloud.Client.Proxy.Interfaces; using Vinno.vCloud.Common.Client.Managers.Interfaces; using Vinno.vCloud.Common.Client.Managers.vCloudClient; using Vinno.vCloud.Common.Storage; using Vinno.vCloud.Common.Storage.ObjectStorageInfo; using Vinno.vCloud.Protocol.Infrastructures; using Vinno.vCloud.Protocol.Initializers; using Vinno.vCloud.Protocol.Messages; using Vinno.vCloud.Protocol.Messages.Client.Account; using Vinno.vCloud.Protocol.Messages.Client.LiveTalking; using Vinno.vCloud.Protocol.Messages.Client.Login; using Vinno.vCloud.Protocol.Messages.Client.Storage; using Vinno.vCloud.Protocol.Messages.Live; using Vinno.vCloud.Protocol.Messages.Login; namespace Vinno.vCloud.Client.Proxy { public partial class ClientManager { private const int HeartRateTime = 1; //minute private ConnectionKeeper _connectionKeeper; private HeartRateKeeper _heartRateKeeper; private ITcpCreator _tcpCreator; private LoginSource _loginSource; private string _sessionId; private object _clientLoker = new object(); private ClientLeaf _leaf; private string _password; private string _accountName; private string _accountId; private string _liveServiceUrl; private ClientAccountMessage _accountDataMessage; private string _currentUniqueCode = string.Empty; private string _serverAddress; private int _port; private string _clinetId; private string _openId; /// <summary> /// login account Id /// </summary> public string AccountId => _accountId; public string AccountName=> _accountName; /// <summary> /// Gets or set the leaf of this client manager. /// </summary> public ClientLeaf Leaf { get { return _leaf; } set { if (_leaf != value) { if (_leaf != null) { _heartRateKeeper?.Stop(); if (_connectionKeeper != null) { _connectionKeeper.Offlined -= OnOfflined; _connectionKeeper.Stop(); } _leaf.MessageArrived -= OnMessageArrived; _leaf.Close(); } _leaf = value; if (_leaf != null) { _leaf.MessageArrived += OnMessageArrived; _connectionKeeper = new ConnectionKeeper(Leaf); _connectionKeeper.Offlined += OnOfflined; _connectionKeeper.Start(); } } } } /// <summary> /// Network connection is offlined then relogining, trigger by connection keeper /// </summary> public event EventHandler AccountRelogining; /// <summary> /// The event that account relogin /// </summary> public event EventHandler AccountRelogin; /// <summary> /// The event befor connection replaced /// </summary> public event EventHandler ConnectionReplacing; /// <summary> /// The event connection replaced, it may account login in another client /// </summary> public event EventHandler ConnectionReplaced; /// <summary> /// The event account password changed in another client /// </summary> public event EventHandler<string> AccountPasswordChanged; /// <summary> /// execute when visitor relogin fail /// </summary> public event EventHandler<LoginStatus> VisitorReloginFail; /// <summary> /// execute when scan login success /// </summary> public event EventHandler<bool> ScanLoginState; /// <summary> /// Flag indicates client is connected to vCloud server /// </summary> public bool IsConnected => Leaf != null && Leaf.Online; public event EventHandler<bool> ConnectedChanged; /// <summary> /// Get the upgrader which providers the upgrade functions. /// </summary> public IUpgrader Upgrader { get; set; } public IRemedical Remedical { get; } public IRemoteDiagnosis RemoteDiagnosis { get; } /// <summary> /// This property provide all community api communicate to server. /// </summary> public ICommunity Community { get; } /// <summary> /// Provide all chat message api communicate to server. /// </summary> public IMessageCenter MessageCenter { get; } /// <summary> /// Provide all account api communicate to server. /// </summary> public IAccount Account { get; } /// <summary> /// provide all report api /// </summary> public IReport Report { get; } /// <summary> /// provide all Share api /// </summary> public IShare Share { get; } /// <summary> /// provide all live api /// </summary> public ILive Live { get; } /// <summary> /// WorkOrder System /// </summary> public IWorkOrderSystem WorkOrderSystem { get; } /// <summary> /// provide all training api /// </summary> public ITraining Training { get; } public IDataStatistics DataStatistics { get; } /// <summary> /// Assign terminal /// </summary> public IAssignTerminal AssignTerminal { get; } public ILiveTalking LiveTalking { get; } public IAfterSales AfterSales { get; } public ICarotid Carotid { get; } /// <summary> /// provide all teaching api /// </summary> public ITeaching Teaching { get; } /// <summary> /// Provide all AI diagnosis requests. /// </summary> public IAIDiagnosis AIDiagnosis { get; } public IFrontPage FrontPage { get; } public ILiveWatcher LiveWatcher { get; private set; } public event EventHandler<Message> MessageArrived; public ClientManager(string hostUrl) { var address = hostUrl.Split(':'); _serverAddress = address[0]; _port = int.Parse(address[1]); _tcpCreator = new TcpCreator(_serverAddress, _port); Leaf = new ClientLeaf(new LeafIdContext(), LeafMode.Dual, _tcpCreator); Leaf.RegisterSetAccountDataMessageFunc(SetAccountDataToMessage); UploadHelper.GetAuthorization = GetAuthentication; } private void OnOfflined(object sender, EventArgs eventArgs) { lock (_clientLoker) { try { if (Leaf == null) //Account had log off, do not need to reconnect { return; } Logger.WriteLineInfo("OnOfflined Enter"); _heartRateKeeper?.Stop(); _heartRateKeeper = null; OnAccountRelogining(); TryResetClientLeaf(); if (Leaf.Online) { if (LoginByOpenId(_openId, _accountName,_password) == LoginStatus.Success) { OnAccountRelogin(); } } } catch (Exception e) { Logger.WriteLineError($"OnOfflined{e}"); } } } public event EventHandler LoginChanged; private void OnMessageArrived(object sender, Message e) { MessageArrived?.Invoke(this, e); } public void ResetClientLeafWithLock() { lock (_clientLoker) { TryResetClientLeaf(); } } /// <summary> /// Try set ClientLeaf if is online /// </summary> private void TryResetClientLeaf() { _tcpCreator = new TcpCreator(_serverAddress, _port); if (!_tcpCreator.HasValidIpAddress) { return; } var clientLeaf = new ClientLeaf(new LeafIdContext(), LeafMode.Dual, _tcpCreator); if (clientLeaf.Online) { Leaf = clientLeaf; Leaf.RegisterSetAccountDataMessageFunc(SetAccountDataToMessage); } else { clientLeaf.Close(); } Logger.WriteLineInfo($"TryResetClientLeaf- new ClientLeaf end"); } /// <summary> /// Login to vCloud server /// </summary> /// <param name="accountName">Account name (Unique)</param> /// <param name="password">Password(encrypted) </param> /// <param name="loginSource">Login Source</param> /// <returns></returns> public LoginStatus Login(string accountName, string password, LoginSource loginSource, string clientId, bool isOffine = false) { lock (_clientLoker) { _loginSource = loginSource; _accountName = accountName; _password = password; _clinetId = clientId; if (IsConnected) { var loginRequest = new ClientLoginRequest2 { Name = accountName, Password = password, Source = loginSource, ClientId = clientId, ClientVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(), Force = true }; try { var result = Leaf.Send(loginRequest); var loginResult = LoginResult2.Convert(result); if (loginResult != null) { _sessionId = loginResult.AccountSessionId; _accountId = loginResult.AccountId; var status = loginResult.Status; if (status == LoginStatus.Success) { Logger.WriteLineInfo($"LoginRequest Success - account:{accountName}"); if (Leaf.Mode == LeafMode.Dual) { _heartRateKeeper = new HeartRateKeeper(_sessionId, Leaf, HeartRateTime); _heartRateKeeper.Start(); } } return loginResult.Status; } } catch (ConnectionTimeoutException) { return LoginStatus.ConnectionTmeout; } catch (NotConnectedException) { return LoginStatus.ConnectServerFailed; } catch (Exception e) { Logger.WriteLineError($"Login ex:{e}"); } } ConnectedChanged?.Invoke(this, false); return LoginStatus.Unknown; } } public LoginStatus LoginByOpenId(string openId, string username="", string password = "" ) { lock (_clientLoker) { try { _openId = openId; _loginSource = LoginSource.ClientProxy; if (!string.IsNullOrEmpty(username)) { _accountName = username; } if (!string.IsNullOrEmpty(password)) { _password = password; } if (string.IsNullOrEmpty(_clinetId)) { _clinetId = Guid.NewGuid().ToString(); } if (IsConnected) { using (var request = MessagePool.GetMessage<LoginByOpenIdRequest>()) { request.OpenId = openId; request.Source = _loginSource; request.ClientId = _clinetId; request.ClientVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); request.Name = username; request.Password = password; request.Type = LoginType.User; var result = Leaf.Send(request); var loginResult = LoginResult2.Convert(result); if (loginResult != null) { _sessionId = loginResult.AccountSessionId; _accountId = loginResult.AccountId; var status = loginResult.Status; if (status == LoginStatus.Success) { Logger.WriteLineInfo($"LoginRequest Success -openId:{openId} , account:{_accountId}"); if (Leaf.Mode == LeafMode.Dual) { _heartRateKeeper = new HeartRateKeeper(_sessionId, Leaf, HeartRateTime); _heartRateKeeper.Start(); } } return loginResult.Status; } } } } catch (ConnectionTimeoutException) { return LoginStatus.ConnectionTmeout; } catch (NotConnectedException) { return LoginStatus.ConnectServerFailed; } catch (Exception e) { Logger.WriteLineError($"Login ex:{e}"); } ConnectedChanged?.Invoke(this, false); return LoginStatus.Unknown; } } internal Task<Message> SendAsync(Message request) { return Leaf.SendAsync(request); } /// <summary> /// Logout from vCloud server async method /// </summary> /// <returns>Logoff status</returns> public async Task<LogoffStatus> LogoutAsync() { LogoffStatus logoffStatus = await Task.Run(() => { lock (_clientLoker) { try { var logoffRequest = new ClientLogoffRequest { Name = _accountName, Password = _password, Source = _loginSource }; var result = Leaf.Send(logoffRequest); LogoffResult logoffResult = LogoffResult.Convert(result); if (logoffResult != null) { return logoffResult.Status; } } catch (Exception exception) { Logger.WriteLineError($"LogoutAsync ex {exception}"); } finally { try { Leaf = null; } catch (Exception ex) { Logger.WriteLineError($"KeepConnection failed, ex: {ex}"); } } return LogoffStatus.Unknown; } }); return logoffStatus; } public void Dispose() { lock (_clientLoker) { Leaf = null; } } protected virtual void OnAccountRelogining() { AccountRelogining?.Invoke(this, EventArgs.Empty); } protected virtual void OnAccountRelogin() { AccountRelogin?.Invoke(this, EventArgs.Empty); } public void StartBackgroundKeeper() { _connectionKeeper?.Stop(); _heartRateKeeper?.Stop(); _connectionKeeper?.Start(); _heartRateKeeper?.Start(); } private Message SetAccountDataToMessage(Message message) { if (message is ClientRequestMessage clientRequestMessage) { if (clientRequestMessage != null) { clientRequestMessage.AccountData = GetAccountDataMessage() as ClientAccountMessage; } } else if (message is DictionaryMessage dictionaryMessage) { var accountMessage = GetAccountDataMessage() as ClientAccountMessage; if (accountMessage != null && dictionaryMessage != null && string.IsNullOrWhiteSpace(dictionaryMessage.GetAccountId())) { dictionaryMessage.SetAccountBaseId(accountMessage.AccountId); var accountIdValue = dictionaryMessage.GetAccountId(); } } return message; } private Message GetAccountDataMessage() { var accountData = new ClientAccountMessage { AccountId = _accountId ?? string.Empty, AccountName = _accountName ?? string.Empty, SessionId = _sessionId ?? string.Empty, Source = _loginSource }; return accountData; } private string GetAuthentication(string fileName) { try { var authorization = string.Empty; var getAuthorizationRequest = new GetAuthorizationRequest(); getAuthorizationRequest.FileName = fileName; var storageResult = Leaf.Send(getAuthorizationRequest); var getAuthorizationResult = GetAuthorizationResult.Convert(storageResult); if (getAuthorizationResult != null) { authorization = getAuthorizationResult.Authorization; } return authorization; } catch (Exception e) { throw new Exception("get authentication form server error"); } } public string GetLiveServiceUrl() { if (string.IsNullOrEmpty(_liveServiceUrl)) { using (var request = MessagePool.GetMessage<GetLiveServiceUrlRequest>()) { var result = Leaf.Send(request); if (result != null) { var resultMessage = GetLiveServiceUrlResult.Convert(result); if (resultMessage != null) { _liveServiceUrl = resultMessage.Url; } } } } return _liveServiceUrl; } } }