|
@@ -0,0 +1,192 @@
|
|
|
|
|
+using YZWater.Core.Models;
|
|
|
|
|
+
|
|
|
|
|
+namespace YZWater.Core.Services;
|
|
|
|
|
+
|
|
|
|
|
+/// <summary>
|
|
|
|
|
+/// 连接状态集中管理服务(借鉴 AutoFMA ConnectionStatusService)
|
|
|
|
|
+///
|
|
|
|
|
+/// 设计原则:
|
|
|
|
|
+/// 1. 统一订阅各设备服务的事件(PlcService / PlcPollingService / HubServer / HubClient)
|
|
|
|
|
+/// 2. 各 ViewModel 通过此服务获取连接状态,避免多处重复订阅
|
|
|
|
|
+/// 3. 状态实际变化时才触发 StatusChanged
|
|
|
|
|
+/// 4. 提供 DisplayText 供 UI 直接绑定
|
|
|
|
|
+///
|
|
|
|
|
+/// HubServer/HubClient 是 App 层按运行模式动态创建的,
|
|
|
|
|
+/// 通过 RegisterHubServer / RegisterHubClient / UnregisterHubs 动态挂接。
|
|
|
|
|
+/// </summary>
|
|
|
|
|
+public sealed class ConnectionStatusService : IDisposable
|
|
|
|
|
+{
|
|
|
|
|
+ private static ConnectionStatusService? _instance;
|
|
|
|
|
+ private static readonly object _instanceLock = new();
|
|
|
|
|
+ public static ConnectionStatusService Instance
|
|
|
|
|
+ {
|
|
|
|
|
+ get { lock (_instanceLock) { return _instance ??= new ConnectionStatusService(); } }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private readonly object _lock = new();
|
|
|
|
|
+
|
|
|
|
|
+ // ─── 状态 ───
|
|
|
|
|
+ private bool _isPlcConnected;
|
|
|
|
|
+ private bool _isHubServerRunning;
|
|
|
|
|
+ private bool _isHubClientConnected;
|
|
|
|
|
+
|
|
|
|
|
+ private HubServer? _hubServer;
|
|
|
|
|
+ private HubClient? _hubClient;
|
|
|
|
|
+
|
|
|
|
|
+ // ─── 属性 ───
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>PLC 是否已连接(含轮询通信状态)</summary>
|
|
|
|
|
+ public bool IsPlcConnected { get { lock (_lock) return _isPlcConnected; } }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>中控服务端是否运行中</summary>
|
|
|
|
|
+ public bool IsHubServerRunning { get { lock (_lock) return _isHubServerRunning; } }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>中控客户端是否已连接</summary>
|
|
|
|
|
+ public bool IsHubClientConnected { get { lock (_lock) return _isHubClientConnected; } }
|
|
|
|
|
+
|
|
|
|
|
+ // ─── 显示文本(供 UI 直接绑定) ───
|
|
|
|
|
+
|
|
|
|
|
+ public string PlcDisplayText
|
|
|
|
|
+ {
|
|
|
|
|
+ get
|
|
|
|
|
+ {
|
|
|
|
|
+ var mode = ConfigService.GetConfig()?.RunMode ?? "Direct";
|
|
|
|
|
+ if (mode == "Mock") return "PLC: 模拟模式";
|
|
|
|
|
+ return IsPlcConnected ? "PLC: 已连接" : "PLC: 未连接";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public string HubDisplayText
|
|
|
|
|
+ {
|
|
|
|
|
+ get
|
|
|
|
|
+ {
|
|
|
|
|
+ var mode = ConfigService.GetConfig()?.RunMode ?? "Direct";
|
|
|
|
|
+ return mode switch
|
|
|
|
|
+ {
|
|
|
|
|
+ "Server" => IsHubServerRunning ? "中控: 服务端运行中" : "中控: 服务端已停止",
|
|
|
|
|
+ "Client" => IsHubClientConnected ? "中控: 已连接服务端" : "中控: 未连接",
|
|
|
|
|
+ _ => "中控: 直连模式"
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ─── 事件 ───
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>任一连接状态变化时触发</summary>
|
|
|
|
|
+ public event Action? StatusChanged;
|
|
|
|
|
+
|
|
|
|
|
+ private ConnectionStatusService()
|
|
|
|
|
+ {
|
|
|
|
|
+ // PLC 底层连接状态
|
|
|
|
|
+ PlcService.ConnectionChanged += OnPlcConnectionChanged;
|
|
|
|
|
+
|
|
|
|
|
+ // PLC 轮询通信状态(轮询失败时 IsPlcConnected 会变为 false,反映真实通信健康度)
|
|
|
|
|
+ PlcPollingService.Instance.DataUpdated += OnPlcDataUpdated;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ─── Hub 动态挂接(App 层按运行模式调用) ───
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 注册中控服务端(Server 模式启动后调用)
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public void RegisterHubServer(HubServer server)
|
|
|
|
|
+ {
|
|
|
|
|
+ UnregisterHubs();
|
|
|
|
|
+ lock (_lock)
|
|
|
|
|
+ {
|
|
|
|
|
+ _hubServer = server;
|
|
|
|
|
+ _isHubServerRunning = server.IsRunning;
|
|
|
|
|
+ }
|
|
|
|
|
+ server.RunningChanged += OnHubServerRunningChanged;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 注册中控客户端(Client 模式创建后调用)
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public void RegisterHubClient(HubClient client)
|
|
|
|
|
+ {
|
|
|
|
|
+ UnregisterHubs();
|
|
|
|
|
+ lock (_lock)
|
|
|
|
|
+ {
|
|
|
|
|
+ _hubClient = client;
|
|
|
|
|
+ _isHubClientConnected = client.IsConnected;
|
|
|
|
|
+ }
|
|
|
|
|
+ client.ConnectionChanged += OnHubClientConnectionChanged;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 取消注册 Hub(停止服务/登出时调用)
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public void UnregisterHubs()
|
|
|
|
|
+ {
|
|
|
|
|
+ lock (_lock)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (_hubServer != null) _hubServer.RunningChanged -= OnHubServerRunningChanged;
|
|
|
|
|
+ if (_hubClient != null) _hubClient.ConnectionChanged -= OnHubClientConnectionChanged;
|
|
|
|
|
+ var changed = _isHubServerRunning || _isHubClientConnected;
|
|
|
|
|
+ _hubServer = null;
|
|
|
|
|
+ _hubClient = null;
|
|
|
|
|
+ _isHubServerRunning = false;
|
|
|
|
|
+ _isHubClientConnected = false;
|
|
|
|
|
+ if (changed) RaiseStatusChanged();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ─── 事件处理器 ───
|
|
|
|
|
+
|
|
|
|
|
+ private void OnPlcConnectionChanged(bool connected)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool changed;
|
|
|
|
|
+ lock (_lock)
|
|
|
|
|
+ {
|
|
|
|
|
+ changed = _isPlcConnected != connected;
|
|
|
|
|
+ _isPlcConnected = connected;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (changed) RaiseStatusChanged();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void OnPlcDataUpdated(PlcDataModel data)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool changed;
|
|
|
|
|
+ lock (_lock)
|
|
|
|
|
+ {
|
|
|
|
|
+ changed = _isPlcConnected != data.IsPlcConnected;
|
|
|
|
|
+ _isPlcConnected = data.IsPlcConnected;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (changed) RaiseStatusChanged();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void OnHubServerRunningChanged(bool running)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool changed;
|
|
|
|
|
+ lock (_lock)
|
|
|
|
|
+ {
|
|
|
|
|
+ changed = _isHubServerRunning != running;
|
|
|
|
|
+ _isHubServerRunning = running;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (changed) RaiseStatusChanged();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void OnHubClientConnectionChanged(bool connected)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool changed;
|
|
|
|
|
+ lock (_lock)
|
|
|
|
|
+ {
|
|
|
|
|
+ changed = _isHubClientConnected != connected;
|
|
|
|
|
+ _isHubClientConnected = connected;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (changed) RaiseStatusChanged();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void RaiseStatusChanged()
|
|
|
|
|
+ {
|
|
|
|
|
+ StatusChanged?.Invoke();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void Dispose()
|
|
|
|
|
+ {
|
|
|
|
|
+ PlcService.ConnectionChanged -= OnPlcConnectionChanged;
|
|
|
|
|
+ PlcPollingService.Instance.DataUpdated -= OnPlcDataUpdated;
|
|
|
|
|
+ UnregisterHubs();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|