vCloudTerminal.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using Vinno.IUS.Common.Log;
  8. using Vinno.IUS.Common.Network.Leaf;
  9. using Vinno.IUS.Common.Network.Tcp;
  10. using Vinno.IUS.Common.Network.Transfer;
  11. using Vinno.IUS.Common.Utilities;
  12. using Vinno.vCloud.Common.FIS.AfterSales;
  13. using Vinno.vCloud.Common.FIS.FLYINSONOLogin;
  14. using Vinno.vCloud.Common.FIS.LiveVideos;
  15. using Vinno.vCloud.Common.FIS.Remedicals;
  16. using Vinno.vCloud.Common.Storage;
  17. using Vinno.vCloud.FIS.CrossPlatform.Common;
  18. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  19. using Vinno.vCloud.Protocol.Infrastructures;
  20. using Vinno.vCloud.Protocol.Messages;
  21. using Vinno.vCloud.Protocol.Messages.Client;
  22. using Vinno.vCloud.Protocol.Messages.Client.AfterSales;
  23. using Vinno.vCloud.Protocol.Messages.Client.AssignTermianl;
  24. using Vinno.vCloud.Protocol.Messages.Client.AssignTerminal;
  25. using Vinno.vCloud.Protocol.Messages.Client.Live;
  26. using Vinno.vCloud.Protocol.Messages.Client.Share;
  27. using Vinno.vCloud.Protocol.Messages.Client.Storage;
  28. using Vinno.vCloud.Protocol.Messages.Login;
  29. using Vinno.vCloud.Protocol.Messages.Terminal;
  30. using Vinno.vCloud.Protocol.Messages.Terminal.Login;
  31. namespace Vinno.vCloud.Common.FIS
  32. {
  33. internal class vCloudTerminal : IvCloudTerminal
  34. {
  35. private readonly Dictionary<TerminalFeatureType, object> _features = new Dictionary<TerminalFeatureType, object>();
  36. private readonly ConnectionInfo _connectionInfo;
  37. private readonly string _deviceName;
  38. private readonly string _password;
  39. private readonly bool _isUserDefined;
  40. private readonly LoginSource _loginSource;
  41. private readonly string _url;
  42. private readonly int _usScreenWidth;
  43. private readonly int _usScreenHeight;
  44. private string _clientId;
  45. private int _connectionCheckCycle;
  46. private int _heartRateCycle;
  47. private TerminalStatus _status;
  48. private ClientLeaf _leaf;
  49. private ConnectionChecker _connectionChecker;
  50. private HeartRateKeeper _heartRateKeeper;
  51. private bool _disposed;
  52. private string _id;
  53. private string _sessionId;
  54. private int _reconnectCounter;
  55. private bool _isUseOldTerminalSdk;
  56. /// <summary>
  57. /// Raised when the status is changed.
  58. /// </summary>
  59. public event EventHandler StatusChanged;
  60. /// <summary>
  61. /// Gets the unique id.
  62. /// </summary>
  63. public string UniqueId { get; private set; }
  64. /// <inheritdoc />
  65. /// <summary>
  66. /// Gets the status of the Terminal
  67. /// </summary>
  68. /// <remarks>
  69. /// </remarks>
  70. public TerminalStatus Status
  71. {
  72. get => _status;
  73. private set
  74. {
  75. if (_status != value)
  76. {
  77. _status = value;
  78. OnStatusChanged();
  79. }
  80. }
  81. }
  82. public string Id => _id;
  83. public string TerminalName => _deviceName;
  84. public string TerminalMode => _connectionInfo.DeviceMode;
  85. /// <summary>
  86. /// Gets the global remedical working folder.
  87. /// </summary>
  88. internal static string WorkingFolder { get; private set; }
  89. public vCloudTerminal(ConnectionInfo connectionInfo, bool isUsedOldSdk = false)
  90. {
  91. _isUseOldTerminalSdk = isUsedOldSdk;
  92. _usScreenHeight = connectionInfo.USScreenHeight;
  93. _usScreenWidth = connectionInfo.USScreenWidth;
  94. _connectionInfo = connectionInfo;
  95. _deviceName = connectionInfo.Account.Name;
  96. _password = connectionInfo.Account.Password;
  97. _isUserDefined = connectionInfo.Account.IsUserDefined;
  98. _url = connectionInfo.ServerUrl;
  99. _loginSource = CommonParameter.Instance.IsSonopost ? LoginSource.WindowSonopost : LoginSource.UltrasoundMachine;
  100. _clientId = IdHelper.Generate<string>();
  101. //Set the default value 10 seconds.
  102. _connectionCheckCycle = 10;
  103. //Set the default value 3 minutes.
  104. _heartRateCycle = 3;
  105. _status = TerminalStatus.Offline;
  106. WorkingFolder = connectionInfo.FISFolder;
  107. if (!Directory.Exists(WorkingFolder))
  108. {
  109. Directory.CreateDirectory(WorkingFolder);
  110. }
  111. if (!_isUseOldTerminalSdk)
  112. {
  113. CreateLeaf();
  114. CreateConnectionChecker();
  115. if (!connectionInfo.IsOnlyUsedToRegister)
  116. {
  117. CPCombineSmartPushConfiguration.Instance.Initialize(connectionInfo.FISFolder);
  118. UploadHelper.GetAuthorization = GetAuthorization;
  119. }
  120. }
  121. }
  122. /// <inheritdoc />
  123. /// <summary>
  124. /// Get the feature instance by feature enum.
  125. /// </summary>
  126. /// <typeparam name="T">The interface of the feature</typeparam>
  127. /// <param name="featureType">The feature type</param>
  128. /// <returns>The instance of the feature</returns>
  129. /// <remarks>
  130. /// If the feature doesn't exist, this method will return null.
  131. /// </remarks>
  132. public T GetFeature<T>(TerminalFeatureType featureType) where T : IFeature
  133. {
  134. if (_features.ContainsKey(featureType))
  135. {
  136. var feature = _features[featureType];
  137. if (feature is T t)
  138. {
  139. return t;
  140. }
  141. }
  142. return default(T);
  143. }
  144. /// <summary>
  145. /// Connect to server.
  146. /// </summary>
  147. internal void Connect(string uniqueId = "", string terminalId = "")
  148. {
  149. try
  150. {
  151. if (!_isUseOldTerminalSdk)
  152. {
  153. var loginResult = NewLogin();
  154. if (!_isUserDefined && loginResult.Status == LoginStatus.WrongAccount)
  155. {
  156. if (string.IsNullOrEmpty(_connectionInfo.Organization))
  157. {
  158. Status = TerminalStatus.OrganizationMissing;
  159. return;
  160. }
  161. if (RegisterAccount())
  162. {
  163. NewLogin();
  164. }
  165. else
  166. {
  167. Status = TerminalStatus.LoginFailed;
  168. }
  169. }
  170. }
  171. else
  172. {
  173. UniqueId = uniqueId;
  174. _id = terminalId;
  175. ReleaseFeatures();
  176. UpdateFeatures(_connectionInfo.EnabledFeatures);
  177. Status = TerminalStatus.Logon;
  178. }
  179. }
  180. catch (Exception e)
  181. {
  182. Logger.WriteLineError($"Terminal {_deviceName} login url:{_url} failed {e}");
  183. Status = TerminalStatus.LoginFailed;
  184. }
  185. }
  186. public bool Register()
  187. {
  188. return RegisterAccount();
  189. }
  190. /// <summary>
  191. /// Register Account
  192. /// </summary>
  193. /// <returns></returns>
  194. private bool RegisterAccount()
  195. {
  196. using (var request = MessagePool.GetMessage<AddTerminalAccountRequest>())
  197. {
  198. request.TerminalName = _deviceName;
  199. request.TerminalModel = _connectionInfo.DeviceMode;
  200. request.TerminalPassword = _password;
  201. request.OrganizationName = _connectionInfo.Organization;
  202. request.IsLive = true;
  203. var addTerminalAccountServerResult = _leaf?.Send(request);
  204. var addTerminalAccountResult = ResultMessage.Convert(addTerminalAccountServerResult);
  205. if (addTerminalAccountResult == CCR.OK)
  206. {
  207. return true;
  208. }
  209. else
  210. {
  211. return false;
  212. }
  213. }
  214. }
  215. public void Disconnect()
  216. {
  217. if (!_isUseOldTerminalSdk)
  218. {
  219. var status = TerminalStatus.Logoff;
  220. try
  221. {
  222. SendStopPushStreamResult();
  223. using (var request = MessagePool.GetMessage<NewTerminalLogoffRequest>())
  224. {
  225. request.Name = _deviceName;
  226. request.Password = _password;
  227. request.Source = _loginSource;
  228. request.IsUserDefinedAccount = _isUserDefined;
  229. var result = _leaf?.Send(request);
  230. var logoffResult = LogoffResult.Convert(result);
  231. switch (logoffResult.Status)
  232. {
  233. case LogoffStatus.Success:
  234. status = TerminalStatus.Logoff;
  235. break;
  236. case LogoffStatus.WrongAccount:
  237. status = TerminalStatus.WrongAccount;
  238. break;
  239. case LogoffStatus.WrongPassword:
  240. status = TerminalStatus.WrongPassword;
  241. break;
  242. }
  243. }
  244. }
  245. catch (Exception e)
  246. {
  247. Logger.WriteLineError($"Disconnect terminal {_deviceName} error {e}");
  248. }
  249. finally
  250. {
  251. Release();
  252. FLYINSONOUserManager.Instance.Clear();
  253. Status = status;
  254. }
  255. }
  256. else
  257. {
  258. try
  259. {
  260. Release();
  261. FLYINSONOUserManager.Instance.Clear();
  262. Status = TerminalStatus.Logoff;
  263. }
  264. catch (Exception e)
  265. {
  266. Logger.WriteLineError($"Disconnect terminal with old Sdk {_deviceName} error {e}");
  267. }
  268. }
  269. }
  270. public IEnumerable<string> GetOrganizations(string keyWord)
  271. {
  272. using (var request = MessagePool.GetMessage<FindOrganizationByKeyWordRequest>())
  273. {
  274. request.KeyWord = keyWord;
  275. var result = _leaf?.Send(request);
  276. var findOrganizationInfosResult = FindOrganizationInfosResult.Convert(result);
  277. if (findOrganizationInfosResult?.OrganizationInfos != null)
  278. {
  279. return findOrganizationInfosResult.OrganizationInfos.Select(i => i.Name);
  280. }
  281. }
  282. return new List<string>();
  283. }
  284. public bool IsTerminalOrganizationMissging()
  285. {
  286. return Status == TerminalStatus.OrganizationMissing;
  287. }
  288. public bool UpdatelTerminalOrganizationName(string organizationName, bool createNewOrganization)
  289. {
  290. using (var request = MessagePool.GetMessage<UpdateTerminalOrganizationNameRequest>())
  291. {
  292. request.TerminalName = _deviceName;
  293. request.OrganizationName = organizationName;
  294. request.IsCreateNewOrganization = createNewOrganization;
  295. var result = _leaf?.Send(request);
  296. var updateTerminalResult = ResultMessage.Convert(result);
  297. if (updateTerminalResult == CCR.OK)
  298. {
  299. Logger.WriteLineInfo($"vCloudTerminal UpdatelTerminalOrganizationName Success,TerminalName:{_deviceName},OrganizationName:{organizationName},CreateNewOrganization:{createNewOrganization}");
  300. return true;
  301. }
  302. else
  303. {
  304. Logger.WriteLineError($"vCloudTerminal UpdatelTerminalOrganizationName Failed,TerminalName:{_deviceName},OrganizationName:{organizationName},CreateNewOrganization:{createNewOrganization}");
  305. return false; //update organization name fail
  306. }
  307. }
  308. }
  309. public string GetOrganizationName()
  310. {
  311. var organizationName = string.Empty;
  312. try
  313. {
  314. using (var request = MessagePool.GetMessage<FindTerminalByNameRequest>())
  315. {
  316. request.TerminalName = _deviceName;
  317. var result = _leaf?.Send(request);
  318. if (result != null)
  319. {
  320. var findTerminalByNameResult = FindTerminalByNameResult.Convert(result);
  321. if (findTerminalByNameResult != null)
  322. {
  323. organizationName = findTerminalByNameResult.Termianl?.OrganizationName;
  324. }
  325. }
  326. }
  327. }
  328. catch (Exception ex)
  329. {
  330. Logger.WriteLineError($"Vcloud terminal get organization name by terminal failed:{ex}");
  331. }
  332. return organizationName;
  333. }
  334. public IEnumerable<byte[]> GetReportImagesByPatientId(string patientId)
  335. {
  336. try
  337. {
  338. using (var request = MessagePool.GetMessage<GetShareReportImageByPatientIdRequest>())
  339. {
  340. request.PatientId = patientId;
  341. var language = "";
  342. var lcid = CultureInfo.CurrentCulture.LCID;
  343. if (lcid == 0x804 || lcid == 0xc04 || lcid == 0x1404 || lcid == 0x1004 || lcid == 0x404)
  344. {
  345. language = "Chinese";
  346. }
  347. else
  348. {
  349. language = "English";
  350. }
  351. request.Language = language;
  352. var result = _leaf?.Send(request);
  353. if (result != null)
  354. {
  355. var getReportImageByPatientIdResult = GetShareReportImageByPatientIdResult.Convert(result);
  356. if (getReportImageByPatientIdResult != null)
  357. {
  358. var reportImages = getReportImageByPatientIdResult.ReportImages;
  359. return reportImages.Select(v => v.GetBytes()).ToList();
  360. }
  361. }
  362. }
  363. }
  364. catch (Exception e)
  365. {
  366. Logger.WriteLineError($"vCloudTerminal GetReportByPatientId failed error {e}");
  367. }
  368. return new List<byte[]>();
  369. }
  370. /// <summary>
  371. /// Update enabled feature types.
  372. /// </summary>
  373. /// <param name="enabledFeatureTypes">The enabled feature types.</param>
  374. public void UpdateFeatures(IEnumerable<TerminalFeatureType> enabledFeatureTypes)
  375. {
  376. CommonParameter.Instance.IsFeatureReleased = false;
  377. if (!_isUseOldTerminalSdk)
  378. {
  379. var removedFeatures = _features.Keys.Where(f => !enabledFeatureTypes.Contains(f)).ToList();
  380. foreach (var feature in removedFeatures)
  381. {
  382. var disposable = _features[feature] as IDisposable;
  383. disposable?.Dispose();
  384. _features.Remove(feature);
  385. }
  386. foreach (var enabledFeature in enabledFeatureTypes)
  387. {
  388. if (!_features.ContainsKey(enabledFeature))
  389. {
  390. var feature = GetFeature(enabledFeature);
  391. _features.Add(enabledFeature, feature);
  392. }
  393. }
  394. }
  395. else
  396. {
  397. var removedFeatures = _features.Keys.Where(f => !enabledFeatureTypes.Contains(f)).ToList();
  398. foreach (var feature in removedFeatures)
  399. {
  400. if (feature == TerminalFeatureType.Consultation)
  401. {
  402. var disposable = _features[feature] as IDisposable;
  403. disposable?.Dispose();
  404. _features.Remove(feature);
  405. }
  406. }
  407. foreach (var enabledFeature in enabledFeatureTypes)
  408. {
  409. if (enabledFeature == TerminalFeatureType.Consultation)
  410. {
  411. if (!_features.ContainsKey(enabledFeature))
  412. {
  413. var feature = GetFeature(enabledFeature);
  414. _features.Add(enabledFeature, feature);
  415. }
  416. }
  417. }
  418. }
  419. }
  420. public void Dispose()
  421. {
  422. if (!_disposed)
  423. {
  424. Release();
  425. _disposed = true;
  426. }
  427. GC.SuppressFinalize(this);
  428. }
  429. private void SendStopPushStreamResult()
  430. {
  431. if (!string.IsNullOrWhiteSpace(_id))
  432. {
  433. using (var request = MessagePool.GetMessage<StopPushStreamResult>())
  434. {
  435. request.TerminalId = _id;
  436. var result = _leaf?.Send(request);
  437. var ok = ResultMessage.Convert(result);
  438. if (ok == null || ok.ResultCode != 0)
  439. throw new InvalidOperationException("Send reply to server error.");
  440. }
  441. }
  442. }
  443. private string GetAuthorization(string fileName)
  444. {
  445. try
  446. {
  447. var authorization = string.Empty;
  448. var getAuthorizationRequest = new GetAuthorizationRequest();
  449. getAuthorizationRequest.FileName = fileName;
  450. var storageResult = _leaf?.Send(getAuthorizationRequest);
  451. var getAuthorizationResult = GetAuthorizationResult.Convert(storageResult);
  452. if (getAuthorizationResult != null)
  453. {
  454. authorization = getAuthorizationResult.Authorization;
  455. }
  456. return authorization;
  457. }
  458. catch (Exception e)
  459. {
  460. throw new Exception($"get authentication form server error:{e}");
  461. }
  462. }
  463. private NewTerminalLoginResult4 NewLogin()
  464. {
  465. using (var request = MessagePool.GetMessage<NewTerminalLoginRequest4>())
  466. {
  467. request.Name = _deviceName;
  468. request.Password = _password;
  469. request.SupportLive = true;
  470. request.ClientId = _clientId;
  471. request.IsUserDefinedAccount = _isUserDefined;
  472. request.Source = _loginSource;
  473. request.TerminalVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
  474. var result = _leaf?.Send(request);
  475. var loginResult = NewTerminalLoginResult4.Convert(result);
  476. if (loginResult != null)
  477. {
  478. UniqueId = loginResult.TerminalUniqueId;
  479. ////TODO(FISJuly)
  480. //StorageType = loginResult.StorageType;
  481. HandleLoginResult(loginResult.Status, loginResult.AccountId, loginResult.AccountSessionId);
  482. }
  483. else
  484. {
  485. throw new InvalidOperationException("Login failed.");
  486. }
  487. return loginResult;
  488. }
  489. }
  490. private void HandleLoginResult(LoginStatus loginStatus, string accountId, string accountSessionId)
  491. {
  492. if (loginStatus == LoginStatus.Success)
  493. {
  494. Status = TerminalStatus.Logoning;
  495. _sessionId = accountSessionId;
  496. _id = accountId;
  497. CreateHeartRateKeeper();
  498. ReleaseFeatures();
  499. UpdateFeatures(_connectionInfo.EnabledFeatures);
  500. UpdateTerminalInfo();
  501. _reconnectCounter = 0;
  502. Status = TerminalStatus.Logon;
  503. Logger.WriteLineInfo($"{_deviceName} Login url:{_url} successed, UniqueId:{UniqueId}");
  504. }
  505. else if (loginStatus == LoginStatus.WrongPassword)
  506. {
  507. Status = TerminalStatus.WrongPassword;
  508. }
  509. else if (_isUserDefined && loginStatus == LoginStatus.WrongAccount)
  510. {
  511. Status = TerminalStatus.WrongAccount;
  512. }
  513. else
  514. {
  515. Logger.WriteLineWarn($"Login to server error:{loginStatus}");
  516. }
  517. }
  518. private void UpdateTerminalInfo()
  519. {
  520. try
  521. {
  522. Logger.WriteLineInfo($"begin ChangeTerminalDeviceInfoRequest SerialNumber:{_connectionInfo.SerialNumber} ,USMode:{_connectionInfo.DeviceMode}, USCPU:{_connectionInfo.USCPU}, USOS:{_connectionInfo.USOS}, USSoftware:{_connectionInfo.SoftwareVersion}, ");
  523. if (CommonParameter.Instance.IsSonopost)
  524. {
  525. using (var request = MessagePool.GetMessage<ChangeTerminalDeviceInfoRequest1>())
  526. {
  527. request.TerminalId = _id;
  528. request.SerialNumber = _connectionInfo.SerialNumber;
  529. request.TerminalMode = _connectionInfo.DeviceMode;
  530. request.TerminalCPU = _connectionInfo.USCPU;
  531. request.TerminalOS = "";
  532. request.SoftwareVersion = _connectionInfo.SoftwareVersion;
  533. request.IsSonopost = true;
  534. request.Capability = _deviceName;
  535. request.SonopostVerson = SonopostVersonEnum.Sonopost2;
  536. var result = _leaf?.Send(request);
  537. var changeTerminalDeviceInfoResult = ChangeTerminalDeviceInfoResult.Convert(result);
  538. if (changeTerminalDeviceInfoResult != null && changeTerminalDeviceInfoResult.IsSuccess)
  539. {
  540. Logger.WriteLineInfo($"ChangeTerminalDeviceInfoRequest success");
  541. }
  542. else
  543. {
  544. Logger.WriteLineError($"ChangeTerminalDeviceInfoRequest failed: {changeTerminalDeviceInfoResult.Msg}");
  545. }
  546. }
  547. }
  548. else
  549. {
  550. using (var request = MessagePool.GetMessage<ChangeTerminalDeviceInfoRequest>())
  551. {
  552. request.TerminalId = _id;
  553. request.SerialNumber = _connectionInfo.SerialNumber;
  554. request.TerminalMode = _connectionInfo.DeviceMode;
  555. request.TerminalCPU = _connectionInfo.USCPU;
  556. request.TerminalOS = _connectionInfo.USOS;
  557. request.SoftwareVersion = _connectionInfo.SoftwareVersion;
  558. request.IsSonopost = false;
  559. request.Capability = _deviceName;
  560. var result = _leaf?.Send(request);
  561. var changeTerminalDeviceInfoResult = ChangeTerminalDeviceInfoResult.Convert(result);
  562. if (changeTerminalDeviceInfoResult != null && changeTerminalDeviceInfoResult.IsSuccess)
  563. {
  564. Logger.WriteLineInfo($"ChangeTerminalDeviceInfoRequest success");
  565. }
  566. else
  567. {
  568. Logger.WriteLineError($"ChangeTerminalDeviceInfoRequest failed: {changeTerminalDeviceInfoResult.Msg}");
  569. }
  570. }
  571. }
  572. }
  573. catch (Exception ex)
  574. {
  575. Logger.WriteLineError($"ChangeTerminalDeviceInfoRequest error: {ex}");
  576. }
  577. }
  578. private void OnStatusChanged()
  579. {
  580. StatusChanged?.Invoke(this, EventArgs.Empty);
  581. }
  582. ////TODO(July):支里是否是超声机已在其他机器登录的原因,代码得看看
  583. private void CreateLeaf()
  584. {
  585. _leaf = new ClientLeaf(new LeafIdContext(), LeafMode.Dual, new TcpCreator(_url), "Terminal connection:");
  586. _leaf.MessageArrived += OnMessageArrived;
  587. if (!_leaf.Online)
  588. {
  589. _leaf.Close();
  590. Status = TerminalStatus.Offline;
  591. }
  592. else
  593. {
  594. _leaf.RegisterSetAccountDataMessageFunc(SetAccountDataToMessage);
  595. Status = TerminalStatus.Online;
  596. }
  597. }
  598. private void DisposeLeaf()
  599. {
  600. try
  601. {
  602. if (_leaf != null)
  603. {
  604. _leaf.MessageArrived -= OnMessageArrived;
  605. _leaf.Close();
  606. _leaf = null;
  607. }
  608. }
  609. catch (Exception ex)
  610. {
  611. Logger.WriteLineError($"VCloudTerminal DisposeLeaf Error:{ex}");
  612. }
  613. }
  614. private void CreateHeartRateKeeper()
  615. {
  616. if (_heartRateKeeper == null)
  617. {
  618. _heartRateKeeper = new HeartRateKeeper(_sessionId, _leaf, _heartRateCycle);
  619. _heartRateKeeper.Start();
  620. }
  621. }
  622. private void DisposeHeartRateKeeper()
  623. {
  624. try
  625. {
  626. if (_heartRateKeeper != null)
  627. {
  628. _heartRateKeeper.Stop();
  629. _heartRateKeeper = null;
  630. }
  631. }
  632. catch (Exception ex)
  633. {
  634. Logger.WriteLineError($"VCloudTerminal DisposeHeartRateKeeper Error:{ex}");
  635. }
  636. }
  637. private void CreateConnectionChecker()
  638. {
  639. if (_connectionChecker == null)
  640. {
  641. _connectionChecker = new ConnectionChecker(_leaf, _connectionCheckCycle);
  642. _connectionChecker.Offlined += ConnectionCheckerOnOfflined;
  643. _connectionChecker.Start();
  644. }
  645. }
  646. private void DisposeConnectionChecker()
  647. {
  648. try
  649. {
  650. if (_connectionChecker != null)
  651. {
  652. _connectionChecker.Offlined -= ConnectionCheckerOnOfflined;
  653. _connectionChecker.Stop();
  654. _connectionChecker = null;
  655. }
  656. }
  657. catch (Exception ex)
  658. {
  659. Logger.WriteLineError($"VCloudTerminal DisposeConnectionChecker Error:{ex}");
  660. }
  661. }
  662. private void OnMessageArrived(object sender, Message e)
  663. {
  664. var connectionReplacedNotification = ConnectionReplacedNotification.Convert(e);
  665. if (connectionReplacedNotification != null)
  666. {
  667. HandleConnectionReplacedNotification(connectionReplacedNotification);
  668. }
  669. var connectNotification = ConnectNotification.Convert(e);
  670. if (connectNotification != null)
  671. {
  672. HandleConnectNotification(connectNotification);
  673. }
  674. }
  675. private void HandleConnectionReplacedNotification(ConnectionReplacedNotification connectionReplacedNotification)
  676. {
  677. Dispose();
  678. Status = TerminalStatus.ReplacedNotification;
  679. }
  680. private void HandleConnectNotification(ConnectNotification connectNotification)
  681. {
  682. try
  683. {
  684. var afterSales = GetFeature<IAfterSales>(TerminalFeatureType.AfterSales);
  685. if (afterSales != null)
  686. {
  687. afterSales.UpdateAfterSalesInfo(connectNotification.UserId, connectNotification.UserName);
  688. using (var processReslut = MessagePool.GetMessage<ProcessReslut>())
  689. {
  690. processReslut.TargetId = connectNotification.UserId;
  691. processReslut.RunTaskType = TaskType.Connect;
  692. processReslut.RunTaskStatus = TaskStatus.Finished;
  693. processReslut.Detail = DetailType.Connected;
  694. processReslut.Percent = 1;
  695. processReslut.Source = ProcessSource.FromTerminal;
  696. processReslut.FileToken = string.Empty;
  697. _leaf?.Send(processReslut);
  698. }
  699. }
  700. else
  701. {
  702. using (var processReslut = MessagePool.GetMessage<ProcessReslut>())
  703. {
  704. processReslut.TargetId = connectNotification.UserId;
  705. processReslut.RunTaskType = TaskType.Connect;
  706. processReslut.RunTaskStatus = TaskStatus.Finished;
  707. processReslut.Detail = DetailType.ConnectedDeny;
  708. processReslut.Percent = 0;
  709. processReslut.Source = ProcessSource.FromTerminal;
  710. processReslut.FileToken = string.Empty;
  711. _leaf?.Send(processReslut);
  712. }
  713. }
  714. }
  715. catch (Exception ex)
  716. {
  717. Logger.WriteLineError($"HandleConnectNotification error:{ex}");
  718. }
  719. }
  720. private Message SetAccountDataToMessage(Message message)
  721. {
  722. if (message is ClientRequestMessage clientRequestMessage)
  723. {
  724. clientRequestMessage.AccountData = GetAccountDataMessage() as ClientAccountMessage;
  725. return clientRequestMessage;
  726. }
  727. return message;
  728. }
  729. private Message GetAccountDataMessage()
  730. {
  731. var accountData = MessagePool.GetMessage<ClientAccountMessage>();
  732. accountData.AccountId = _id ?? string.Empty;
  733. accountData.AccountName = _deviceName ?? string.Empty;
  734. accountData.SessionId = _sessionId ?? string.Empty;
  735. accountData.Source = _loginSource;
  736. return accountData;
  737. }
  738. private void ConnectionCheckerOnOfflined(object sender, EventArgs e)
  739. {
  740. Release();
  741. Status = TerminalStatus.Offline;
  742. //No need to reconnect after instance release
  743. if (_disposed) return;
  744. //Reconnect
  745. if (_reconnectCounter < 5)
  746. {
  747. if (!string.IsNullOrEmpty(_deviceName) && !string.IsNullOrEmpty(_password))
  748. {
  749. CreateLeaf();
  750. CreateConnectionChecker();
  751. if (Status == TerminalStatus.Online)
  752. {
  753. Status = TerminalStatus.Reconnecting;
  754. Connect();
  755. _reconnectCounter++;
  756. }
  757. }
  758. }
  759. else
  760. {
  761. Dispose();
  762. }
  763. }
  764. private void Release()
  765. {
  766. _id = string.Empty;
  767. DisposeConnectionChecker();
  768. DisposeHeartRateKeeper();
  769. ReleaseFeatures();
  770. DisposeLeaf();
  771. }
  772. private void ReleaseFeatures()
  773. {
  774. CommonParameter.Instance.IsFeatureReleased = true;
  775. foreach (var type in _features.Keys.ToList())
  776. {
  777. var feature = _features[type];
  778. var disposable = feature as IDisposable;
  779. disposable?.Dispose();
  780. _features.Remove(type);
  781. }
  782. }
  783. private IFeature GetFeature(TerminalFeatureType terminalFeatureType)
  784. {
  785. switch (terminalFeatureType)
  786. {
  787. case TerminalFeatureType.Remedical:
  788. return new Remedical(_id, _leaf);
  789. case TerminalFeatureType.LiveVideo:
  790. if (CommonParameter.Instance.IsSonopost)
  791. {
  792. return new LiveVideoForSonopost(_id, _deviceName, _leaf);
  793. }
  794. else
  795. {
  796. return new LiveVideo(_id, _deviceName, _leaf, _usScreenWidth, _usScreenHeight);
  797. }
  798. case TerminalFeatureType.AfterSales:
  799. return new AfterSales.AfterSales(_id, _leaf);
  800. case TerminalFeatureType.Upgrade:
  801. return new Upgraders.Upgraders(_leaf);
  802. case TerminalFeatureType.Teaching:
  803. return new Teaching.Teaching(_id, _leaf);
  804. case TerminalFeatureType.Consultation:
  805. return new Consultation.Consultation(_id, _deviceName, _url, LoginSource.PersonalComputer, UniqueId);
  806. case TerminalFeatureType.Log:
  807. return new Log.Log(_id, _leaf);
  808. default:
  809. return null;
  810. }
  811. }
  812. }
  813. }