feat:继续重构插件api
This commit is contained in:
@@ -69,8 +69,8 @@ class ComponentRegistry:
|
||||
self._register_action_component(component_info, component_class)
|
||||
elif component_type == ComponentType.COMMAND:
|
||||
self._register_command_component(component_info, component_class)
|
||||
|
||||
logger.info(f"已注册{component_type.value}组件: {component_name} ({component_class.__name__})")
|
||||
|
||||
logger.debug(f"已注册{component_type.value}组件: {component_name} ({component_class.__name__})")
|
||||
return True
|
||||
|
||||
def _register_action_component(self, action_info: ActionInfo, action_class: Type):
|
||||
@@ -185,7 +185,7 @@ class ComponentRegistry:
|
||||
return False
|
||||
|
||||
self._plugins[plugin_name] = plugin_info
|
||||
logger.info(f"已注册插件: {plugin_name} (组件数量: {len(plugin_info.components)})")
|
||||
logger.debug(f"已注册插件: {plugin_name} (组件数量: {len(plugin_info.components)})")
|
||||
return True
|
||||
|
||||
def get_plugin_info(self, plugin_name: str) -> Optional[PluginInfo]:
|
||||
@@ -215,7 +215,7 @@ class ComponentRegistry:
|
||||
component_info = self._components[component_name]
|
||||
if isinstance(component_info, ActionInfo):
|
||||
self._default_actions[component_name] = component_info.description
|
||||
logger.info(f"已启用组件: {component_name}")
|
||||
logger.debug(f"已启用组件: {component_name}")
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -226,7 +226,7 @@ class ComponentRegistry:
|
||||
# 如果是Action,从默认动作集中移除
|
||||
if component_name in self._default_actions:
|
||||
del self._default_actions[component_name]
|
||||
logger.info(f"已禁用组件: {component_name}")
|
||||
logger.debug(f"已禁用组件: {component_name}")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
from typing import Dict, List, Optional, Any
|
||||
from typing import Dict, List, Optional, Any, TYPE_CHECKING
|
||||
import os
|
||||
import importlib
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.plugin_system.base.base_plugin import BasePlugin
|
||||
|
||||
from src.common.logger_manager import get_logger
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
from src.plugin_system.base.component_types import PluginInfo, ComponentType
|
||||
from src.plugin_system.base.component_types import ComponentType, PluginInfo
|
||||
|
||||
logger = get_logger("plugin_manager")
|
||||
|
||||
@@ -18,16 +22,17 @@ class PluginManager:
|
||||
|
||||
def __init__(self):
|
||||
self.plugin_directories: List[str] = []
|
||||
self.loaded_plugins: Dict[str, Any] = {}
|
||||
self.loaded_plugins: Dict[str, 'BasePlugin'] = {}
|
||||
self.failed_plugins: Dict[str, str] = {}
|
||||
|
||||
self.plugin_paths: Dict[str, str] = {} # 记录插件名到目录路径的映射
|
||||
|
||||
logger.info("插件管理器初始化完成")
|
||||
|
||||
def add_plugin_directory(self, directory: str):
|
||||
"""添加插件目录"""
|
||||
if os.path.exists(directory):
|
||||
self.plugin_directories.append(directory)
|
||||
logger.info(f"已添加插件目录: {directory}")
|
||||
logger.debug(f"已添加插件目录: {directory}")
|
||||
else:
|
||||
logger.warning(f"插件目录不存在: {directory}")
|
||||
|
||||
@@ -37,8 +42,8 @@ class PluginManager:
|
||||
Returns:
|
||||
tuple[int, int]: (插件数量, 组件数量)
|
||||
"""
|
||||
logger.info("开始加载所有插件...")
|
||||
|
||||
logger.debug("开始加载所有插件...")
|
||||
|
||||
# 第一阶段:加载所有插件模块(注册插件类)
|
||||
total_loaded_modules = 0
|
||||
total_failed_modules = 0
|
||||
@@ -47,9 +52,9 @@ class PluginManager:
|
||||
loaded, failed = self._load_plugin_modules_from_directory(directory)
|
||||
total_loaded_modules += loaded
|
||||
total_failed_modules += failed
|
||||
|
||||
logger.info(f"插件模块加载完成 - 成功: {total_loaded_modules}, 失败: {total_failed_modules}")
|
||||
|
||||
|
||||
logger.debug(f"插件模块加载完成 - 成功: {total_loaded_modules}, 失败: {total_failed_modules}")
|
||||
|
||||
# 第二阶段:实例化所有已注册的插件类
|
||||
from src.plugin_system.base.base_plugin import get_registered_plugin_classes, instantiate_and_register_plugin
|
||||
|
||||
@@ -58,25 +63,110 @@ class PluginManager:
|
||||
total_failed_registration = 0
|
||||
|
||||
for plugin_name, plugin_class in plugin_classes.items():
|
||||
# 尝试找到插件对应的目录
|
||||
plugin_dir = self._find_plugin_directory(plugin_class)
|
||||
|
||||
# 使用记录的插件目录路径
|
||||
plugin_dir = self.plugin_paths.get(plugin_name)
|
||||
|
||||
# 如果没有记录,则尝试查找(fallback)
|
||||
if not plugin_dir:
|
||||
plugin_dir = self._find_plugin_directory(plugin_class)
|
||||
if plugin_dir:
|
||||
self.plugin_paths[plugin_name] = plugin_dir
|
||||
|
||||
if instantiate_and_register_plugin(plugin_class, plugin_dir):
|
||||
total_registered += 1
|
||||
self.loaded_plugins[plugin_name] = plugin_class
|
||||
|
||||
# 📊 显示插件详细信息
|
||||
plugin_info = component_registry.get_plugin_info(plugin_name)
|
||||
if plugin_info:
|
||||
component_count = len(plugin_info.components)
|
||||
component_types = {}
|
||||
for comp in plugin_info.components:
|
||||
comp_type = comp.component_type.name
|
||||
component_types[comp_type] = component_types.get(comp_type, 0) + 1
|
||||
|
||||
components_str = ", ".join([f"{count}个{ctype}" for ctype, count in component_types.items()])
|
||||
logger.info(f"✅ 插件加载成功: {plugin_name} v{plugin_info.version} ({components_str}) - {plugin_info.description}")
|
||||
else:
|
||||
logger.info(f"✅ 插件加载成功: {plugin_name}")
|
||||
else:
|
||||
total_failed_registration += 1
|
||||
self.failed_plugins[plugin_name] = "插件注册失败"
|
||||
|
||||
logger.info(f"插件注册完成 - 成功: {total_registered}, 失败: {total_failed_registration}")
|
||||
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name}")
|
||||
|
||||
# 获取组件统计信息
|
||||
stats = component_registry.get_registry_stats()
|
||||
logger.info(f"组件注册统计: {stats}")
|
||||
|
||||
|
||||
# 📋 显示插件加载总览
|
||||
if total_registered > 0:
|
||||
action_count = stats.get('action_components', 0)
|
||||
command_count = stats.get('command_components', 0)
|
||||
total_components = stats.get('total_components', 0)
|
||||
|
||||
logger.info("🎉 插件系统加载完成!")
|
||||
logger.info(f"📊 总览: {total_registered}个插件, {total_components}个组件 (Action: {action_count}, Command: {command_count})")
|
||||
|
||||
# 显示详细的插件列表
|
||||
logger.info("📋 已加载插件详情:")
|
||||
for plugin_name, plugin_class in self.loaded_plugins.items():
|
||||
plugin_info = component_registry.get_plugin_info(plugin_name)
|
||||
if plugin_info:
|
||||
# 插件基本信息
|
||||
version_info = f"v{plugin_info.version}" if plugin_info.version else ""
|
||||
author_info = f"by {plugin_info.author}" if plugin_info.author else ""
|
||||
info_parts = [part for part in [version_info, author_info] if part]
|
||||
extra_info = f" ({', '.join(info_parts)})" if info_parts else ""
|
||||
|
||||
logger.info(f" 📦 {plugin_name}{extra_info}")
|
||||
|
||||
# 组件列表
|
||||
if plugin_info.components:
|
||||
action_components = [c for c in plugin_info.components if c.component_type.name == 'ACTION']
|
||||
command_components = [c for c in plugin_info.components if c.component_type.name == 'COMMAND']
|
||||
|
||||
if action_components:
|
||||
action_names = [c.name for c in action_components]
|
||||
logger.info(f" 🎯 Action组件: {', '.join(action_names)}")
|
||||
|
||||
if command_components:
|
||||
command_names = [c.name for c in command_components]
|
||||
logger.info(f" ⚡ Command组件: {', '.join(command_names)}")
|
||||
|
||||
# 依赖信息
|
||||
if plugin_info.dependencies:
|
||||
logger.info(f" 🔗 依赖: {', '.join(plugin_info.dependencies)}")
|
||||
|
||||
# 配置文件信息
|
||||
if plugin_info.config_file:
|
||||
config_status = "✅" if self.plugin_paths.get(plugin_name) else "❌"
|
||||
logger.info(f" ⚙️ 配置: {plugin_info.config_file} {config_status}")
|
||||
|
||||
# 显示目录统计
|
||||
logger.info("📂 加载目录统计:")
|
||||
for directory in self.plugin_directories:
|
||||
if os.path.exists(directory):
|
||||
plugins_in_dir = []
|
||||
for plugin_name in self.loaded_plugins.keys():
|
||||
plugin_path = self.plugin_paths.get(plugin_name, "")
|
||||
if plugin_path.startswith(directory):
|
||||
plugins_in_dir.append(plugin_name)
|
||||
|
||||
if plugins_in_dir:
|
||||
logger.info(f" 📁 {directory}: {len(plugins_in_dir)}个插件 ({', '.join(plugins_in_dir)})")
|
||||
else:
|
||||
logger.info(f" 📁 {directory}: 0个插件")
|
||||
|
||||
# 失败信息
|
||||
if total_failed_registration > 0:
|
||||
logger.info(f"⚠️ 失败统计: {total_failed_registration}个插件加载失败")
|
||||
for failed_plugin, error in self.failed_plugins.items():
|
||||
logger.info(f" ❌ {failed_plugin}: {error}")
|
||||
else:
|
||||
logger.warning("😕 没有成功加载任何插件")
|
||||
|
||||
# 返回插件数量和组件数量
|
||||
return total_registered, stats.get("total_components", 0)
|
||||
|
||||
return total_registered, total_components
|
||||
|
||||
def _find_plugin_directory(self, plugin_class) -> Optional[str]:
|
||||
"""查找插件类对应的目录路径"""
|
||||
try:
|
||||
@@ -85,8 +175,8 @@ class PluginManager:
|
||||
module = inspect.getmodule(plugin_class)
|
||||
if module and hasattr(module, "__file__") and module.__file__:
|
||||
return os.path.dirname(module.__file__)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.debug(f"通过inspect获取插件目录失败: {e}")
|
||||
return None
|
||||
|
||||
def _load_plugin_modules_from_directory(self, directory: str) -> tuple[int, int]:
|
||||
@@ -97,16 +187,17 @@ class PluginManager:
|
||||
if not os.path.exists(directory):
|
||||
logger.warning(f"插件目录不存在: {directory}")
|
||||
return loaded_count, failed_count
|
||||
|
||||
logger.info(f"正在扫描插件目录: {directory}")
|
||||
|
||||
|
||||
logger.debug(f"正在扫描插件目录: {directory}")
|
||||
|
||||
# 遍历目录中的所有Python文件和包
|
||||
for item in os.listdir(directory):
|
||||
item_path = os.path.join(directory, item)
|
||||
|
||||
if os.path.isfile(item_path) and item.endswith(".py") and item != "__init__.py":
|
||||
# 单文件插件
|
||||
if self._load_plugin_module_file(item_path):
|
||||
plugin_name = Path(item_path).stem
|
||||
if self._load_plugin_module_file(item_path, plugin_name, directory):
|
||||
loaded_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
@@ -115,17 +206,22 @@ class PluginManager:
|
||||
# 插件包
|
||||
plugin_file = os.path.join(item_path, "plugin.py")
|
||||
if os.path.exists(plugin_file):
|
||||
if self._load_plugin_module_file(plugin_file):
|
||||
plugin_name = item # 使用目录名作为插件名
|
||||
if self._load_plugin_module_file(plugin_file, plugin_name, item_path):
|
||||
loaded_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
|
||||
return loaded_count, failed_count
|
||||
|
||||
def _load_plugin_module_file(self, plugin_file: str) -> bool:
|
||||
"""加载单个插件模块文件"""
|
||||
plugin_name = None
|
||||
|
||||
|
||||
def _load_plugin_module_file(self, plugin_file: str, plugin_name: str, plugin_dir: str) -> bool:
|
||||
"""加载单个插件模块文件
|
||||
|
||||
Args:
|
||||
plugin_file: 插件文件路径
|
||||
plugin_name: 插件名称
|
||||
plugin_dir: 插件目录路径
|
||||
"""
|
||||
# 生成模块名
|
||||
plugin_path = Path(plugin_file)
|
||||
if plugin_path.parent.name != "plugins":
|
||||
@@ -144,18 +240,17 @@ class PluginManager:
|
||||
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
# 模块加载成功,插件类会自动通过装饰器注册
|
||||
plugin_name = plugin_path.parent.name if plugin_path.parent.name != "plugins" else plugin_path.stem
|
||||
|
||||
|
||||
# 记录插件名和目录路径的映射
|
||||
self.plugin_paths[plugin_name] = plugin_dir
|
||||
|
||||
logger.debug(f"插件模块加载成功: {plugin_file}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"加载插件模块 {plugin_file} 失败: {e}"
|
||||
logger.error(error_msg)
|
||||
if plugin_name:
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
return False
|
||||
|
||||
def get_loaded_plugins(self) -> List[PluginInfo]:
|
||||
@@ -174,7 +269,7 @@ class PluginManager:
|
||||
# 启用插件的所有组件
|
||||
for component in plugin_info.components:
|
||||
component_registry.enable_component(component.name)
|
||||
logger.info(f"已启用插件: {plugin_name}")
|
||||
logger.debug(f"已启用插件: {plugin_name}")
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -186,7 +281,7 @@ class PluginManager:
|
||||
# 禁用插件的所有组件
|
||||
for component in plugin_info.components:
|
||||
component_registry.disable_component(component.name)
|
||||
logger.info(f"已禁用插件: {plugin_name}")
|
||||
logger.debug(f"已禁用插件: {plugin_name}")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user