diff --git a/core/config_sync.py b/core/config_sync.py index d2e4f0c..7bad3e8 100644 --- a/core/config_sync.py +++ b/core/config_sync.py @@ -528,10 +528,14 @@ class ConfigSyncManager: try: # 同步摄像头配置 cameras = config_data.get("cameras", []) + incoming_camera_ids = set() for cam in cameras: + cam_id = cam.get("camera_id", "") + if cam_id: + incoming_camera_ids.add(cam_id) try: self._db_manager.save_camera_config( - camera_id=cam.get("camera_id", ""), + camera_id=cam_id, rtsp_url=cam.get("rtsp_url", ""), camera_name=cam.get("camera_name", ""), enabled=cam.get("enabled", True), @@ -543,13 +547,16 @@ class ConfigSyncManager: # 同步 ROI 配置 rois = config_data.get("rois", []) + incoming_roi_ids = set() for roi in rois: if not isinstance(roi, dict): - logger.error(f"?? ROI ????: invalid roi item type={type(roi)}") + logger.error(f"无效 ROI 数据: invalid roi item type={type(roi)}") continue + roi_id = roi.get("roi_id", "") + if roi_id: + incoming_roi_ids.add(roi_id) try: coordinates = roi.get("coordinates", []) - # ?? rectangle dict ? polygon list-of-dict ?? if isinstance(coordinates, dict): coordinates = { "x": coordinates.get("x", 0), @@ -561,7 +568,7 @@ class ConfigSyncManager: coordinates = [[p.get("x", 0), p.get("y", 0)] for p in coordinates] self._db_manager.save_roi_config( - roi_id=roi.get("roi_id", ""), + roi_id=roi_id, camera_id=roi.get("camera_id", ""), roi_type=roi.get("roi_type", "polygon"), coordinates=coordinates, @@ -574,10 +581,14 @@ class ConfigSyncManager: # 同步算法绑定 binds = config_data.get("binds", []) + incoming_bind_ids = set() for bind in binds: + bind_id = bind.get("bind_id", "") + if bind_id: + incoming_bind_ids.add(bind_id) try: self._db_manager.save_roi_algo_bind( - bind_id=bind.get("bind_id", ""), + bind_id=bind_id, roi_id=bind.get("roi_id", ""), algo_code=bind.get("algo_code", ""), params=bind.get("params", {}), @@ -590,9 +601,51 @@ class ConfigSyncManager: logger.info(f"配置同步到 SQLite 完成: {count} 条记录") + # 清理 SQLite 中不在本次推送列表中的旧数据 + self._cleanup_stale_records(incoming_camera_ids, incoming_roi_ids, incoming_bind_ids) + except Exception as e: logger.error(f"配置同步到 SQLite 失败: {e}") + def _cleanup_stale_records(self, incoming_camera_ids: set, incoming_roi_ids: set, incoming_bind_ids: set): + """清理 SQLite 中不在本次推送列表中的旧记录""" + if not self._db_manager: + return + + # 仅在推送列表非空时执行清理,防止空配置误删所有数据 + if not incoming_camera_ids and not incoming_roi_ids: + logger.debug("推送列表为空,跳过旧数据清理") + return + + removed = 0 + try: + # 清理旧摄像头 + if incoming_camera_ids: + existing_cameras = self._db_manager.get_all_camera_configs() + for cam in existing_cameras: + old_id = cam.get("camera_id", "") + if old_id and old_id not in incoming_camera_ids: + self._db_manager.delete_camera_config(old_id) + removed += 1 + logger.info(f"清理旧摄像头: {old_id}") + + # 清理旧 ROI 及其关联的算法绑定 + if incoming_roi_ids: + existing_rois = self._db_manager.get_all_roi_configs() + for roi in existing_rois: + old_roi_id = roi.get("roi_id", "") + if old_roi_id and old_roi_id not in incoming_roi_ids: + bind_count = self._db_manager.delete_bindings_by_roi(old_roi_id) + self._db_manager.delete_roi_config(old_roi_id) + removed += 1 + bind_count + logger.info(f"清理旧 ROI: {old_roi_id} (含 {bind_count} 条算法绑定)") + + if removed > 0: + logger.info(f"旧数据清理完成: 共删除 {removed} 条过期记录") + + except Exception as e: + logger.error(f"清理旧数据失败: {e}") + # ==================== 回调管理 ==================== def register_callback(self, topic: str, callback: Callable):