""" 插件管理器 统一管理和协调所有插件系统 """ import asyncio import importlib import inspect import threading from pathlib import Path from typing import Any, Dict, List, Optional, Type from src.core.logger import logger from src.plugins.auth.base import AuthPlugin from src.plugins.cache.base import CachePlugin # 移除审计插件 - 审计功能现在是核心服务,不再作为插件 from src.plugins.common import BasePlugin, HealthStatus, PluginMetadata from src.plugins.load_balancer.base import LoadBalancerStrategy from src.plugins.monitor.base import MonitorPlugin from src.plugins.notification.base import NotificationPlugin from src.plugins.rate_limit.base import RateLimitStrategy from src.plugins.token.base import TokenCounterPlugin class PluginManager: """ 统一的插件管理器 负责加载、配置和管理所有类型的插件 """ # 当前支持的 API 版本 SUPPORTED_API_VERSION = "1.0" # 插件类型映射 PLUGIN_TYPES = { "auth": AuthPlugin, "rate_limit": RateLimitStrategy, "cache": CachePlugin, "monitor": MonitorPlugin, "token": TokenCounterPlugin, "notification": NotificationPlugin, "load_balancer": LoadBalancerStrategy, # 移除 "audit" - 审计功能现在是核心服务 } def __init__(self, config: Optional[Dict[str, Any]] = None): """ 初始化插件管理器 Args: config: 配置字典 """ self.config = config or {} self.plugins: Dict[str, Dict[str, Any]] = { "auth": {}, "rate_limit": {}, "cache": {}, "monitor": {}, "token": {}, "notification": {}, "load_balancer": {}, # 移除 "audit" - 审计功能现在是核心服务 } self.default_plugins: Dict[str, Optional[str]] = { "auth": None, "rate_limit": None, "cache": None, "monitor": None, "token": None, "notification": None, "load_balancer": "sticky_priority", # 默认使用粘性优先级策略 # 移除 "audit" - 审计功能现在是核心服务 } # 跟踪因版本不兼容而跳过的插件 self._incompatible_plugins: List[str] = [] # 自动发现和加载插件 self._auto_discover_plugins() # 应用配置 self._apply_config() def _auto_discover_plugins(self): """自动发现和加载插件""" plugins_dir = Path(__file__).parent for plugin_type in self.PLUGIN_TYPES: type_dir = plugins_dir / plugin_type if not type_dir.exists(): continue # 扫描插件目录 for file_path in type_dir.glob("*.py"): if file_path.name.startswith("_") or file_path.name == "base.py": continue module_name = f"src.plugins.{plugin_type}.{file_path.stem}" try: module = importlib.import_module(module_name) self._load_plugin_from_module(module, plugin_type) except Exception as e: logger.error(f"Failed to load plugin module {module_name}: {e}") def _is_api_version_compatible(self, plugin_api_version: str) -> bool: """ 检查插件 API 版本是否兼容 采用语义化版本的主版本号兼容策略: - 主版本号相同则兼容 - 例如: 支持版本 "1.0",插件版本 "1.0", "1.1", "1.2" 都兼容 Args: plugin_api_version: 插件声明的 API 版本 Returns: 是否兼容 """ try: supported_major = self.SUPPORTED_API_VERSION.split(".")[0] plugin_major = plugin_api_version.split(".")[0] return supported_major == plugin_major except (ValueError, IndexError): # 解析失败,假设兼容 return True def _load_plugin_from_module(self, module: Any, plugin_type: str): """从模块加载插件类""" base_class = self.PLUGIN_TYPES[plugin_type] for name, obj in inspect.getmembers(module): if inspect.isclass(obj) and issubclass(obj, base_class) and obj != base_class: # 实例化插件 try: plugin_instance = obj() # 检查 API 版本兼容性 plugin_api_version = getattr(plugin_instance.metadata, "api_version", "1.0") if not self._is_api_version_compatible(plugin_api_version): logger.warning(f"Plugin {plugin_instance.name} has incompatible API version " f"{plugin_api_version} (supported: {self.SUPPORTED_API_VERSION}), " f"plugin will be disabled") plugin_instance.enabled = False self._incompatible_plugins.append(plugin_instance.name) self.register_plugin(plugin_type, plugin_instance) logger.info(f"Loaded {plugin_type} plugin: {plugin_instance.name}") except Exception as e: logger.error(f"Failed to instantiate plugin {name}: {e}") def _apply_config(self): """应用配置到插件""" for plugin_type, plugins in self.plugins.items(): type_config = self.config.get(plugin_type, {}) # 设置默认插件 if "default" in type_config: self.default_plugins[plugin_type] = type_config["default"] # 配置各个插件 for plugin_name, plugin in plugins.items(): plugin_config = type_config.get(plugin_name, {}) if plugin_config: plugin.configure(plugin_config) def register_plugin(self, plugin_type: str, plugin: Any, set_as_default: bool = False): """ 注册插件 Args: plugin_type: 插件类型 plugin: 插件实例 set_as_default: 是否设为默认 """ if plugin_type not in self.plugins: raise ValueError(f"Unknown plugin type: {plugin_type}") # 验证插件类型 base_class = self.PLUGIN_TYPES[plugin_type] if not isinstance(plugin, base_class): raise TypeError( f"Plugin must be instance of {base_class.__name__}, " f"got {type(plugin).__name__}" ) # 注册插件 self.plugins[plugin_type][plugin.name] = plugin # 设为默认 if set_as_default or not self.default_plugins[plugin_type]: self.default_plugins[plugin_type] = plugin.name logger.debug(f"Registered {plugin_type} plugin: {plugin.name}") def unregister_plugin(self, plugin_type: str, plugin_name: str): """ 注销插件 Args: plugin_type: 插件类型 plugin_name: 插件名称 """ if plugin_type in self.plugins: if plugin_name in self.plugins[plugin_type]: del self.plugins[plugin_type][plugin_name] # 如果是默认插件,清除默认设置 if self.default_plugins[plugin_type] == plugin_name: self.default_plugins[plugin_type] = None logger.debug(f"Unregistered {plugin_type} plugin: {plugin_name}") def get_plugin(self, plugin_type: str, plugin_name: Optional[str] = None) -> Optional[Any]: """ 获取插件实例 Args: plugin_type: 插件类型 plugin_name: 插件名称,不指定则返回默认插件 Returns: 插件实例,如果不存在返回None """ if plugin_type not in self.plugins: return None if plugin_name: return self.plugins[plugin_type].get(plugin_name) # 返回默认插件 default_name = self.default_plugins[plugin_type] if default_name: return self.plugins[plugin_type].get(default_name) # 如果没有默认插件,返回第一个可用的 if self.plugins[plugin_type]: return next(iter(self.plugins[plugin_type].values())) return None def get_plugins_by_type(self, plugin_type: str) -> List[Any]: """ 获取某个类型的所有插件 Args: plugin_type: 插件类型 Returns: 插件列表 """ if plugin_type not in self.plugins: return [] return list(self.plugins[plugin_type].values()) def get_enabled_plugins(self, plugin_type: str) -> List[Any]: """ 获取某个类型的所有启用的插件 Args: plugin_type: 插件类型 Returns: 启用的插件列表 """ plugins = self.get_plugins_by_type(plugin_type) return [p for p in plugins if getattr(p, "enabled", True)] async def execute_plugin_chain( self, plugin_type: str, method_name: str, *args, **kwargs ) -> Any: """ 执行插件链(按优先级) Args: plugin_type: 插件类型 method_name: 要调用的方法名 *args: 位置参数 **kwargs: 关键字参数 Returns: 第一个成功的结果 """ plugins = self.get_enabled_plugins(plugin_type) # 按优先级排序(如果有priority属性) plugins.sort(key=lambda p: getattr(p, "priority", 0), reverse=True) for plugin in plugins: if hasattr(plugin, method_name): method = getattr(plugin, method_name) try: if asyncio.iscoroutinefunction(method): result = await method(*args, **kwargs) else: result = method(*args, **kwargs) if result is not None: return result except Exception as e: logger.error(f"Plugin {plugin.name} failed in {method_name}: {e}") return None def get_stats(self) -> Dict[str, Any]: """ 获取插件管理器统计信息 Returns: 统计信息字典 """ stats = { "supported_api_version": self.SUPPORTED_API_VERSION, "plugin_counts": {}, "enabled_counts": {}, "default_plugins": self.default_plugins, "plugin_details": {}, "incompatible_plugins": self._incompatible_plugins, } for plugin_type in self.PLUGIN_TYPES: all_plugins = self.get_plugins_by_type(plugin_type) enabled_plugins = self.get_enabled_plugins(plugin_type) stats["plugin_counts"][plugin_type] = len(all_plugins) stats["enabled_counts"][plugin_type] = len(enabled_plugins) # 详细信息 stats["plugin_details"][plugin_type] = [ { "name": p.name, "enabled": getattr(p, "enabled", True), "priority": getattr(p, "priority", 0), "class": type(p).__name__, "api_version": getattr(p.metadata, "api_version", "unknown"), "version": getattr(p.metadata, "version", "unknown"), } for p in all_plugins ] return stats async def initialize_all(self) -> Dict[str, bool]: """ 初始化所有插件 初始化失败的插件会被自动禁用,防止后续使用未正确初始化的插件。 Returns: 初始化结果字典 {plugin_name: success} """ results = {} # 获取所有插件并按依赖顺序排序 all_plugins = [] for plugin_type in self.PLUGIN_TYPES: all_plugins.extend(self.get_plugins_by_type(plugin_type)) # 拓扑排序处理依赖 sorted_plugins = self._sort_plugins_by_dependencies(all_plugins) # 按顺序初始化插件 for plugin in sorted_plugins: try: # 检查插件是否有 initialize 方法 if not hasattr(plugin, "initialize"): # 如果没有 initialize 方法,假设插件已经初始化完成 logger.debug(f"Plugin {plugin.name} has no initialize() method, skipping") results[f"{plugin.name}"] = True continue success = await plugin.initialize() results[f"{plugin.name}"] = success if success: logger.info(f"Successfully initialized plugin: {plugin.name}") else: # 初始化失败,禁用插件 plugin.enabled = False logger.error(f"Failed to initialize plugin: {plugin.name}, plugin has been disabled") except Exception as e: results[f"{plugin.name}"] = False # 初始化异常,禁用插件 plugin.enabled = False logger.error(f"Error initializing plugin {plugin.name}: {e}, plugin has been disabled") return results async def shutdown_all(self): """ 关闭所有插件 """ # 获取所有插件并按依赖顺序反向排序(先关闭依赖者) all_plugins = [] for plugin_type in self.PLUGIN_TYPES: all_plugins.extend(self.get_plugins_by_type(plugin_type)) sorted_plugins = self._sort_plugins_by_dependencies(all_plugins) sorted_plugins.reverse() # 反向关闭 # 并发关闭插件 shutdown_tasks = [] for plugin in sorted_plugins: # 只关闭有 shutdown 方法的插件 if hasattr(plugin, "shutdown"): shutdown_tasks.append(plugin.shutdown()) if shutdown_tasks: try: await asyncio.gather(*shutdown_tasks, return_exceptions=True) logger.info("All plugins shut down") except Exception as e: logger.error(f"Error during plugin shutdown: {e}") def _sort_plugins_by_dependencies(self, plugins: List[BasePlugin]) -> List[BasePlugin]: """ 按依赖关系对插件进行拓扑排序 Args: plugins: 插件列表 Returns: 排序后的插件列表 Note: 存在循环依赖的插件会被自动禁用 """ # 创建插件名称到插件对象的映射 plugin_map = {plugin.name: plugin for plugin in plugins} # 计算每个插件的入度(被依赖的次数) in_degree = {plugin.name: 0 for plugin in plugins} # 构建依赖图 for plugin in plugins: for dep in plugin.metadata.dependencies: if dep in in_degree: in_degree[plugin.name] += 1 # 拓扑排序 queue = [name for name, degree in in_degree.items() if degree == 0] result = [] while queue: current = queue.pop(0) result.append(plugin_map[current]) # 减少依赖当前插件的其他插件的入度 current_plugin = plugin_map[current] for plugin in plugins: if current in plugin.metadata.dependencies: in_degree[plugin.name] -= 1 if in_degree[plugin.name] == 0: queue.append(plugin.name) # 检查是否存在循环依赖 if len(result) != len(plugins): remaining = [p for p in plugins if p not in result] circular_names = [p.name for p in remaining] logger.error(f"Circular dependency detected among plugins: {circular_names}. " f"These plugins will be disabled.") # 禁用存在循环依赖的插件,而不是继续加载 for plugin in remaining: plugin.enabled = False logger.warning(f"Plugin {plugin.name} has been disabled due to circular dependency") # 不再将循环依赖的插件添加到结果中 return result async def health_check_all(self) -> Dict[str, HealthStatus]: """ 检查所有插件的健康状态 Returns: 健康状态字典 {plugin_name: status} """ results = {} # 获取所有插件 all_plugins = [] for plugin_type in self.PLUGIN_TYPES: all_plugins.extend(self.get_plugins_by_type(plugin_type)) # 并发检查健康状态 health_tasks = [] for plugin in all_plugins: health_tasks.append(plugin.health_check()) if health_tasks: health_results = await asyncio.gather(*health_tasks, return_exceptions=True) for plugin, result in zip(all_plugins, health_results): if isinstance(result, Exception): results[plugin.name] = HealthStatus.UNHEALTHY else: results[plugin.name] = result return results def validate_plugin_dependencies(self) -> Dict[str, List[str]]: """ 验证所有插件的依赖关系 Returns: 验证结果字典 {plugin_name: [missing_dependencies]} """ results = {} # 获取所有可用插件名称 available_plugins = {} for plugin_type in self.PLUGIN_TYPES: available_plugins[plugin_type] = [p.name for p in self.get_plugins_by_type(plugin_type)] # 检查每个插件的依赖 for plugin_type in self.PLUGIN_TYPES: for plugin in self.get_plugins_by_type(plugin_type): missing_deps = plugin.validate_dependencies(available_plugins) if missing_deps: results[plugin.name] = missing_deps return results def reload_plugin_config( self, plugin_type: str, plugin_name: str, new_config: Dict[str, Any] ) -> bool: """ 重新加载插件配置 Args: plugin_type: 插件类型 plugin_name: 插件名称 new_config: 新配置 Returns: 是否成功重新加载 """ plugin = self.get_plugin(plugin_type, plugin_name) if not plugin: return False try: plugin.configure(new_config) logger.info(f"Reloaded config for plugin {plugin_name}: {new_config}") return True except Exception as e: logger.error(f"Failed to reload config for plugin {plugin_name}: {e}") return False # 全局插件管理器实例 _plugin_manager: Optional[PluginManager] = None _plugin_manager_lock = threading.Lock() def get_plugin_manager(config: Optional[Dict[str, Any]] = None) -> PluginManager: """ 获取全局插件管理器实例(线程安全) Args: config: 配置字典 Returns: 插件管理器实例 """ global _plugin_manager if _plugin_manager is None: with _plugin_manager_lock: # 双重检查锁定模式 if _plugin_manager is None: _plugin_manager = PluginManager(config) return _plugin_manager def reset_plugin_manager(): """重置插件管理器(用于测试)""" global _plugin_manager with _plugin_manager_lock: _plugin_manager = None