117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
from fastapi import APIRouter, Depends
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Optional
|
|
|
|
from db.models import get_db
|
|
from services.sync_service import get_sync_service
|
|
|
|
router = APIRouter(prefix="/api/sync", tags=["同步"])
|
|
|
|
|
|
@router.get("/status")
|
|
def get_sync_status(db: Session = Depends(get_db)):
|
|
"""获取同步服务状态"""
|
|
from sqlalchemy import text
|
|
|
|
service = get_sync_service()
|
|
status = service.get_status()
|
|
|
|
pending_cameras = db.execute(
|
|
text("SELECT COUNT(*) FROM cameras WHERE pending_sync = 1")
|
|
).scalar() or 0
|
|
|
|
pending_rois = db.execute(
|
|
text("SELECT COUNT(*) FROM rois WHERE pending_sync = 1")
|
|
).scalar() or 0
|
|
|
|
pending_alarms = db.execute(
|
|
text("SELECT COUNT(*) FROM alarms WHERE upload_status = 'pending' OR upload_status = 'retry'")
|
|
).scalar() or 0
|
|
|
|
return {
|
|
"running": status["running"],
|
|
"cloud_enabled": status["cloud_enabled"],
|
|
"network_status": status["network_status"],
|
|
"device_id": status["device_id"],
|
|
"pending_sync": pending_cameras + pending_rois,
|
|
"pending_alarms": pending_alarms,
|
|
"details": {
|
|
"pending_cameras": pending_cameras,
|
|
"pending_rois": pending_rois,
|
|
"pending_alarms": pending_alarms
|
|
}
|
|
}
|
|
|
|
|
|
@router.get("/pending")
|
|
def get_pending_syncs(db: Session = Depends(get_db)):
|
|
"""获取待同步项列表"""
|
|
from sqlalchemy import text
|
|
from db.models import Camera, ROI, Alarm
|
|
|
|
pending_cameras = db.query(Camera).filter(Camera.pending_sync == True).all()
|
|
pending_rois = db.query(ROI).filter(ROI.pending_sync == True).all()
|
|
|
|
from db.session import SessionLocal
|
|
temp_db = SessionLocal()
|
|
try:
|
|
pending_alarms = temp_db.query(Alarm).filter(
|
|
Alarm.upload_status.in_(['pending', 'retry'])
|
|
).limit(100).all()
|
|
finally:
|
|
temp_db.close()
|
|
|
|
return {
|
|
"cameras": [{"id": c.id, "name": c.name} for c in pending_cameras],
|
|
"rois": [{"id": r.id, "name": r.name, "camera_id": r.camera_id} for r in pending_rois],
|
|
"alarms": [{"id": a.id, "camera_id": a.camera_id, "type": a.event_type} for a in pending_alarms]
|
|
}
|
|
|
|
|
|
@router.post("/trigger")
|
|
def trigger_sync():
|
|
"""手动触发同步"""
|
|
service = get_sync_service()
|
|
from db.session import SessionLocal
|
|
from db.crud import get_all_cameras, get_all_rois
|
|
from db.models import Camera, ROI
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
cameras = get_all_cameras(db)
|
|
for camera in cameras:
|
|
service.queue_camera_sync(camera.id, 'update', {
|
|
'name': camera.name,
|
|
'rtsp_url': camera.rtsp_url,
|
|
'enabled': camera.enabled
|
|
})
|
|
db.query(Camera).filter(Camera.id == camera.id).update({'pending_sync': False})
|
|
db.commit()
|
|
|
|
rois = get_all_rois(db)
|
|
for roi in rois:
|
|
service.queue_roi_sync(roi.id, 'update', {
|
|
'name': roi.name,
|
|
'roi_type': roi.roi_type,
|
|
'points': roi.points,
|
|
'enabled': roi.enabled
|
|
})
|
|
db.query(ROI).filter(ROI.id == roi.id).update({'pending_sync': False})
|
|
db.commit()
|
|
|
|
return {"message": "同步任务已加入队列", "count": len(cameras) + len(rois)}
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@router.post("/clear-failed")
|
|
def clear_failed_syncs(db: Session = Depends(get_db)):
|
|
"""清除失败的同步标记"""
|
|
from sqlalchemy import text
|
|
|
|
db.execute(text("UPDATE cameras SET pending_sync = 0, sync_failed_at = NULL, sync_retry_count = 0"))
|
|
db.execute(text("UPDATE rois SET pending_sync = 0, sync_failed_at = NULL, sync_retry_count = 0"))
|
|
db.commit()
|
|
|
|
return {"message": "已清除所有失败的同步标记"}
|