video_monitor/app/analysis/event_bridge.py

102 lines
2.9 KiB
Python
Raw Normal View History

2026-08-30 22:22:11 +08:00
"""分析事件桥 — 消费子进程 event_queue在主进程写库"""
import logging
import queue
import threading
logger = logging.getLogger("analysis.event_bridge")
_BRIDGE = None
_BRIDGE_LOCK = threading.Lock()
class AnalysisEventBridge(object):
def __init__(self):
self._thread = None
self._running = False
self._queues = []
self._lock = threading.Lock()
2026-09-04 18:16:14 +08:00
self._latest = {}
2026-08-30 22:22:11 +08:00
def register_queue(self, q):
with self._lock:
if q not in self._queues:
self._queues.append(q)
def unregister_queue(self, q):
with self._lock:
if q in self._queues:
self._queues.remove(q)
def start(self):
if self._running:
return
self._running = True
self._thread = threading.Thread(target=self._loop, name="analysis-event-bridge", daemon=True)
self._thread.start()
logger.info("AnalysisEventBridge 已启动")
def _loop(self):
while self._running:
handled = False
with self._lock:
queues = list(self._queues)
for q in queues:
try:
while True:
msg = q.get_nowait()
self._handle(msg)
handled = True
except queue.Empty:
continue
if not handled:
threading.Event().wait(0.05)
def _handle(self, msg):
if not msg or len(msg) < 2:
return
kind, payload = msg[0], msg[1]
try:
if kind == "event":
self._on_event(payload)
elif kind == "touch":
self._on_touch(payload)
2026-09-04 18:16:14 +08:00
elif kind == "preview":
self._on_preview(payload)
2026-08-30 22:22:11 +08:00
except Exception as e:
logger.exception("事件桥处理失败: %s", e)
def _on_event(self, event):
from app.services.alarm_service import write_alarm, ALARM_EVENT_TYPES
etype = event.get("type", "")
if etype in ALARM_EVENT_TYPES:
write_alarm(event)
def _on_touch(self, payload):
# 已停用:不再写追踪快照
pass
2026-09-04 18:16:14 +08:00
def _on_preview(self, payload):
stream_id = payload.get("stream_id")
if stream_id is None:
return
with self._lock:
self._latest[int(stream_id)] = payload
def latest_preview(self, stream_id):
with self._lock:
value = self._latest.get(int(stream_id))
return dict(value) if value else None
def clear_preview(self, stream_id):
with self._lock:
self._latest.pop(int(stream_id), None)
2026-08-30 22:22:11 +08:00
def get_event_bridge():
global _BRIDGE
with _BRIDGE_LOCK:
if _BRIDGE is None:
_BRIDGE = AnalysisEventBridge()
_BRIDGE.start()
return _BRIDGE