模块管理优化

This commit is contained in:
liuwei
2025-03-20 10:47:54 +08:00
parent 05a6ee672c
commit d27d8c1a39
2 changed files with 257 additions and 367 deletions

View File

@@ -3,7 +3,7 @@ import inspect
import logging import logging
import os import os
import sys import sys
from typing import Dict, List, Any, Optional, Type from typing import Dict, List, Any, Optional, Type, Tuple
from plugin_common.plugin_interface import PluginInterface, PluginStatus from plugin_common.plugin_interface import PluginInterface, PluginStatus
from plugin_common.message_plugin_interface import MessagePluginInterface from plugin_common.message_plugin_interface import MessagePluginInterface
@@ -25,6 +25,7 @@ class PluginManager:
self.plugin_dir = plugin_dir self.plugin_dir = plugin_dir
self.plugins: Dict[str, PluginInterface] = {} # 插件实例字典 self.plugins: Dict[str, PluginInterface] = {} # 插件实例字典
self.plugin_modules = {} # 插件模块字典 self.plugin_modules = {} # 插件模块字典
self.module_to_plugin = {} # 模块名到插件名的映射
self.system_context = {} # 系统上下文 self.system_context = {} # 系统上下文
self.LOG = logging.getLogger(__name__) self.LOG = logging.getLogger(__name__)
@@ -94,12 +95,19 @@ class PluginManager:
加载插件 加载插件
Args: Args:
plugin_name: 插件名称 plugin_name: 插件名称(模块名)
Returns: Returns:
插件实例加载失败返回None 插件实例加载失败返回None
""" """
try: try:
# 检查是否已有同名模块的插件加载
for name, plugin in self.plugins.items():
module_name = plugin.__class__.__module__.split('.')[-2]
if module_name == plugin_name:
self.LOG.info(f"PluginManager插件模块 {plugin_name} 已加载为 {name}")
return plugin
# 如果插件已加载,直接返回 # 如果插件已加载,直接返回
if plugin_name in self.plugins: if plugin_name in self.plugins:
return self.plugins[plugin_name] return self.plugins[plugin_name]
@@ -193,9 +201,17 @@ class PluginManager:
# 注册插件 # 注册插件
PluginRegistry().register(plugin) PluginRegistry().register(plugin)
# 在 load_plugin 方法中,修改存储插件实例的部分
# 存储插件实例 # 存储插件实例
self.plugins[plugin.name] = plugin self.plugins[plugin.name] = plugin
# 添加模块名到插件名的映射
try:
module_name = plugin.__class__.__module__.split('.')[-2]
self.module_to_plugin[module_name] = plugin.name
except (IndexError, AttributeError):
self.LOG.warning(f"无法为插件 {plugin.name} 获取有效的模块名")
# 发布插件加载事件 # 发布插件加载事件
EventSystem().publish(EventType.PLUGIN_LOADED, {"plugin": plugin}) EventSystem().publish(EventType.PLUGIN_LOADED, {"plugin": plugin})
@@ -210,40 +226,50 @@ class PluginManager:
卸载插件 卸载插件
Args: Args:
plugin_name: 插件名称 plugin_name: 插件名称(可以是模块名或显示名称)
Returns: Returns:
卸载是否成功 卸载是否成功
""" """
if plugin_name not in self.plugins: # 查找插件
display_name, plugin = self.find_plugin_by_name(plugin_name)
if not plugin:
self.LOG.info(f"PluginManager插件 {plugin_name} 未加载") self.LOG.info(f"PluginManager插件 {plugin_name} 未加载")
return False return False
plugin = self.plugins[plugin_name]
# 停止插件 # 停止插件
if plugin.status == PluginStatus.RUNNING: if plugin.status == PluginStatus.RUNNING:
if not plugin.stop(): if not plugin.stop():
self.LOG.info(f"PluginManager停止插件 {plugin_name} 失败") self.LOG.info(f"PluginManager停止插件 {display_name} 失败")
return False return False
plugin.status = PluginStatus.STOPPED # 确保状态更新 plugin.status = PluginStatus.STOPPED # 确保状态更新
# 清理插件资源 # 清理插件资源
if not plugin.cleanup(): if not plugin.cleanup():
self.LOG.info(f"PluginManager清理插件 {plugin_name} 资源失败") self.LOG.info(f"PluginManager清理插件 {display_name} 资源失败")
return False return False
# 设置状态为未加载 # 设置状态为未加载
plugin.status = PluginStatus.UNLOADED plugin.status = PluginStatus.UNLOADED
# 注销插件 # 注销插件
PluginRegistry().unregister(plugin_name) 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
# 移除插件实例 # 移除插件实例
del self.plugins[plugin_name] del self.plugins[display_name]
# 发布插件卸载事件 # 发布插件卸载事件
EventSystem().publish(EventType.PLUGIN_UNLOADED, {"plugin_name": plugin_name}) EventSystem().publish(EventType.PLUGIN_UNLOADED, {"plugin_name": display_name})
return True return True
@@ -252,31 +278,41 @@ class PluginManager:
重新加载插件 重新加载插件
Args: Args:
plugin_name: 插件名称 plugin_name: 插件名称(可以是模块名或显示名称)
Returns: Returns:
插件实例重新加载失败返回None 插件实例重新加载失败返回None
""" """
# 记录原插件状态 # 查找插件
was_running = False display_name, plugin = self.find_plugin_by_name(plugin_name)
if plugin_name in self.plugins:
was_running = self.plugins[plugin_name].status == PluginStatus.RUNNING if not plugin:
self.LOG.info(f"PluginManager插件 {plugin_name} 未加载,无法重载")
return None
# 卸载插件 # 记录原插件状态和模块名
if not self.unload_plugin(plugin_name): was_running = plugin.status == PluginStatus.RUNNING
self.LOG.info(f"卸载插件 {plugin_name} 失败") try:
return None module_name = plugin.__class__.__module__.split('.')[-2]
except (IndexError, AttributeError):
self.LOG.error(f"无法获取插件 {display_name} 的模块名,重载失败")
return None
# 卸载插件
if not self.unload_plugin(display_name):
self.LOG.info(f"卸载插件 {display_name} 失败,无法重载")
return None
# 重新导入模块 # 重新导入模块
if plugin_name in self.plugin_modules: if module_name in self.plugin_modules:
try: try:
importlib.reload(self.plugin_modules[plugin_name]) importlib.reload(self.plugin_modules[module_name])
except Exception as e: except Exception as e:
self.LOG.info(f"重新导入插件模块 {plugin_name} 失败: {e}") self.LOG.info(f"重新导入插件模块 {module_name} 失败: {e}")
return None return None
# 加载插件 # 加载插件
plugin = self.load_plugin(plugin_name) plugin = self.load_plugin(module_name)
# 如果原来是运行状态,则重新启动 # 如果原来是运行状态,则重新启动
if plugin and was_running: if plugin and was_running:
@@ -289,28 +325,29 @@ class PluginManager:
启动插件 启动插件
Args: Args:
plugin_name: 插件名称 plugin_name: 插件名称(可以是模块名或显示名称)
Returns: Returns:
启动是否成功 启动是否成功
""" """
if plugin_name not in self.plugins: # 查找插件
display_name, plugin = self.find_plugin_by_name(plugin_name)
if not plugin:
self.LOG.info(f"PluginManager插件 {plugin_name} 未加载") self.LOG.info(f"PluginManager插件 {plugin_name} 未加载")
return False return False
plugin = self.plugins[plugin_name]
if plugin.status == PluginStatus.RUNNING: if plugin.status == PluginStatus.RUNNING:
self.LOG.info(f"PluginManager插件 {plugin_name} 已经在运行") self.LOG.info(f"PluginManager插件 {display_name} 已经在运行")
return True return True
if plugin.start(): if plugin.start():
plugin.status = PluginStatus.RUNNING plugin.status = PluginStatus.RUNNING
self.LOG.info(f"PluginManager插件 {plugin_name} 状态变更为在运行") self.LOG.info(f"PluginManager插件 {display_name} 状态变更为在运行")
return True return True
else: else:
plugin.status = PluginStatus.ERROR plugin.status = PluginStatus.ERROR
self.LOG.info(f"PluginManager插件 {plugin_name} 状态变更为异常") self.LOG.info(f"PluginManager插件 {display_name} 状态变更为异常")
return False return False
def stop_plugin(self, plugin_name: str) -> bool: def stop_plugin(self, plugin_name: str) -> bool:
@@ -318,57 +355,31 @@ class PluginManager:
停止插件 停止插件
Args: Args:
plugin_name: 插件名称 plugin_name: 插件名称(可以是模块名或显示名称)
Returns: Returns:
停止是否成功 停止是否成功
""" """
if plugin_name not in self.plugins: # 查找插件
display_name, plugin = self.find_plugin_by_name(plugin_name)
if not plugin:
self.LOG.info(f"插件 {plugin_name} 未加载") self.LOG.info(f"插件 {plugin_name} 未加载")
return False return False
plugin = self.plugins[plugin_name]
if plugin.status != PluginStatus.RUNNING: if plugin.status != PluginStatus.RUNNING:
self.LOG.info(f"插件 {plugin_name} 未在运行") self.LOG.info(f"插件 {display_name} 未在运行")
return True return True
if plugin.stop(): if plugin.stop():
plugin.status = PluginStatus.STOPPED plugin.status = PluginStatus.STOPPED
self.LOG.info(f"插件 {plugin_name} 状态变更为已停止") self.LOG.info(f"插件 {display_name} 状态变更为已停止")
return True return True
else: else:
plugin.status = PluginStatus.ERROR plugin.status = PluginStatus.ERROR
self.LOG.info(f"插件 {plugin_name} 状态变更为异常") self.LOG.info(f"插件 {display_name} 状态变更为异常")
return False return False
def reload_plugin(self, plugin_name: str) -> Optional[PluginInterface]:
"""
重新加载插件
Args:
plugin_name: 插件名称
Returns:
插件实例重新加载失败返回None
"""
# 卸载插件
if plugin_name in self.plugins:
if not self.unload_plugin(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:
self.LOG.info(f"重新导入插件模块 {plugin_name} 失败: {e}")
return None
# 加载插件
return self.load_plugin(plugin_name)
def shutdown_plugins(self) -> bool: def shutdown_plugins(self) -> bool:
""" """
卸载所有插件 卸载所有插件
@@ -394,3 +405,33 @@ class PluginManager:
success = False success = False
return success return success
def find_plugin_by_name(self, plugin_name: str) -> Tuple[Optional[str], Optional[PluginInterface]]:
"""
根据插件名称或模块名查找插件
Args:
plugin_name: 插件名称或模块名
Returns:
(插件显示名称, 插件实例) 元组,未找到返回 (None, None)
"""
# 直接通过显示名称查找
if plugin_name in self.plugins:
return plugin_name, self.plugins[plugin_name]
# 通过模块名查找
if plugin_name in self.module_to_plugin:
display_name = self.module_to_plugin[plugin_name]
return display_name, self.plugins.get(display_name)
# 遍历所有插件查找匹配的模块名
for name, plugin in self.plugins.items():
try:
module_name = plugin.__class__.__module__.split('.')[-2]
if module_name == plugin_name:
return name, plugin
except (IndexError, AttributeError):
continue
return None, None

View File

@@ -1,13 +1,11 @@
import logging import logging
import os import os
import sys
from typing import Dict, Any, List, Optional, Tuple from typing import Dict, Any, List, Optional, Tuple
from plugin_common.message_plugin_interface import MessagePluginInterface from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus from plugin_common.plugin_interface import PluginStatus
from plugin_common.plugin_registry import PluginRegistry from plugin_common.plugin_registry import PluginRegistry
from plugin_common.plugin_manager import PluginManager from plugin_common.plugin_manager import PluginManager
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import GroupBotManager from robot_cmd.robot_command import GroupBotManager
@@ -38,9 +36,28 @@ class PluginManagerPlugin(MessagePluginInterface):
def commands(self) -> List[str]: def commands(self) -> List[str]:
return self._commands return self._commands
def start(self) -> bool:
"""启动插件"""
self.LOG.info(f"[{self.name}] 插件已启动")
self.status = PluginStatus.RUNNING
return True
def stop(self) -> bool:
"""停止插件"""
self.LOG.info(f"[{self.name}] 插件已停止")
self.status = PluginStatus.STOPPED
return True
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.plugin_manager = None self.plugin_manager = None
self.plugin_registry = None
self.wcf = None
self.event_system = None
self.message_util = None
self._commands = []
self.command_format = ""
self.enable = True
def initialize(self, context: Dict[str, Any]) -> bool: def initialize(self, context: Dict[str, Any]) -> bool:
"""初始化插件""" """初始化插件"""
@@ -51,13 +68,13 @@ class PluginManagerPlugin(MessagePluginInterface):
self.wcf = context.get("wcf") self.wcf = context.get("wcf")
self.event_system = context.get("event_system") self.event_system = context.get("event_system")
self.message_util = context.get("message_util") self.message_util = context.get("message_util")
# 保存插件注册表引用,用于管理插件 # 保存插件注册表引用,用于管理插件
self.plugin_registry: PluginRegistry = context.get("plugin_registry") self.plugin_registry: PluginRegistry = context.get("plugin_registry")
if not self.plugin_registry: if not self.plugin_registry:
self.LOG.error("无法获取插件注册表,插件管理功能将无法正常工作") self.LOG.error("无法获取插件注册表,插件管理功能将无法正常工作")
return False return False
# 创建插件管理器实例 # 创建插件管理器实例
self.plugin_manager = PluginManager() self.plugin_manager = PluginManager()
# 设置系统上下文 # 设置系统上下文
@@ -70,17 +87,7 @@ class PluginManagerPlugin(MessagePluginInterface):
self.LOG.info(f"[{self.name}] 插件初始化完成,指令:{self._commands}") self.LOG.info(f"[{self.name}] 插件初始化完成,指令:{self._commands}")
return True return True
def start(self) -> bool: # ... start 和 stop 方法保持不变 ...
"""启动插件"""
self.LOG.info(f"[{self.name}] 插件已启动")
self.status = PluginStatus.RUNNING
return True
def stop(self) -> bool:
"""停止插件"""
self.LOG.info(f"[{self.name}] 插件已停止")
self.status = PluginStatus.STOPPED
return True
def can_process(self, message: Dict[str, Any]) -> bool: def can_process(self, message: Dict[str, Any]) -> bool:
"""检查是否可以处理该消息""" """检查是否可以处理该消息"""
@@ -96,23 +103,22 @@ class PluginManagerPlugin(MessagePluginInterface):
"""处理消息""" """处理消息"""
content = str(message.get("content", "")).strip() content = str(message.get("content", "")).strip()
self.LOG.info(f"插件执行: {self.name}{content}") self.LOG.info(f"插件执行: {self.name}{content}")
sender = message.get("sender") sender = message.get("sender")
roomid = message.get("roomid", "") roomid = message.get("roomid", "")
wcf = message.get("wcf") wcf = message.get("wcf")
gbm = message.get("gbm") gbm = message.get("gbm")
target = roomid if roomid else sender
# 检查命令格式 # 检查命令格式
parts = content.split(" ") parts = content.split(" ")
if len(parts) == 1: if len(parts) == 1:
wcf.send_text(f"❌命令格式错误!\n{self.command_format}", wcf.send_text(f"❌命令格式错误!\n{self.command_format}", target, sender)
(roomid if roomid else sender), sender)
return True, "命令格式错误" return True, "命令格式错误"
# 检查权限 (只允许管理员操作) # 检查权限 (只允许管理员操作)
if not self._is_admin(sender, gbm): if not self._is_admin(sender, gbm):
wcf.send_text(f"❌权限不足,只有管理员可以管理插件", wcf.send_text(f"❌权限不足,只有管理员可以管理插件", target, sender)
(roomid if roomid else sender), sender)
return True, "权限不足" return True, "权限不足"
# 解析子命令 # 解析子命令
@@ -121,42 +127,40 @@ class PluginManagerPlugin(MessagePluginInterface):
try: try:
# 根据子命令执行相应操作 # 根据子命令执行相应操作
if sub_command == "列表": command_handlers = {
return self._list_plugins(wcf, sender, roomid) "列表": self._list_plugins,
elif sub_command == "启用" and plugin_name: "启用": lambda w, s, r: self._operate_plugin(plugin_name, w, s, r, self._enable_plugin),
return self._enable_plugin(plugin_name, wcf, sender, roomid) "禁用": lambda w, s, r: self._operate_plugin(plugin_name, w, s, r, self._disable_plugin),
elif sub_command == "禁用" and plugin_name: "重载": lambda w, s, r: self._operate_plugin(plugin_name, w, s, r, self._reload_plugin),
return self._disable_plugin(plugin_name, wcf, sender, roomid) "卸载": lambda w, s, r: self._operate_plugin(plugin_name, w, s, r, self._unload_plugin),
elif sub_command == "" and plugin_name: "": lambda w, s, r: self._operate_plugin(plugin_name, w, s, r, self._load_plugin),
return self._reload_plugin(plugin_name, wcf, sender, roomid) "信息": lambda w, s, r: self._operate_plugin(plugin_name, w, s, r, self._plugin_info)
elif sub_command == "卸载" and plugin_name: }
return self._unload_plugin(plugin_name, wcf, sender, roomid)
elif sub_command == "加载" and plugin_name: handler = command_handlers.get(sub_command)
return self._load_plugin(plugin_name, wcf, sender, roomid) if handler and (sub_command == "列表" or plugin_name):
elif sub_command == "信息" and plugin_name: return handler(wcf, sender, roomid)
return self._plugin_info(plugin_name, wcf, sender, roomid)
else: else:
wcf.send_text(f"❌未知命令或缺少参数!\n{self.command_format}", wcf.send_text(f"❌未知命令或缺少参数!\n{self.command_format}", target, sender)
(roomid if roomid else sender), sender)
return True, "未知命令" return True, "未知命令"
except Exception as e: except Exception as e:
import traceback import traceback
error_trace = traceback.format_exc() error_trace = traceback.format_exc()
self.LOG.error(f"处理插件管理请求出错: {e}\n{error_trace}") self.LOG.error(f"处理插件管理请求出错: {e}\n{error_trace}")
wcf.send_text(f"❌操作失败: {str(e)}", wcf.send_text(f"❌操作失败: {str(e)}", target, sender)
(roomid if roomid else sender), sender)
return True, f"处理出错: {e}" return True, f"处理出错: {e}"
def _is_admin(self, user_id: str, gbm: GroupBotManager) -> bool: def _is_admin(self, user_id: str, gbm: GroupBotManager) -> bool:
"""检查用户是否为管理员""" """检查用户是否为管理员"""
# 从配置中获取管理员列表
admin_list = gbm.get_admin_list() if gbm else [] admin_list = gbm.get_admin_list() if gbm else []
return user_id in admin_list return user_id in admin_list
def _list_plugins(self, wcf, sender: str, roomid: str) -> Tuple[bool, str]: def _list_plugins(self, wcf, sender: str, roomid: str) -> Tuple[bool, str]:
"""列出所有插件""" """列出所有插件"""
plugins = self.plugin_registry.get_all_plugins().values() plugins = self.plugin_registry.get_all_plugins().values()
target = roomid if roomid else sender
# 构建插件列表消息 # 构建插件列表消息
message = "📋 插件列表:\n" message = "📋 插件列表:\n"
for plugin in plugins: for plugin in plugins:
@@ -164,277 +168,122 @@ class PluginManagerPlugin(MessagePluginInterface):
# 获取插件模块名 # 获取插件模块名
module_name = plugin.__class__.__module__.split('.')[-2] module_name = plugin.__class__.__module__.split('.')[-2]
message += f"{status}-{plugin.name} [模块: {module_name}]\n" message += f"{status}-{plugin.name} [模块: {module_name}]\n"
wcf.send_text(message, (roomid if roomid else sender), sender) wcf.send_text(message, target, sender)
return True, "列出插件成功" return True, "列出插件成功"
def _find_plugin_by_name(self, input_name: str) -> Optional[str]: def _operate_plugin(self, plugin_name: str, wcf, sender: str, roomid: str,
""" operation_func) -> Tuple[bool, str]:
根据用户输入的名称查找匹配的插件 """通用插件操作函数"""
支持模糊匹配和不区分大小写 target = roomid if roomid else sender
Args: # 查找匹配的插件名称
input_name: 用户输入的插件名称 actual_plugin_name = self.plugin_manager.find_plugin_by_name(plugin_name)
Returns: if not actual_plugin_name:
匹配到的插件名称未找到返回None wcf.send_text(f"❌未找到插件 {plugin_name},请检查名称是否正确", target, sender)
""" return True, f"未找到插件 {plugin_name}"
if not input_name:
return None # 不允许操作自身(对于某些操作)
if actual_plugin_name == self.name and operation_func in [self._unload_plugin, self._disable_plugin]:
# 获取所有插件 wcf.send_text(f"⚠️不能对插件管理插件自身执行此操作", target, sender)
all_plugins = self.plugin_registry.get_all_plugins() return True, "不能对插件管理插件自身执行此操作"
# 精确匹配 # 执行具体操作
if input_name in all_plugins: return operation_func(actual_plugin_name, wcf, sender, roomid)
return input_name
# 不区分大小写的精确匹配
for plugin_name in all_plugins:
if plugin_name.lower() == input_name.lower():
return plugin_name
# 模块名匹配例如输入music匹配音乐点播
for plugin_name, plugin in all_plugins.items():
module_name = plugin.__class__.__module__.split('.')[-2] # 获取模块名
if module_name.lower() == input_name.lower():
return plugin_name
# 部分匹配(包含关系)
matched_plugins = []
for plugin_name in all_plugins:
if input_name.lower() in plugin_name.lower() or plugin_name.lower() in input_name.lower():
matched_plugins.append(plugin_name)
# 如果只有一个匹配项,返回它
if len(matched_plugins) == 1:
return matched_plugins[0]
# 如果有多个匹配项返回None需要用户明确指定
elif len(matched_plugins) > 1:
return None
return None
# 修改现有的插件操作方法使用_find_plugin_by_name函数
def _enable_plugin(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]: def _enable_plugin(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]:
"""启用插件""" """启用插件"""
# 查找匹配的插件名称 target = roomid if roomid else sender
actual_plugin_name = self._find_plugin_by_name(plugin_name) plugin = self.plugin_registry.get_plugin(plugin_name)
if not actual_plugin_name:
wcf.send_text(f"❌未找到插件 {plugin_name},请检查名称是否正确",
(roomid if roomid else sender), sender)
return True, f"未找到插件 {plugin_name}"
plugin = self.plugin_registry.get_plugin(actual_plugin_name)
if not plugin: if not plugin:
wcf.send_text(f"❌插件 {actual_plugin_name} 不存在", wcf.send_text(f"❌插件 {plugin_name} 不存在", target, sender)
(roomid if roomid else sender), sender) return True, f"插件 {plugin_name} 不存在"
return True, f"插件 {actual_plugin_name} 不存在"
if plugin.status == PluginStatus.RUNNING: if plugin.status == PluginStatus.RUNNING:
wcf.send_text(f"插件 {actual_plugin_name} 已经启用状态", wcf.send_text(f"⚠️插件 {plugin_name} 已经处于启用状态", target, sender)
(roomid if roomid else sender), sender) return True, f"插件 {plugin_name} 已经处于启用状态"
return True, f"插件 {actual_plugin_name} 已经是启用状态"
# 获取插件的模块名
# 获取插件的模块名,这才是插件管理器需要的名称
module_name = plugin.__class__.__module__.split('.')[-2] module_name = plugin.__class__.__module__.split('.')[-2]
# 使用模块名启用插件 # 启动插件
if self.plugin_manager.start_plugin(module_name): if self.plugin_manager.start_plugin(module_name):
wcf.send_text(f"✅插件 {actual_plugin_name} 启用成功", wcf.send_text(f"✅插件 {plugin_name} 启用成功", target, sender)
(roomid if roomid else sender), sender) return True, f"插件 {plugin_name} 启用成功"
return True, f"插件 {actual_plugin_name} 启用成功"
else: else:
wcf.send_text(f"❌插件 {actual_plugin_name} 启用失败", wcf.send_text(f"❌插件 {plugin_name} 启用失败", target, sender)
(roomid if roomid else sender), sender) return False, f"插件 {plugin_name} 启用失败"
return True, f"插件 {actual_plugin_name} 启用失败"
# 同样修改其他插件操作方法
def _disable_plugin(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]: def _disable_plugin(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]:
"""禁用插件""" """禁用插件"""
# 查找匹配的插件名称 target = roomid if roomid else sender
actual_plugin_name = self._find_plugin_by_name(plugin_name) plugin = self.plugin_registry.get_plugin(plugin_name)
if not actual_plugin_name:
wcf.send_text(f"❌未找到插件 {plugin_name},请检查名称是否正确",
(roomid if roomid else sender), sender)
return True, f"未找到插件 {plugin_name}"
# 不允许禁用自身
if actual_plugin_name == self.name:
wcf.send_text(f"⚠️不能禁用插件管理插件自身",
(roomid if roomid else sender), sender)
return True, "不能禁用插件管理插件自身"
plugin = self.plugin_registry.get_plugin(actual_plugin_name)
if not plugin: if not plugin:
wcf.send_text(f"❌插件 {actual_plugin_name} 不存在", wcf.send_text(f"❌插件 {plugin_name} 不存在", target, sender)
(roomid if roomid else sender), sender) return True, f"插件 {plugin_name} 不存在"
return True, f"插件 {actual_plugin_name} 不存在"
if plugin.status != PluginStatus.RUNNING:
if plugin.status == PluginStatus.STOPPED: wcf.send_text(f"⚠️插件 {plugin_name} 已经处于禁用状态", target, sender)
wcf.send_text(f"⚠️插件 {actual_plugin_name} 已经禁用状态", return True, f"插件 {plugin_name} 已经处于禁用状态"
(roomid if roomid else sender), sender)
return True, f"插件 {actual_plugin_name} 已经是禁用状态" # 获取插件的模块名
# 获取插件的模块名,这才是插件管理器需要的名称
module_name = plugin.__class__.__module__.split('.')[-2] module_name = plugin.__class__.__module__.split('.')[-2]
# 使用插件管理器停止插件 - 使用模块名而不是显示名称 # 停止插件
success = self.plugin_manager.stop_plugin(module_name) if self.plugin_manager.stop_plugin(module_name):
if success: wcf.send_text(f"✅插件 {plugin_name} 禁用成功", target, sender)
wcf.send_text(f"插件 {actual_plugin_name} 禁用成功", return True, f"插件 {plugin_name} 禁用成功"
(roomid if roomid else sender), sender)
return True, f"插件 {actual_plugin_name} 禁用成功"
else: else:
wcf.send_text(f"❌插件 {actual_plugin_name} 禁用失败", wcf.send_text(f"❌插件 {plugin_name} 禁用失败", target, sender)
(roomid if roomid else sender), sender) return False, f"插件 {plugin_name} 禁用失败"
return True, f"插件 {actual_plugin_name} 禁用失败"
def _reload_plugin(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]: def _reload_plugin(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]:
"""新加载插件""" """重载插件"""
# 查找匹配的插件名称 target = roomid if roomid else sender
actual_plugin_name = self._find_plugin_by_name(plugin_name) plugin = self.plugin_registry.get_plugin(plugin_name)
if not actual_plugin_name:
wcf.send_text(f"❌未找到插件 {plugin_name},请检查名称是否正确",
(roomid if roomid else sender), sender)
return True, f"未找到插件 {plugin_name}"
# 不允许重载自身
if actual_plugin_name == self.name:
wcf.send_text(f"⚠️不能重载插件管理插件自身",
(roomid if roomid else sender), sender)
return True, "不能重载插件管理插件自身"
plugin = self.plugin_registry.get_plugin(actual_plugin_name)
if not plugin:
wcf.send_text(f"❌插件 {actual_plugin_name} 不存在",
(roomid if roomid else sender), sender)
return True, f"插件 {actual_plugin_name} 不存在"
# 获取插件的模块名,这才是插件管理器需要的名称
module_name = plugin.__class__.__module__.split('.')[-2]
# 记录插件状态,以便重新加载后恢复
was_running = plugin.status == PluginStatus.RUNNING
try:
# 先确保插件已停止运行
if was_running:
self.LOG.info(f"插件 {actual_plugin_name} 正在运行,先停止它")
self.plugin_manager.stop_plugin(module_name)
# 先卸载插件 - 使用模块名而不是显示名称
self.LOG.info(f"正在卸载插件 {actual_plugin_name}(模块名:{module_name}) 以进行重载")
# 尝试卸载,如果失败则尝试强制从注册表移除
unload_success = self.plugin_manager.unload_plugin(module_name)
if not unload_success:
self.LOG.warning(f"常规卸载失败,尝试强制卸载插件 {actual_plugin_name}")
# 从插件注册表中移除
if actual_plugin_name in self.plugin_registry.get_all_plugins():
self.plugin_registry.remove_plugin(actual_plugin_name)
unload_success = True
if not unload_success:
wcf.send_text(f"❌插件 {actual_plugin_name} 卸载失败,无法重载",
(roomid if roomid else sender), sender)
return False, f"插件 {actual_plugin_name} 卸载失败,无法重载"
# 然后加载插件 - 使用模块名而不是显示名称
self.LOG.info(f"正在加载插件 {module_name}")
plugin = self.plugin_manager.load_plugin(module_name)
if not plugin:
wcf.send_text(f"❌插件 {actual_plugin_name} 加载失败",
(roomid if roomid else sender), sender)
return False, f"插件 {actual_plugin_name} 加载失败"
# 如果之前是启用状态,则重新启用
if was_running:
self.LOG.info(f"正在启用插件 {actual_plugin_name}")
if not self.plugin_manager.start_plugin(module_name): # 使用模块名而不是显示名称
wcf.send_text(f"⚠️插件 {actual_plugin_name} 重载成功,但启用失败",
(roomid if roomid else sender), sender)
return True, f"插件 {actual_plugin_name} 重载成功,但启用失败"
wcf.send_text(f"✅插件 {actual_plugin_name} 重载成功",
(roomid if roomid else sender), sender)
return True, f"插件 {actual_plugin_name} 重载成功"
except Exception as e:
import traceback
error_trace = traceback.format_exc()
self.LOG.error(f"重载插件 {actual_plugin_name} 时出错: {e}\n{error_trace}")
wcf.send_text(f"❌重载插件出错: {str(e)}",
(roomid if roomid else sender), sender)
return False, f"重载插件出错: {e}"
def _unload_plugin(self, plugin_name: str, wcf, sender: str, roomid: str, silent: bool = False) -> Tuple[bool, str]:
"""卸载插件"""
# 查找匹配的插件名称
actual_plugin_name = self._find_plugin_by_name(plugin_name)
if not actual_plugin_name:
if not silent:
wcf.send_text(f"❌未找到插件 {plugin_name},请检查名称是否正确",
(roomid if roomid else sender), sender)
return True, f"未找到插件 {plugin_name}"
# 不允许卸载自身
if actual_plugin_name == self.name:
if not silent:
wcf.send_text(f"⚠️不能卸载插件管理插件自身",
(roomid if roomid else sender), sender)
return True, "不能卸载插件管理插件自身"
plugin = self.plugin_registry.get_plugin(actual_plugin_name)
if not plugin: if not plugin:
if not silent: wcf.send_text(f"❌插件 {plugin_name} 不存在", target, sender)
wcf.send_text(f"插件 {actual_plugin_name} 不存在或已卸载", return True, f"插件 {plugin_name} 不存在"
(roomid if roomid else sender), sender)
return True, f"插件 {actual_plugin_name} 不存在或已卸载" # 记录原插件状态
was_running = plugin.status == PluginStatus.RUNNING
# 获取插件的模块名,这才是插件管理器需要的名称
# 获取插件的模块名
module_name = plugin.__class__.__module__.split('.')[-2] module_name = plugin.__class__.__module__.split('.')[-2]
# 先确保插件已停止运行 # 重载插件
if plugin.status == PluginStatus.RUNNING: reloaded_plugin = self.plugin_manager.reload_plugin(module_name)
self.LOG.info(f"插件 {actual_plugin_name} 正在运行,先停止它")
self.plugin_manager.stop_plugin(module_name) if reloaded_plugin:
wcf.send_text(f"✅插件 {plugin_name} 重载成功", target, sender)
# 使用插件管理器卸载插件 - 使用模块名而不是显示名称 return True, f"插件 {plugin_name} 重载成功"
self.LOG.info(f"正在卸载插件 {actual_plugin_name}(模块名:{module_name})") else:
wcf.send_text(f"❌插件 {plugin_name} 重载失败", target, sender)
# 尝试直接从插件注册表中移除插件 return False, f"插件 {plugin_name} 重载失败"
try:
# 先尝试正常卸载 def _unload_plugin(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]:
success = self.plugin_manager.unload_plugin(module_name) """卸载插件"""
target = roomid if roomid else sender
# 如果失败,尝试强制从注册表移除 plugin = self.plugin_registry.get_plugin(plugin_name)
if not success:
self.LOG.warning(f"常规卸载失败,尝试强制卸载插件 {actual_plugin_name}") if not plugin:
# 从插件注册表中移除 wcf.send_text(f"❌插件 {plugin_name} 不存在", target, sender)
if actual_plugin_name in self.plugin_registry.get_all_plugins(): return True, f"插件 {plugin_name} 不存在"
self.plugin_registry.remove_plugin(actual_plugin_name)
success = True # 获取插件的模块名
module_name = plugin.__class__.__module__.split('.')[-2]
if success:
if not silent: # 卸载插件
wcf.send_text(f"✅插件 {actual_plugin_name} 卸载成功", if self.plugin_manager.unload_plugin(module_name):
(roomid if roomid else sender), sender) wcf.send_text(f"✅插件 {plugin_name} 卸载成功", target, sender)
return True, f"插件 {actual_plugin_name} 卸载成功" return True, f"插件 {plugin_name} 卸载成功"
else: else:
if not silent: wcf.send_text(f"❌插件 {plugin_name} 卸载失败", target, sender)
wcf.send_text(f"插件 {actual_plugin_name} 卸载失败", return False, f"插件 {plugin_name} 卸载失败"
(roomid if roomid else sender), sender)
return False, f"插件 {actual_plugin_name} 卸载失败"
except Exception as e:
self.LOG.error(f"卸载插件 {actual_plugin_name} 时出错: {e}")
if not silent:
wcf.send_text(f"❌卸载插件出错: {str(e)}",
(roomid if roomid else sender), sender)
return False, f"卸载插件出错: {e}"
def _load_plugin(self, plugin_name: str, wcf, sender: str, roomid: str, silent: bool = False) -> Tuple[bool, str]: def _load_plugin(self, plugin_name: str, wcf, sender: str, roomid: str, silent: bool = False) -> Tuple[bool, str]:
"""加载插件""" """加载插件"""
@@ -446,7 +295,7 @@ class PluginManagerPlugin(MessagePluginInterface):
wcf.send_text(f"❌插件目录 {plugin_dir} 不存在", wcf.send_text(f"❌插件目录 {plugin_dir} 不存在",
(roomid if roomid else sender), sender) (roomid if roomid else sender), sender)
return False, f"插件目录 {plugin_dir} 不存在" return False, f"插件目录 {plugin_dir} 不存在"
# 检查插件是否已加载 - 遍历所有插件查找模块名匹配的 # 检查插件是否已加载 - 遍历所有插件查找模块名匹配的
for existing_plugin in self.plugin_registry.get_all_plugins().values(): for existing_plugin in self.plugin_registry.get_all_plugins().values():
existing_module_name = existing_plugin.__class__.__module__.split('.')[-2] existing_module_name = existing_plugin.__class__.__module__.split('.')[-2]
@@ -455,7 +304,7 @@ class PluginManagerPlugin(MessagePluginInterface):
wcf.send_text(f"⚠️插件 {existing_plugin.name} (模块名: {plugin_name}) 已经加载", wcf.send_text(f"⚠️插件 {existing_plugin.name} (模块名: {plugin_name}) 已经加载",
(roomid if roomid else sender), sender) (roomid if roomid else sender), sender)
return True, f"插件 {existing_plugin.name} 已经加载" return True, f"插件 {existing_plugin.name} 已经加载"
try: try:
# 使用插件管理器加载插件 # 使用插件管理器加载插件
plugin = self.plugin_manager.load_plugin(plugin_name) plugin = self.plugin_manager.load_plugin(plugin_name)
@@ -479,22 +328,22 @@ class PluginManagerPlugin(MessagePluginInterface):
def _plugin_info(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]: def _plugin_info(self, plugin_name: str, wcf, sender: str, roomid: str) -> Tuple[bool, str]:
"""查看插件详情""" """查看插件详情"""
# 查找匹配的插件名称 # 查找匹配的插件名称
actual_plugin_name = self._find_plugin_by_name(plugin_name) actual_plugin_name = self.plugin_manager.find_plugin_by_name(plugin_name)
if not actual_plugin_name: if not actual_plugin_name:
wcf.send_text(f"❌未找到插件 {plugin_name},请检查名称是否正确", wcf.send_text(f"❌未找到插件 {plugin_name},请检查名称是否正确",
(roomid if roomid else sender), sender) (roomid if roomid else sender), sender)
return True, f"未找到插件 {plugin_name}" return True, f"未找到插件 {plugin_name}"
plugin = self.plugin_registry.get_plugin(actual_plugin_name) plugin = self.plugin_registry.get_plugin(actual_plugin_name)
if not plugin: if not plugin:
wcf.send_text(f"❌插件 {actual_plugin_name} 不存在", wcf.send_text(f"❌插件 {actual_plugin_name} 不存在",
(roomid if roomid else sender), sender) (roomid if roomid else sender), sender)
return True, f"插件 {actual_plugin_name} 不存在" return True, f"插件 {actual_plugin_name} 不存在"
# 获取插件模块名 # 获取插件模块名
module_name = plugin.__class__.__module__.split('.')[-2] module_name = plugin.__class__.__module__.split('.')[-2]
# 构建插件详情消息 # 构建插件详情消息
status_text = "✅ 已启用" if plugin.status == PluginStatus.RUNNING else "❌ 已禁用" status_text = "✅ 已启用" if plugin.status == PluginStatus.RUNNING else "❌ 已禁用"
message = f""" message = f"""
@@ -506,6 +355,6 @@ class PluginManagerPlugin(MessagePluginInterface):
⚙️ 状态:{status_text} ⚙️ 状态:{status_text}
🔑 命令:{', '.join(plugin.commands) if hasattr(plugin, 'commands') else ''} 🔑 命令:{', '.join(plugin.commands) if hasattr(plugin, 'commands') else ''}
""" """
wcf.send_text(message, (roomid if roomid else sender), sender) wcf.send_text(message, (roomid if roomid else sender), sender)
return True, "查看插件详情成功" return True, "查看插件详情成功"