格式统一

This commit is contained in:
duxin
2026-07-01 09:57:27 +08:00
parent c793ea2204
commit a3c20d3e49
37 changed files with 2286 additions and 1978 deletions

View File

@ -11,16 +11,19 @@
- 新增 unsubscribe() 方法,允许面板销毁时清理订阅,防止内存泄漏和野指针回调
"""
import sys
import threading
import traceback
from collections import defaultdict
from typing import Any, Callable, Dict, List, Optional
class EventBus:
"""发布-订阅事件总线"""
"""发布-订阅事件总线(线程安全)。"""
def __init__(self):
self._subscribers: Dict[str, List[Callable]] = defaultdict(list)
self._lock = threading.Lock()
# 异常日志回调(可选注入,供 LogManager 使用)
self._error_logger: Optional[Callable[[str], None]] = None
@ -30,38 +33,42 @@ class EventBus:
def subscribe(self, event_name: str, callback: Callable[[dict], None]):
"""订阅事件。callback 接收一个 dict 作为事件数据。"""
if callback not in self._subscribers[event_name]:
self._subscribers[event_name].append(callback)
with self._lock:
if callback not in self._subscribers[event_name]:
self._subscribers[event_name].append(callback)
def unsubscribe(self, event_name: str, callback: Callable[[dict], None]):
"""取消订阅。面板销毁或不再需要接收事件时调用,防止野指针回调。"""
subs = self._subscribers.get(event_name)
if subs and callback in subs:
subs.remove(callback)
# 清理空列表,避免字典膨胀
if not subs:
del self._subscribers[event_name]
with self._lock:
subs = self._subscribers.get(event_name)
if subs and callback in subs:
subs.remove(callback)
# 清理空列表,避免字典膨胀
if not subs:
del self._subscribers[event_name]
def publish(self, event_name: str, data: Dict[str, Any]):
"""发布事件,通知所有订阅者。订阅者异常不再静默吞掉,而是输出 traceback。
迭代订阅者列表的副本,防止回调中调用 unsubscribe() 导致跳过后续订阅者。
"""
for callback in list(self._subscribers.get(event_name, [])):
with self._lock:
snapshot = list(self._subscribers.get(event_name, []))
for callback in snapshot:
try:
callback(data)
except Exception:
cb_name = getattr(callback, '__name__', None) or repr(callback)
err_msg = (
f"[EventBus] 事件 '{event_name}' 的订阅者 {callback.__name__!r} 抛出异常:\n"
f"[EventBus] 事件 '{event_name}' 的订阅者 {cb_name!r} 抛出异常:\n"
+ traceback.format_exc()
)
if self._error_logger:
try:
self._error_logger(err_msg)
except Exception:
pass
print(err_msg, file=sys.stderr, flush=True)
else:
import sys
print(err_msg, file=sys.stderr, flush=True)