fix(edge): 配置同步后清理 SQLite 中的旧摄像头/ROI/绑定记录

- _sync_config_to_sqlite 增加旧数据清理逻辑
- 同步完成后删除不在本次推送列表中的摄像头、ROI 及关联算法绑定
- 仅在推送列表非空时执行清理,防止空配置误删所有数据
- 解决旧摄像头残留导致 Edge 加载过期配置的问题

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 19:58:58 +08:00
parent b2469c576c
commit 3ca6c93479

View File

@@ -528,10 +528,14 @@ class ConfigSyncManager:
try: try:
# 同步摄像头配置 # 同步摄像头配置
cameras = config_data.get("cameras", []) cameras = config_data.get("cameras", [])
incoming_camera_ids = set()
for cam in cameras: for cam in cameras:
cam_id = cam.get("camera_id", "")
if cam_id:
incoming_camera_ids.add(cam_id)
try: try:
self._db_manager.save_camera_config( self._db_manager.save_camera_config(
camera_id=cam.get("camera_id", ""), camera_id=cam_id,
rtsp_url=cam.get("rtsp_url", ""), rtsp_url=cam.get("rtsp_url", ""),
camera_name=cam.get("camera_name", ""), camera_name=cam.get("camera_name", ""),
enabled=cam.get("enabled", True), enabled=cam.get("enabled", True),
@@ -543,13 +547,16 @@ class ConfigSyncManager:
# 同步 ROI 配置 # 同步 ROI 配置
rois = config_data.get("rois", []) rois = config_data.get("rois", [])
incoming_roi_ids = set()
for roi in rois: for roi in rois:
if not isinstance(roi, dict): 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 continue
roi_id = roi.get("roi_id", "")
if roi_id:
incoming_roi_ids.add(roi_id)
try: try:
coordinates = roi.get("coordinates", []) coordinates = roi.get("coordinates", [])
# ?? rectangle dict ? polygon list-of-dict ??
if isinstance(coordinates, dict): if isinstance(coordinates, dict):
coordinates = { coordinates = {
"x": coordinates.get("x", 0), "x": coordinates.get("x", 0),
@@ -561,7 +568,7 @@ class ConfigSyncManager:
coordinates = [[p.get("x", 0), p.get("y", 0)] for p in coordinates] coordinates = [[p.get("x", 0), p.get("y", 0)] for p in coordinates]
self._db_manager.save_roi_config( self._db_manager.save_roi_config(
roi_id=roi.get("roi_id", ""), roi_id=roi_id,
camera_id=roi.get("camera_id", ""), camera_id=roi.get("camera_id", ""),
roi_type=roi.get("roi_type", "polygon"), roi_type=roi.get("roi_type", "polygon"),
coordinates=coordinates, coordinates=coordinates,
@@ -574,10 +581,14 @@ class ConfigSyncManager:
# 同步算法绑定 # 同步算法绑定
binds = config_data.get("binds", []) binds = config_data.get("binds", [])
incoming_bind_ids = set()
for bind in binds: for bind in binds:
bind_id = bind.get("bind_id", "")
if bind_id:
incoming_bind_ids.add(bind_id)
try: try:
self._db_manager.save_roi_algo_bind( self._db_manager.save_roi_algo_bind(
bind_id=bind.get("bind_id", ""), bind_id=bind_id,
roi_id=bind.get("roi_id", ""), roi_id=bind.get("roi_id", ""),
algo_code=bind.get("algo_code", ""), algo_code=bind.get("algo_code", ""),
params=bind.get("params", {}), params=bind.get("params", {}),
@@ -590,9 +601,51 @@ class ConfigSyncManager:
logger.info(f"配置同步到 SQLite 完成: {count} 条记录") logger.info(f"配置同步到 SQLite 完成: {count} 条记录")
# 清理 SQLite 中不在本次推送列表中的旧数据
self._cleanup_stale_records(incoming_camera_ids, incoming_roi_ids, incoming_bind_ids)
except Exception as e: except Exception as e:
logger.error(f"配置同步到 SQLite 失败: {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): def register_callback(self, topic: str, callback: Callable):