Program.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using ivf_tl_Control; // AppData, StartMain
  5. using IvfTl.Control.Services; // Log4netHelper(程序集 ivf_tl_Control_Services;切勿写 operate 端 ivf_tl_Services)
  6. namespace IvfTl.ControlHost
  7. {
  8. public static class Program
  9. {
  10. private static Mutex _singleton;
  11. private static ControlHttpServer _http;
  12. private static volatile bool _started;
  13. private static ManualResetEventSlim _exitEvent;
  14. [STAThread]
  15. public static int Main(string[] args)
  16. {
  17. // 1) 单实例:已有 control 在跑则立即退出(永远只有一个驱动机器)。
  18. bool isNew;
  19. _singleton = new Mutex(true, @"Global\ivf_tl_control_singleton", out isNew);
  20. if (!isNew)
  21. {
  22. Log4netHelper.WriteLog("ControlHost: 已有实例在运行,本进程退出");
  23. return 0;
  24. }
  25. try
  26. {
  27. var hostArgs = HostArgs.Parse(args);
  28. Log4netHelper.WriteLog($"ControlHost 启动 port={hostArgs.Port} account={hostArgs.Account}");
  29. // 2) 先起 HTTP(让 operate 能尽早探到"在启动中"),started=false。
  30. _http = new ControlHttpServer(
  31. hostArgs.Port,
  32. BuildStatus,
  33. msg => Log4netHelper.WriteLog(msg));
  34. _http.Start();
  35. // 3) 账号守卫(对齐 operate 空账号跳过逻辑)。
  36. if (!hostArgs.IsValid)
  37. {
  38. Log4netHelper.WriteLog("ControlHost: 账号/密码为空,不启动采集(仅 HTTP 存活)");
  39. }
  40. else
  41. {
  42. // 4) 启动序放后台线程(复刻 operate MainWindow 的 Task.Run 形态):
  43. // StartRun 内部会阻塞(InitTL 串口握手 + StartAsync().Wait()),不能占住主线程,
  44. // 否则下面的 _exitEvent.Wait() 永不可达、阶段2 /shutdown 也无从优雅停。
  45. // 主线程只负责驻留;HTTP 在独立 Task 上,采集起没起都能被 operate 探活。
  46. System.Threading.Tasks.Task.Run(() => RunStartupSequence(hostArgs));
  47. }
  48. // 5) 驻留:主线程阻塞等退出信号(阶段2 的 /shutdown 会 Set 此事件)。
  49. _exitEvent = new ManualResetEventSlim(false);
  50. _exitEvent.Wait();
  51. return 0;
  52. }
  53. catch (Exception ex)
  54. {
  55. Log4netHelper.WriteLog("ControlHost 致命异常", ex);
  56. return 1;
  57. }
  58. finally
  59. {
  60. try { _http?.Stop(); } catch { }
  61. try { _singleton?.ReleaseMutex(); } catch { }
  62. }
  63. }
  64. /// <summary>
  65. /// control 启动序(后台线程跑,复刻 operate MainWindow 顺序,顺序不可变):
  66. /// Login → 设缓存盘 → HAL.ScanDevices → StartMain.StartRun。
  67. /// 任一步失败仅记日志降级,不退进程(HTTP 仍存活,operate 可探活到"未就绪")。
  68. /// </summary>
  69. private static void RunStartupSequence(HostArgs hostArgs)
  70. {
  71. try
  72. {
  73. if (!AppData.Instance.Login(hostArgs.Account, hostArgs.Password))
  74. {
  75. Log4netHelper.WriteLog("ControlHost: control 登录失败");
  76. return;
  77. }
  78. if (!string.IsNullOrEmpty(hostArgs.CacheDisk))
  79. {
  80. ivf_tl_UtilHelper.PathHelper.pan = hostArgs.CacheDisk;
  81. AppData.Instance.LogService.Pan = hostArgs.CacheDisk;
  82. }
  83. try
  84. {
  85. IvfTl.Hardware.Impl.HardwareAccessLayer.Instance.Log =
  86. msg => Log4netHelper.WriteLog(msg);
  87. var devices = IvfTl.Hardware.Impl.HardwareAccessLayer.Instance.ScanDevices();
  88. Log4netHelper.WriteLog($"ControlHost: HAL 发现 {devices.Count} 个舱");
  89. }
  90. catch (Exception hex)
  91. {
  92. Log4netHelper.WriteLog("ControlHost: HAL 发现异常(降级):" + hex.Message);
  93. }
  94. var startMain = new StartMain();
  95. string err = startMain.StartRun(); // 阻塞:InitTL→InitHouse→StartAsync
  96. if (!string.IsNullOrEmpty(err))
  97. Log4netHelper.WriteLog("ControlHost: control 启动失败:" + err);
  98. else
  99. {
  100. _started = true;
  101. Log4netHelper.WriteLog("ControlHost: control 启动成功,常驻运行");
  102. }
  103. }
  104. catch (Exception ex)
  105. {
  106. Log4netHelper.WriteLog("ControlHost: 启动序异常(降级,HTTP 仍存活)", ex);
  107. }
  108. }
  109. /// <summary>提供给 HTTP /status 的快照(阶段1:基础存活;阶段2 接 GetMonitorSnapshot 补全)。</summary>
  110. private static StatusDto BuildStatus()
  111. {
  112. string tlSn = "";
  113. try { tlSn = AppData.Instance.TLSetting?.tlSn ?? ""; } catch { }
  114. return new StatusDto
  115. {
  116. Ok = true,
  117. Pid = Process.GetCurrentProcess().Id,
  118. TlSn = tlSn,
  119. Started = _started
  120. };
  121. }
  122. }
  123. }