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:
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user