""" 事件管理器模块 提供事件的注册、分发和管理: - 优先级事件处理 - 处理器缓存优化 - 事件统计 - 异常隔离 """ import asyncio import time import traceback from collections import defaultdict from dataclasses import dataclass, field from typing import Any, Callable, Dict, List, Optional, Set, Tuple from loguru import logger @dataclass class HandlerInfo: """事件处理器信息""" handler: Callable instance: object priority: int handler_name: str = field(default="") def __post_init__(self): if not self.handler_name: self.handler_name = f"{self.instance.__class__.__name__}.{self.handler.__name__}" @dataclass class EventStats: """事件统计信息""" emit_count: int = 0 handler_calls: int = 0 total_time_ms: float = 0 error_count: int = 0 stopped_count: int = 0 # 被 return False 中断的次数 class EventManager: """ 事件管理器 特性: - 优先级排序(高优先级先执行) - 处理器可返回 False 中断后续处理 - 异常隔离(单个处理器异常不影响其他) - 性能统计 """ # 类级别存储 _handlers: Dict[str, List[HandlerInfo]] = {} _stats: Dict[str, EventStats] = defaultdict(EventStats) _handler_cache: Dict[str, List[HandlerInfo]] = {} # 排序后的缓存 _cache_valid: Set[str] = set() @classmethod def bind_instance(cls, instance: object): """ 绑定实例的事件处理方法 扫描实例的所有方法,将带有 _event_type 属性的方法注册为事件处理器。 Args: instance: 插件实例 """ registered_count = 0 for method_name in dir(instance): if method_name.startswith('_'): continue try: method = getattr(instance, method_name) except Exception: continue if not callable(method) or not hasattr(method, '_event_type'): continue event_type = getattr(method, '_event_type') priority = getattr(method, '_priority', 50) handler_info = HandlerInfo( handler=method, instance=instance, priority=priority, ) if event_type not in cls._handlers: cls._handlers[event_type] = [] cls._handlers[event_type].append(handler_info) # 使缓存失效 cls._cache_valid.discard(event_type) registered_count += 1 logger.debug( f"[EventManager] 注册: {handler_info.handler_name} -> " f"{event_type} (优先级={priority})" ) if registered_count > 0: logger.success( f"[EventManager] {instance.__class__.__name__} " f"注册了 {registered_count} 个事件处理器" ) @classmethod def unbind_instance(cls, instance: object): """ 解绑实例的所有事件处理器 Args: instance: 插件实例 """ unbound_count = 0 for event_type in list(cls._handlers.keys()): original_count = len(cls._handlers[event_type]) cls._handlers[event_type] = [ h for h in cls._handlers[event_type] if h.instance is not instance ] removed = original_count - len(cls._handlers[event_type]) if removed > 0: unbound_count += removed cls._cache_valid.discard(event_type) # 清理空列表 if not cls._handlers[event_type]: del cls._handlers[event_type] if unbound_count > 0: logger.debug( f"[EventManager] {instance.__class__.__name__} " f"解绑了 {unbound_count} 个事件处理器" ) @classmethod def _get_sorted_handlers(cls, event_type: str) -> List[HandlerInfo]: """获取排序后的处理器列表(带缓存)""" if event_type not in cls._cache_valid: handlers = cls._handlers.get(event_type, []) # 按优先级降序排序 cls._handler_cache[event_type] = sorted( handlers, key=lambda h: h.priority, reverse=True ) cls._cache_valid.add(event_type) return cls._handler_cache.get(event_type, []) @classmethod async def emit(cls, event_type: str, *args, **kwargs) -> bool: """ 触发事件 Args: event_type: 事件类型 *args: 传递给处理器的位置参数(通常是 api_client, message) **kwargs: 传递给处理器的关键字参数 Returns: True 表示所有处理器都执行了,False 表示被中断 """ handlers = cls._get_sorted_handlers(event_type) if not handlers: logger.debug(f"[EventManager] 事件 {event_type} 没有处理器") return True # 更新统计 stats = cls._stats[event_type] stats.emit_count += 1 start_time = time.time() all_completed = True logger.debug( f"[EventManager] 触发: {event_type}, " f"处理器数量: {len(handlers)}" ) for handler_info in handlers: stats.handler_calls += 1 try: logger.debug(f"[EventManager] 调用: {handler_info.handler_name}") result = await handler_info.handler(*args, **kwargs) # 检查是否中断 if result is False: stats.stopped_count += 1 all_completed = False logger.debug( f"[EventManager] {handler_info.handler_name} " f"返回 False,中断事件处理" ) break except Exception as e: stats.error_count += 1 logger.error( f"[EventManager] {handler_info.handler_name} 执行失败: {e}" ) logger.debug(f"详细错误:\n{traceback.format_exc()}") # 继续执行其他处理器 elapsed_ms = (time.time() - start_time) * 1000 stats.total_time_ms += elapsed_ms return all_completed @classmethod async def emit_parallel( cls, event_type: str, *args, max_concurrency: int = 5, **kwargs ) -> List[Any]: """ 并行触发事件(忽略优先级和中断) 适用于不需要顺序执行的场景。 Args: event_type: 事件类型 max_concurrency: 最大并发数 *args, **kwargs: 传递给处理器的参数 Returns: 所有处理器的返回值列表 """ handlers = cls._get_sorted_handlers(event_type) if not handlers: return [] semaphore = asyncio.Semaphore(max_concurrency) async def run_handler(handler_info: HandlerInfo): async with semaphore: try: return await handler_info.handler(*args, **kwargs) except Exception as e: logger.error(f"[EventManager] {handler_info.handler_name} 失败: {e}") return None tasks = [run_handler(h) for h in handlers] return await asyncio.gather(*tasks, return_exceptions=True) @classmethod def get_handlers(cls, event_type: str) -> List[str]: """获取事件的所有处理器名称""" handlers = cls._get_sorted_handlers(event_type) return [h.handler_name for h in handlers] @classmethod def get_all_events(cls) -> List[str]: """获取所有已注册的事件类型""" return list(cls._handlers.keys()) @classmethod def get_stats(cls, event_type: str = None) -> Dict[str, Any]: """ 获取事件统计信息 Args: event_type: 指定事件类型,None 返回所有 Returns: 统计信息字典 """ if event_type: stats = cls._stats.get(event_type, EventStats()) return { "emit_count": stats.emit_count, "handler_calls": stats.handler_calls, "total_time_ms": stats.total_time_ms, "avg_time_ms": stats.total_time_ms / max(stats.emit_count, 1), "error_count": stats.error_count, "stopped_count": stats.stopped_count, } return { event: cls.get_stats(event) for event in cls._stats.keys() } @classmethod def reset_stats(cls): """重置所有统计""" cls._stats.clear() @classmethod def clear(cls): """清除所有处理器和统计(用于测试)""" cls._handlers.clear() cls._handler_cache.clear() cls._cache_valid.clear() cls._stats.clear() # ==================== 导出 ==================== __all__ = ['EventManager', 'HandlerInfo', 'EventStats']