using System.Collections.Concurrent; using System.Diagnostics; namespace SHH.MjpegPlayer { /// /// 设备配置同步处理器 (原 ConfigSyncManager 瘦身版) /// 职责:仅负责确保远程分析节点(Instance)的摄像头配置与本地数据库一致。 /// 逻辑:通过 5 秒初始化冷却期避开抖动,并利用配置快照对比实现增量同步。 /// public class DeviceConfigHandler { #region 单例与核心存储字段 /// /// 获取配置处理器的全局单例实例 /// public static DeviceConfigHandler Instance { get; } = new DeviceConfigHandler(); /// /// 活跃服务实例 ID 集合 (InstanceId) /// 用于记录当前所有已建立 gRpc 长连接的远程节点 /// private readonly ConcurrentHashSet _activeServiceIds = new ConcurrentHashSet(); /// /// 配置快照缓存:用于防止重复下发相同的配置 /// Key 格式: "InstanceId_CameraId" /// Value: 该摄像头配置的 JSON 字符串快照 /// private readonly ConcurrentDictionary _lastSentConfigCache = new ConcurrentDictionary(); /// /// 后台监控任务的任务取消令牌源 /// private CancellationTokenSource _cts; /// /// 初始化完成时间戳:用于 5 秒冷却期判定 /// 防止在服务刚启动或节点刚连接时,由于数据库加载延迟导致误判设备被移除 /// private DateTime _initCompleteTime = DateTime.MaxValue; #endregion #region 构造函数与初始化 /// /// 私有构造函数:订阅消息总线并启动监控任务 /// private DeviceConfigHandler() { // 订阅总线:仅关注节点注册事件,以此作为触发初始化全量同步的开关 MessageBus.Instance.OnServerRegistered += async (payload) => { await HandleServiceOnlineAsync(payload.InstanceId); }; // 启动后台轮询监控任务 (检测 Add/Update/Remove) StartMonitorTask(); } #endregion #region 核心业务处理 (节点上线) /// /// 处理新节点上线:执行全量同步 /// /// 远程服务实例唯一标识 private async Task HandleServiceOnlineAsync(string instanceId) { // 1. 将新实例记录到活跃列表 _activeServiceIds.Add(instanceId); // 2. 预留 1 秒等待期,确保 gRpc 双向通道完全稳定 await Task.Delay(1000); //// 3. 从数据库拍摄当前所有摄像头的快照 //var snapshot = CSdkStatics.DbCameras.ToList(); //// 4. 对新节点执行全量下发 //foreach (var cam in snapshot) //{ // await SendSyncCommandAsync(instanceId, cam); //} // 5. 更新冷却期起始点 _initCompleteTime = DateTime.Now; Debug.WriteLine($"[ConfigHandler] 节点 {instanceId} 初始化全量同步已完成。"); } #endregion #region 后台监控任务 (增量同步) /// /// 启动后台增量监控任务 /// private void StartMonitorTask() { } #endregion } }