vCloudTerminal.cs 33 KB

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