From 9e42a4690d4440f11839e8ac44a80f5581ca3d87 Mon Sep 17 00:00:00 2001 From: liuwei Date: Wed, 19 Mar 2025 10:20:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8F=92=E4=BB=B6=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin_common/plugin_manager.py | 169 ++++++++++++++++------------ plugins/message_summary/__init__.py | 7 -- plugins/stats_collector/__init__.py | 7 -- plugins/stats_collector/main.py | 14 ++- plugins/stats_dashboard/main.py | 14 ++- 5 files changed, 125 insertions(+), 86 deletions(-) diff --git a/plugin_common/plugin_manager.py b/plugin_common/plugin_manager.py index 353cad0..1875040 100644 --- a/plugin_common/plugin_manager.py +++ b/plugin_common/plugin_manager.py @@ -1,5 +1,6 @@ import importlib import inspect +import logging import os import sys from typing import Dict, List, Any, Optional, Type @@ -13,7 +14,7 @@ from plugin_common.event_system import EventSystem, EventType class PluginManager: """插件管理器,负责插件的加载、初始化、启动、停止和卸载""" - + def __init__(self, plugin_dir: str = "plugins"): """ 初始化插件管理器 @@ -25,15 +26,16 @@ class PluginManager: self.plugins: Dict[str, PluginInterface] = {} # 插件实例字典 self.plugin_modules = {} # 插件模块字典 self.system_context = {} # 系统上下文 - + + self.LOG = logging.getLogger(__name__) # 确保插件目录存在 if not os.path.exists(self.plugin_dir): os.makedirs(self.plugin_dir) - + # 将插件目录添加到Python路径 if self.plugin_dir not in sys.path: sys.path.insert(0, self.plugin_dir) - + def set_system_context(self, context: Dict[str, Any]): """ 设置系统上下文 @@ -42,7 +44,7 @@ class PluginManager: context: 系统上下文 """ self.system_context = context - + def discover_plugins(self) -> List[str]: """ 发现可用插件 @@ -51,7 +53,7 @@ class PluginManager: 插件模块名称列表 """ plugin_modules = [] - + # 遍历插件目录 for item in os.listdir(self.plugin_dir): if os.path.isdir(os.path.join(self.plugin_dir, item)) and not item.startswith("__"): @@ -61,9 +63,9 @@ class PluginManager: elif item.endswith(".py") and not item.startswith("__"): # 单文件插件 plugin_modules.append(item[:-3]) - + self.LOG.info(f"plugin_modules:{plugin_modules}") return plugin_modules - + def load_plugin(self, plugin_name: str) -> Optional[PluginInterface]: """ 加载插件 @@ -78,80 +80,107 @@ class PluginManager: # 如果插件已加载,直接返回 if plugin_name in self.plugins: return self.plugins[plugin_name] - + # 确定插件路径 if os.path.isdir(os.path.join(self.plugin_dir, plugin_name)): plugin_path = os.path.join(self.plugin_dir, plugin_name) - # 优先从main.py加载插件 + # 直接从main.py加载插件,不再尝试从__init__.py加载 main_module_path = f"{plugin_name}.main" if os.path.exists(os.path.join(plugin_path, "main.py")): try: module = importlib.import_module(main_module_path) self.plugin_modules[plugin_name] = module - except ImportError: - # 如果main.py导入失败,尝试从__init__.py加载 - module = importlib.import_module(plugin_name) - self.plugin_modules[plugin_name] = module + except ImportError as e: + self.LOG.error(f"导入插件模块 {main_module_path} 失败: {e}") + return None else: - # 如果没有main.py,从__init__.py加载 - module = importlib.import_module(plugin_name) - self.plugin_modules[plugin_name] = module + self.LOG.error(f"插件 {plugin_name} 缺少 main.py 文件") + return None else: # 单文件插件 plugin_path = self.plugin_dir module = importlib.import_module(plugin_name) self.plugin_modules[plugin_name] = module - + # 查找插件类 plugin_class = None for name, obj in inspect.getmembers(module): - if (inspect.isclass(obj) and - issubclass(obj, PluginInterface) and - obj != PluginInterface - # 修改这里:不排除继承自 MessagePluginInterface 和 ScheduledPluginInterface 的类 - # obj != MessagePluginInterface and - # obj != ScheduledPluginInterface - ): + if (inspect.isclass(obj) and + issubclass(obj, PluginInterface) and + obj != PluginInterface and + obj != MessagePluginInterface and + obj != ScheduledPluginInterface): plugin_class = obj break - + + # 如果插件类为空,尝试查找get_plugin函数 if plugin_class is None: - print(f"插件 {plugin_name} 中未找到有效的插件类") + get_plugin_func = getattr(module, "get_plugin", None) + if callable(get_plugin_func): + plugin = get_plugin_func() + if isinstance(plugin, PluginInterface): + # 设置插件路径 + plugin.set_plugin_path(plugin_path) + + # 加载插件配置 + if not plugin.load_config(): + self.LOG.error(f"插件 {plugin_name} 加载配置失败") + return None + + # 初始化插件 + if not plugin.initialize(self.system_context): + self.LOG.error(f"插件 {plugin_name} 初始化失败") + return None + + # 注册插件 + PluginRegistry().register(plugin) + + # 存储插件实例 + self.plugins[plugin.name] = plugin + + # 发布插件加载事件 + EventSystem().publish(EventType.PLUGIN_LOADED, {"plugin": plugin}) + + return plugin + else: + self.LOG.error(f"插件 {plugin_name} 的 get_plugin() 返回的不是有效的插件实例") + else: + self.LOG.error(f"插件 {plugin_name} 中未找到有效的插件类或 get_plugin 函数") return None - + # 实例化插件 plugin = plugin_class() plugin.status = PluginStatus.LOADED - + # 设置插件路径 plugin.set_plugin_path(plugin_path) - + # 加载插件配置 if not plugin.load_config(): - print(f"插件 {plugin_name} 加载配置失败") + self.LOG.error(f"插件 {plugin_name} 加载配置失败") return None - + # 初始化插件 if not plugin.initialize(self.system_context): - print(f"插件 {plugin_name} 初始化失败") + self.LOG.error(f"插件 {plugin_name} 初始化失败") return None - + # 注册插件 PluginRegistry().register(plugin) - + # 存储插件实例 self.plugins[plugin.name] = plugin - + # 发布插件加载事件 EventSystem().publish(EventType.PLUGIN_LOADED, {"plugin": plugin}) - + return plugin except Exception as e: - print(f"加载插件 {plugin_name} 失败: {e}") + self.LOG.error(f"加载插件 {plugin_name} 失败: {e}") return None - + def load_all_plugins(self) -> Dict[str, PluginInterface]: """ 加载所有插件 @@ -160,12 +189,12 @@ class PluginManager: 插件实例字典 """ plugin_modules = self.discover_plugins() - + for module_name in plugin_modules: self.load_plugin(module_name) - + return self.plugins - + def unload_plugin(self, plugin_name: str) -> bool: """ 卸载插件 @@ -177,33 +206,33 @@ class PluginManager: 卸载是否成功 """ if plugin_name not in self.plugins: - print(f"插件 {plugin_name} 未加载") + self.LOG.info(f"插件 {plugin_name} 未加载") return False - + plugin = self.plugins[plugin_name] - + # 停止插件 if plugin.status == PluginStatus.RUNNING: if not plugin.stop(): - print(f"停止插件 {plugin_name} 失败") + self.LOG.info(f"停止插件 {plugin_name} 失败") return False - + # 清理插件资源 if not plugin.cleanup(): - print(f"清理插件 {plugin_name} 资源失败") + self.LOG.info(f"清理插件 {plugin_name} 资源失败") return False - + # 注销插件 PluginRegistry().unregister(plugin_name) - + # 移除插件实例 del self.plugins[plugin_name] - + # 发布插件卸载事件 EventSystem().publish(EventType.PLUGIN_UNLOADED, {"plugin_name": plugin_name}) - + return True - + def start_plugin(self, plugin_name: str) -> bool: """ 启动插件 @@ -215,22 +244,22 @@ class PluginManager: 启动是否成功 """ if plugin_name not in self.plugins: - print(f"插件 {plugin_name} 未加载") + self.LOG.info(f"插件 {plugin_name} 未加载") return False - + plugin = self.plugins[plugin_name] - + if plugin.status == PluginStatus.RUNNING: - print(f"插件 {plugin_name} 已经在运行") + self.LOG.info(f"插件 {plugin_name} 已经在运行") return True - + if plugin.start(): plugin.status = PluginStatus.RUNNING return True else: plugin.status = PluginStatus.ERROR return False - + def stop_plugin(self, plugin_name: str) -> bool: """ 停止插件 @@ -242,22 +271,22 @@ class PluginManager: 停止是否成功 """ if plugin_name not in self.plugins: - print(f"插件 {plugin_name} 未加载") + self.LOG.info(f"插件 {plugin_name} 未加载") return False - + plugin = self.plugins[plugin_name] - + if plugin.status != PluginStatus.RUNNING: - print(f"插件 {plugin_name} 未在运行") + self.LOG.info(f"插件 {plugin_name} 未在运行") return True - + if plugin.stop(): plugin.status = PluginStatus.STOPPED return True else: plugin.status = PluginStatus.ERROR return False - + def reload_plugin(self, plugin_name: str) -> Optional[PluginInterface]: """ 重新加载插件 @@ -271,16 +300,16 @@ class PluginManager: # 卸载插件 if plugin_name in self.plugins: if not self.unload_plugin(plugin_name): - print(f"卸载插件 {plugin_name} 失败") + self.LOG.info(f"卸载插件 {plugin_name} 失败") return None - + # 重新导入模块 if plugin_name in self.plugin_modules: try: importlib.reload(self.plugin_modules[plugin_name]) except Exception as e: - print(f"重新导入插件模块 {plugin_name} 失败: {e}") + self.LOG.info(f"重新导入插件模块 {plugin_name} 失败: {e}") return None - + # 加载插件 - return self.load_plugin(plugin_name) \ No newline at end of file + return self.load_plugin(plugin_name) diff --git a/plugins/message_summary/__init__.py b/plugins/message_summary/__init__.py index f7f5fc1..e69de29 100644 --- a/plugins/message_summary/__init__.py +++ b/plugins/message_summary/__init__.py @@ -1,7 +0,0 @@ -from plugins.message_summary.main import MessageSummaryPlugin - -def get_plugin(): - """获取插件实例""" - return MessageSummaryPlugin() - -__all__ = ['MessageSummaryPlugin', 'get_plugin'] \ No newline at end of file diff --git a/plugins/stats_collector/__init__.py b/plugins/stats_collector/__init__.py index 5c15c03..e69de29 100644 --- a/plugins/stats_collector/__init__.py +++ b/plugins/stats_collector/__init__.py @@ -1,7 +0,0 @@ -from plugins.stats_collector.main import StatsCollectorPlugin - -def get_plugin(): - """获取插件实例""" - return StatsCollectorPlugin() - -__all__ = ['StatsCollectorPlugin', 'get_plugin'] \ No newline at end of file diff --git a/plugins/stats_collector/main.py b/plugins/stats_collector/main.py index 6278edd..4bc1d3d 100644 --- a/plugins/stats_collector/main.py +++ b/plugins/stats_collector/main.py @@ -3,7 +3,7 @@ import time from typing import Dict, Any, Tuple, Optional, List from datetime import datetime -from plugin_common.plugin_interface import PluginInterface +from plugin_common.plugin_interface import PluginInterface, PluginStatus from event_system.event_manager import EventManager # 使用正确的事件类型导入 from event_system.events.plugin_events import PluginCallStartEvent, PluginCallEndEvent, PluginCallErrorEvent @@ -154,3 +154,15 @@ class StatsCollectorPlugin(PluginInterface): self.event_manager.unregister(PluginCallErrorEvent, self.handle_plugin_error) self.logger.info("统计收集插件已关闭") + + def start(self) -> bool: + """启动插件""" + self.status = PluginStatus.RUNNING + self.LOG.info(f"{self.name} 插件已启动") + return True + + def stop(self) -> bool: + """停止插件""" + self.status = PluginStatus.STOPPED + self.LOG.info(f"{self.name} 插件已停止") + return True diff --git a/plugins/stats_dashboard/main.py b/plugins/stats_dashboard/main.py index 8063835..b8d552b 100644 --- a/plugins/stats_dashboard/main.py +++ b/plugins/stats_dashboard/main.py @@ -2,7 +2,7 @@ import logging import threading from typing import Dict, Any, Tuple, Optional, List -from plugin_common.plugin_interface import PluginInterface +from plugin_common.plugin_interface import PluginInterface, PluginStatus from .dashboard_server import DashboardServer @@ -144,3 +144,15 @@ class StatsDashboardPlugin(PluginInterface): """关闭插件""" if self.server: self.stop_server() + + def start(self) -> bool: + """启动插件""" + self.status = PluginStatus.RUNNING + self.LOG.info(f"{self.name} 插件已启动") + return True + + def stop(self) -> bool: + """停止插件""" + self.status = PluginStatus.STOPPED + self.LOG.info(f"{self.name} 插件已停止") + return True