diff --git a/plugin_common/plugin_manager.py b/plugin_common/plugin_manager.py index e2efe16..f907dfd 100644 --- a/plugin_common/plugin_manager.py +++ b/plugin_common/plugin_manager.py @@ -48,9 +48,9 @@ class PluginManager: plugin_dir: 插件目录 """ self.plugin_dir = plugin_dir - self.plugins: Dict[str, PluginInterface] = {} # 插件实例字典 - self.plugin_modules = {} # 插件模块字典 - self.module_to_plugin = {} # 模块名到插件名的映射 + self.plugins: Dict[str, PluginInterface] = {} # 插件实例字典,键为display_name + self.plugin_modules = {} # 插件模块字典,键为module_name + self.module_to_display = {} # 模块名到显示名的映射 self.system_context = {} # 系统上下文 self.LOG = logging.getLogger(__name__) @@ -76,125 +76,151 @@ class PluginManager: 发现可用插件 Returns: - 插件模块名称列表 + 插件模块名称列表(module_name) """ - plugin_modules = [] + module_names = [] # 遍历插件目录 for item in os.listdir(self.plugin_dir): if os.path.isdir(os.path.join(self.plugin_dir, item)) and not item.startswith("__"): # 检查是否有main.py文件 if os.path.exists(os.path.join(self.plugin_dir, item, "main.py")): - plugin_modules.append(item) + module_names.append(item) elif item.endswith(".py") and not item.startswith("__"): # 单文件插件 - plugin_modules.append(item[:-3]) - self.LOG.info(f"PluginManager:发现插件模块: {plugin_modules}") - return plugin_modules + module_names.append(item[:-3]) + self.LOG.info(f"PluginManager:发现插件模块: {module_names}") + return module_names def load_all_plugins(self) -> Dict[str, PluginInterface]: """ 加载所有插件 Returns: - 插件实例字典 + 插件实例字典,键为display_name """ - plugin_modules = self.discover_plugins() - loaded_plugins = [] - failed_plugins = [] + module_names = self.discover_plugins() + loaded_modules = [] + failed_modules = [] # 记录开始加载的插件列表 - self.LOG.info(f"PluginManager:开始加载插件列表: {plugin_modules}") + self.LOG.info(f"PluginManager:开始加载插件列表: {module_names}") - for plugin_name in plugin_modules: + for module_name in module_names: try: - plugin = self.load_plugin(plugin_name) + plugin = self.load_plugin(module_name) if plugin: - loaded_plugins.append(plugin_name) + loaded_modules.append(module_name) # 自动启动插件 self.start_plugin(plugin.name) else: - failed_plugins.append(plugin_name) + failed_modules.append(module_name) except Exception as e: - self.LOG.error(f"PluginManager:加载插件 {plugin_name} 时发生错误: {str(e)}", exc_info=True) - failed_plugins.append(plugin_name) + self.LOG.error(f"PluginManager:加载插件模块 {module_name} 时发生错误: {str(e)}", exc_info=True) + failed_modules.append(module_name) # 验证所有已加载插件的模块映射 - for name, plugin in self.plugins.items(): + for display_name, plugin in self.plugins.items(): try: - module_name = plugin.__class__.__module__.split('.')[-2] - if module_name not in self.module_to_plugin: - self.module_to_plugin[module_name] = name - self.LOG.info(f"PluginManager:补充缺失的模块映射 {module_name} -> {name}") - except (IndexError, AttributeError) as e: - self.LOG.warning(f"PluginManager:获取插件 {name} 的模块名时出错: {e}") - # 使用插件目录名作为备选模块名 - folder_name = name.lower().replace(' ', '_') - if folder_name not in self.module_to_plugin: - self.module_to_plugin[folder_name] = name - self.LOG.info(f"PluginManager:使用目录名作为模块映射 {folder_name} -> {name}") + # 尝试从类模块路径获取模块名 + module_name = self._get_module_name_from_plugin(plugin) + if module_name and module_name not in self.module_to_display: + self.module_to_display[module_name] = display_name + self.LOG.info(f"PluginManager:补充缺失的模块映射 {module_name} -> {display_name}") + except Exception as e: + self.LOG.warning(f"PluginManager:获取插件 {display_name} 的模块名时出错: {e}") + # 使用插件显示名称作为备选模块名 + folder_name = display_name.lower().replace(' ', '_') + if folder_name not in self.module_to_display: + self.module_to_display[folder_name] = display_name + self.LOG.info(f"PluginManager:使用目录名作为模块映射 {folder_name} -> {display_name}") # 检查是否有重复或无效的映射 invalid_mappings = [] - for module_name, plugin_name in self.module_to_plugin.items(): - if plugin_name not in self.plugins: + for module_name, display_name in self.module_to_display.items(): + if display_name not in self.plugins: invalid_mappings.append(module_name) - self.LOG.warning(f"PluginManager:发现无效的模块映射 {module_name} -> {plugin_name}") + self.LOG.warning(f"PluginManager:发现无效的模块映射 {module_name} -> {display_name}") # 清理无效的映射 for module_name in invalid_mappings: - del self.module_to_plugin[module_name] + del self.module_to_display[module_name] self.LOG.info(f"PluginManager:清理无效的模块映射 {module_name}") # 记录最终状态 - self.LOG.info(f"PluginManager:加载成功的插件: {loaded_plugins}") - if failed_plugins: - self.LOG.warning(f"PluginManager:加载失败的插件: {failed_plugins}") + self.LOG.info(f"PluginManager:加载成功的插件模块: {loaded_modules}") + if failed_modules: + self.LOG.warning(f"PluginManager:加载失败的插件模块: {failed_modules}") self.LOG.info(f"PluginManager:当前已加载的插件实例: {list(self.plugins.keys())}") - self.LOG.info(f"PluginManager:最终的模块映射关系: {self.module_to_plugin}") + self.LOG.info(f"PluginManager:最终的模块映射关系: {self.module_to_display}") return self.plugins - def load_plugin(self, plugin_name: str) -> Optional[PluginInterface]: + def _get_module_name_from_plugin(self, plugin: PluginInterface) -> Optional[str]: + """ + 从插件实例获取模块名 + + Args: + plugin: 插件实例 + + Returns: + 模块名,获取失败返回None + """ + try: + # 获取完整模块路径 + full_module = plugin.__class__.__module__ + module_parts = full_module.split('.') + + # 处理不同的模块路径情况 + if len(module_parts) >= 2 and module_parts[0] == 'plugins': + # 对于目录插件,模块名在第二个位置 + return module_parts[1] + elif len(module_parts) >= 2: + # 其他情况,取倒数第二个 + return module_parts[-2] + else: + # 单文件插件,直接返回 + return full_module + except (IndexError, AttributeError) as e: + self.LOG.warning(f"获取插件 {plugin.name} 的模块名时出错: {e}") + return None + + def load_plugin(self, module_name: str) -> Optional[PluginInterface]: """ 加载插件 Args: - plugin_name: 插件名称(模块名) + module_name: 插件模块名 Returns: 插件实例,加载失败返回None """ try: # 检查是否已有同名模块的插件加载 - for name, plugin in self.plugins.items(): + for display_name, plugin in self.plugins.items(): try: - module_name = plugin.__class__.__module__.split('.')[-2] - if module_name == plugin_name: - self.LOG.info(f"PluginManager:插件模块 {plugin_name} 已加载为 {name}") - # 确保模块名到插件名的映射存在 - if module_name not in self.module_to_plugin: - self.module_to_plugin[module_name] = name - self.LOG.info(f"PluginManager:添加缺失的模块映射 {module_name} -> {name}") + plugin_module_name = self._get_module_name_from_plugin(plugin) + if plugin_module_name == module_name: + self.LOG.info(f"PluginManager:插件模块 {module_name} 已加载为 {display_name}") + # 确保模块名到显示名的映射存在 + if module_name not in self.module_to_display: + self.module_to_display[module_name] = display_name + self.LOG.info(f"PluginManager:添加缺失的模块映射 {module_name} -> {display_name}") return plugin - except (IndexError, AttributeError) as e: - self.LOG.warning(f"获取插件 {name} 的模块名时出错: {e}") + except Exception as e: + self.LOG.warning(f"获取插件 {display_name} 的模块名时出错: {e}") continue - # 如果插件已加载,直接返回 - if plugin_name in self.plugins: - return self.plugins[plugin_name] - # 确定插件路径和模块路径 - plugin_path = os.path.join(self.plugin_dir, plugin_name) + plugin_path = os.path.join(self.plugin_dir, module_name) # 加载模块 if os.path.isdir(plugin_path) and os.path.exists(os.path.join(plugin_path, "main.py")): # 目录插件,从main.py加载 - module_path = f"plugins.{plugin_name}.main" + module_path = f"plugins.{module_name}.main" try: module = importlib.import_module(module_path) - self.plugin_modules[plugin_name] = module + self.plugin_modules[module_name] = module except ImportError as e: self.LOG.error(f"PluginManager:导入插件模块 {module_path} 失败: {e}") return None @@ -202,10 +228,10 @@ class PluginManager: # 单文件插件 plugin_path = self.plugin_dir try: - module = importlib.import_module(plugin_name) - self.plugin_modules[plugin_name] = module + module = importlib.import_module(module_name) + self.plugin_modules[module_name] = module except ImportError as e: - self.LOG.error(f"PluginManager:导入单文件插件 {plugin_name} 失败: {e}") + self.LOG.error(f"PluginManager:导入单文件插件 {module_name} 失败: {e}") return None # 查找插件类 @@ -230,32 +256,35 @@ class PluginManager: # 加载插件配置 if not plugin.load_config(): - self.LOG.error(f"PluginManager:插件 {plugin_name} 加载配置失败") + self.LOG.error(f"PluginManager:插件模块 {module_name} 加载配置失败") return None # 初始化插件 if not plugin.initialize(self.system_context): - self.LOG.error(f"PluginManager:插件 {plugin_name} 初始化失败") + self.LOG.error(f"PluginManager:插件模块 {module_name} 初始化失败") return None # 注册插件 PluginRegistry().register(plugin) - # 存储插件实例 - self.plugins[plugin.name] = plugin + # 获取显示名称 + display_name = plugin.name - # 添加模块名到插件名的映射 - self.module_to_plugin[plugin_name] = plugin.name - self.LOG.info(f"PluginManager:添加模块映射 {plugin_name} -> {plugin.name}") + # 存储插件实例 + self.plugins[display_name] = plugin + + # 添加模块名到显示名的映射 + self.module_to_display[module_name] = display_name + self.LOG.info(f"PluginManager:添加模块映射 {module_name} -> {display_name}") # 发布插件加载事件 EventSystem().publish(EventType.PLUGIN_LOADED, {"plugin": plugin}) return plugin else: - self.LOG.error(f"PluginManager:插件 {plugin_name} 的 get_plugin() 返回的不是有效的插件实例") + self.LOG.error(f"PluginManager:插件模块 {module_name} 的 get_plugin() 返回的不是有效的插件实例") else: - self.LOG.error(f"PluginManager:插件 {plugin_name} 中未找到有效的插件类或 get_plugin 函数") + self.LOG.error(f"PluginManager:插件模块 {module_name} 中未找到有效的插件类或 get_plugin 函数") return None # 实例化插件 @@ -267,30 +296,26 @@ class PluginManager: # 加载插件配置 if not plugin.load_config(): - self.LOG.error(f"PluginManager:插件 {plugin_name} 加载配置失败") + self.LOG.error(f"PluginManager:插件模块 {module_name} 加载配置失败") return None # 初始化插件 if not plugin.initialize(self.system_context): - self.LOG.error(f"PluginManager:插件 {plugin_name} 初始化失败") + self.LOG.error(f"PluginManager:插件模块 {module_name} 初始化失败") return None # 注册插件 PluginRegistry().register(plugin) + # 获取显示名称 + display_name = plugin.name + # 存储插件实例 - self.plugins[plugin.name] = plugin + self.plugins[display_name] = plugin - # 添加模块名到插件名的映射 - try: - module_name = plugin.__class__.__module__.split('.')[-2] - self.module_to_plugin[module_name] = plugin.name - self.LOG.info(f"PluginManager:添加模块映射 {module_name} -> {plugin.name}") - except (IndexError, AttributeError) as e: - self.LOG.warning(f"无法为插件 {plugin.name} 获取有效的模块名: {e}") - # 使用传入的插件名作为备选 - self.module_to_plugin[plugin_name] = plugin.name - self.LOG.info(f"PluginManager:使用备选模块映射 {plugin_name} -> {plugin.name}") + # 添加模块名到显示名的映射 + self.module_to_display[module_name] = display_name + self.LOG.info(f"PluginManager:添加模块映射 {module_name} -> {display_name}") # 发布插件加载事件 EventSystem().publish(EventType.PLUGIN_LOADED, {"plugin": plugin}) @@ -298,24 +323,24 @@ class PluginManager: return plugin except Exception as e: - self.LOG.error(f"PluginManager:加载插件 {plugin_name} 失败: {e}", exc_info=True) + self.LOG.error(f"PluginManager:加载插件模块 {module_name} 失败: {e}", exc_info=True) return None - def unload_plugin(self, plugin_name: str) -> bool: + def unload_plugin(self, name: str) -> bool: """ 卸载插件 Args: - plugin_name: 插件名称(可以是模块名或显示名称) + name: 插件名称(可以是模块名或显示名称) Returns: 卸载是否成功 """ # 查找插件 - display_name, plugin = self.find_plugin_by_name(plugin_name) + display_name, plugin = self.find_plugin_by_name(name) if not plugin: - self.LOG.info(f"PluginManager:插件 {plugin_name} 未加载") + self.LOG.info(f"PluginManager:插件 {name} 未加载") return False # 停止插件 @@ -337,13 +362,10 @@ class PluginManager: PluginRegistry().unregister(display_name) # 获取模块名,用于清理映射 - try: - module_name = plugin.__class__.__module__.split('.')[-2] - # 清理模块名到插件名的映射 - if module_name in self.module_to_plugin: - del self.module_to_plugin[module_name] - except (IndexError, AttributeError): - pass + module_name = self._get_module_name_from_plugin(plugin) + if module_name and module_name in self.module_to_display: + del self.module_to_display[module_name] + self.LOG.info(f"PluginManager:清理模块映射 {module_name} -> {display_name}") # 移除插件实例 del self.plugins[display_name] @@ -353,28 +375,28 @@ class PluginManager: return True - def reload_plugin(self, plugin_name: str) -> Optional[PluginInterface]: + def reload_plugin(self, name: str) -> Optional[PluginInterface]: """ 重新加载插件 Args: - plugin_name: 插件名称(可以是模块名或显示名称) + name: 插件名称(可以是模块名或显示名称) Returns: 插件实例,重新加载失败返回None """ # 查找插件 - display_name, plugin = self.find_plugin_by_name(plugin_name) + display_name, plugin = self.find_plugin_by_name(name) if not plugin: - self.LOG.info(f"PluginManager:插件 {plugin_name} 未加载,无法重载") + self.LOG.info(f"PluginManager:插件 {name} 未加载,无法重载") return None # 记录原插件状态和模块名 was_running = plugin.status == PluginStatus.RUNNING - try: - module_name = plugin.__class__.__module__.split('.')[-2] - except (IndexError, AttributeError): + module_name = self._get_module_name_from_plugin(plugin) + + if not module_name: self.LOG.error(f"无法获取插件 {display_name} 的模块名,重载失败") return None @@ -400,21 +422,21 @@ class PluginManager: return plugin - def start_plugin(self, plugin_name: str) -> bool: + def start_plugin(self, name: str) -> bool: """ 启动插件 Args: - plugin_name: 插件名称(可以是模块名或显示名称) + name: 插件名称(可以是模块名或显示名称) Returns: 启动是否成功 """ # 查找插件 - display_name, plugin = self.find_plugin_by_name(plugin_name) + display_name, plugin = self.find_plugin_by_name(name) if not plugin: - self.LOG.info(f"PluginManager:插件 {plugin_name} 未加载") + self.LOG.info(f"PluginManager:插件 {name} 未加载") return False if plugin.status == PluginStatus.RUNNING: @@ -430,21 +452,21 @@ class PluginManager: self.LOG.info(f"PluginManager:插件 {display_name} 状态变更为异常") return False - def stop_plugin(self, plugin_name: str) -> bool: + def stop_plugin(self, name: str) -> bool: """ 停止插件 Args: - plugin_name: 插件名称(可以是模块名或显示名称) + name: 插件名称(可以是模块名或显示名称) Returns: 停止是否成功 """ # 查找插件 - display_name, plugin = self.find_plugin_by_name(plugin_name) + display_name, plugin = self.find_plugin_by_name(name) if not plugin: - self.LOG.info(f"插件 {plugin_name} 未加载") + self.LOG.info(f"插件 {name} 未加载") return False if plugin.status != PluginStatus.RUNNING: @@ -469,15 +491,16 @@ class PluginManager: """ success = True # 创建插件名称的副本,因为在卸载过程中会修改self.plugins字典 - plugin_names = list(self.plugins.keys()) + display_names = list(self.plugins.keys()) - for plugin_name in plugin_names: - if not self.unload_plugin(plugin_name): - self.LOG.error(f"卸载插件 {plugin_name} 失败") + for display_name in display_names: + if not self.unload_plugin(display_name): + self.LOG.error(f"卸载插件 {display_name} 失败") success = False # 清空插件模块字典 self.plugin_modules.clear() + self.module_to_display.clear() # 确保插件字典为空 if self.plugins: @@ -486,58 +509,58 @@ class PluginManager: return success - def find_plugin_by_name(self, plugin_name: str) -> Tuple[Optional[str], Optional[PluginInterface]]: + def find_plugin_by_name(self, name: str) -> Tuple[Optional[str], Optional[PluginInterface]]: """ 根据插件名称或模块名查找插件 Args: - plugin_name: 插件名称或模块名 + name: 插件名称或模块名 Returns: (插件显示名称, 插件实例) 元组,未找到返回 (None, None) """ # 直接通过显示名称查找 - if plugin_name in self.plugins: - return plugin_name, self.plugins[plugin_name] + if name in self.plugins: + return name, self.plugins[name] # 通过模块名查找 - if plugin_name in self.module_to_plugin: - display_name = self.module_to_plugin[plugin_name] + if name in self.module_to_display: + display_name = self.module_to_display[name] return display_name, self.plugins.get(display_name) # 遍历所有插件查找匹配的模块名 - for name, plugin in self.plugins.items(): + for display_name, plugin in self.plugins.items(): try: - module_name = plugin.__class__.__module__.split('.')[-2] - if module_name == plugin_name: + module_name = self._get_module_name_from_plugin(plugin) + if module_name and module_name == name: # 顺便更新映射 - if module_name not in self.module_to_plugin: - self.module_to_plugin[module_name] = name - self.LOG.info(f"PluginManager:添加缺失的模块映射 {module_name} -> {name}") - return name, plugin + if module_name not in self.module_to_display: + self.module_to_display[module_name] = display_name + self.LOG.info(f"PluginManager:添加缺失的模块映射 {module_name} -> {display_name}") + return display_name, plugin # 不区分大小写比较 - if module_name.lower() == plugin_name.lower(): - if module_name not in self.module_to_plugin: - self.module_to_plugin[module_name] = name - return name, plugin + if module_name and module_name.lower() == name.lower(): + if module_name not in self.module_to_display: + self.module_to_display[module_name] = display_name + return display_name, plugin - # 检查插件名是否包含在模块名中(不区分大小写) - if plugin_name.lower() in module_name.lower(): - return name, plugin + # 检查名称是否包含在模块名中(不区分大小写) + if module_name and name.lower() in module_name.lower(): + return display_name, plugin - # 检查模块名是否包含在插件名中(不区分大小写) - if module_name.lower() in plugin_name.lower(): - return name, plugin + # 检查模块名是否包含在名称中(不区分大小写) + if module_name and module_name.lower() in name.lower(): + return display_name, plugin - # 检查插件名是否包含在显示名称中(不区分大小写) - if plugin_name.lower() in name.lower(): - return name, plugin - except (IndexError, AttributeError): + # 检查名称是否包含在显示名称中(不区分大小写) + if name.lower() in display_name.lower(): + return display_name, plugin + except Exception: continue # 记录未找到插件的详细信息,帮助调试 - self.LOG.warning(f"未找到插件: {plugin_name},当前已加载插件: {list(self.plugins.keys())}") - self.LOG.warning(f"模块映射: {self.module_to_plugin}") + self.LOG.warning(f"未找到插件: {name},当前已加载插件: {list(self.plugins.keys())}") + self.LOG.warning(f"模块映射: {self.module_to_display}") - return None, None + return None, None \ No newline at end of file