diff --git a/changes.md b/changes.md index 70b9dfbf2..7d4f2ae8f 100644 --- a/changes.md +++ b/changes.md @@ -21,6 +21,8 @@ - `database_api.py`中的`db_query`方法调整了参数顺序以增强参数限制的同时,保证了typing正确;`db_get`方法增加了`single_result`参数,与`db_query`保持一致。 5. 增加了`logging_api`,可以用`get_logger`来获取日志记录器。 6. 增加了插件和组件管理的API。 +7. `BaseCommand`的`execute`方法现在返回一个三元组,包含是否执行成功、可选的回复消息和是否拦截消息。 + - 这意味着你终于可以动态控制是否继续后续消息的处理了。 # 插件系统修改 1. 现在所有的匹配模式不再是关键字了,而是枚举类。**(可能有遗漏)** diff --git a/plugins/hello_world_plugin/plugin.py b/plugins/hello_world_plugin/plugin.py index 55b9df82d..8ede9616a 100644 --- a/plugins/hello_world_plugin/plugin.py +++ b/plugins/hello_world_plugin/plugin.py @@ -20,6 +20,7 @@ class HelloAction(BaseAction): # === 基本信息(必须填写)=== action_name = "hello_greeting" action_description = "向用户发送问候消息" + activation_type = ActionActivationType.ALWAYS # 始终激活 # === 功能描述(必须填写)=== action_parameters = {"greeting_message": "要发送的问候消息"} @@ -44,8 +45,7 @@ class ByeAction(BaseAction): action_description = "向用户发送告别消息" # 使用关键词激活 - focus_activation_type = ActionActivationType.KEYWORD - normal_activation_type = ActionActivationType.KEYWORD + activation_type = ActionActivationType.KEYWORD # 关键词设置 activation_keywords = ["再见", "bye", "88", "拜拜"] @@ -75,11 +75,8 @@ class TimeCommand(BaseCommand): # === 命令设置(必须填写)=== command_pattern = r"^/time$" # 精确匹配 "/time" 命令 - command_help = "查询当前时间" - command_examples = ["/time"] - intercept_message = True # 拦截消息,不让其他组件处理 - async def execute(self) -> Tuple[bool, str]: + async def execute(self) -> Tuple[bool, str, bool]: """执行时间查询""" import datetime @@ -92,7 +89,7 @@ class TimeCommand(BaseCommand): message = f"⏰ 当前时间:{time_str}" await self.send_text(message) - return True, f"显示了当前时间: {time_str}" + return True, f"显示了当前时间: {time_str}", True class PrintMessage(BaseEventHandler): diff --git a/src/chat/message_receive/bot.py b/src/chat/message_receive/bot.py index cade4f145..a4228b89a 100644 --- a/src/chat/message_receive/bot.py +++ b/src/chat/message_receive/bot.py @@ -92,7 +92,6 @@ class ChatBot: command_result = component_registry.find_command_by_text(text) if command_result: command_class, matched_groups, command_info = command_result - intercept_message = command_info.intercept_message plugin_name = command_info.plugin_name command_name = command_info.name if ( @@ -115,7 +114,7 @@ class ChatBot: try: # 执行命令 - success, response = await command_instance.execute() + success, response, intercept_message = await command_instance.execute() # 记录命令执行结果 if success: @@ -128,8 +127,6 @@ class ChatBot: except Exception as e: logger.error(f"执行命令时出错: {command_class.__name__} - {e}") - import traceback - logger.error(traceback.format_exc()) try: @@ -138,7 +135,7 @@ class ChatBot: logger.error(f"发送错误消息失败: {send_error}") # 命令出错时,根据命令的拦截设置决定是否继续处理消息 - return True, str(e), not intercept_message + return True, str(e), False # 出错时继续处理消息 # 没有找到命令,继续处理消息 return False, None, True diff --git a/src/plugin_system/base/base_command.py b/src/plugin_system/base/base_command.py index 7909980cb..60ee99add 100644 --- a/src/plugin_system/base/base_command.py +++ b/src/plugin_system/base/base_command.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Dict, Tuple, Optional, List +from typing import Dict, Tuple, Optional from src.common.logger import get_logger from src.plugin_system.base.component_types import CommandInfo, ComponentType from src.chat.message_receive.message import MessageRecv @@ -17,7 +17,6 @@ class BaseCommand(ABC): - command_pattern: 命令匹配的正则表达式 - command_help: 命令帮助信息 - command_examples: 命令使用示例列表 - - intercept_message: 是否拦截消息处理(默认True拦截,False继续传递) """ command_name: str = "" @@ -27,11 +26,6 @@ class BaseCommand(ABC): # 默认命令设置 command_pattern: str = r"" """命令匹配的正则表达式""" - command_help: str = "" - """命令帮助信息""" - command_examples: List[str] = [] - intercept_message: bool = True - """是否拦截信息,默认拦截,不进行后续处理""" def __init__(self, message: MessageRecv, plugin_config: Optional[dict] = None): """初始化Command组件 @@ -57,11 +51,11 @@ class BaseCommand(ABC): self.matched_groups = groups @abstractmethod - async def execute(self) -> Tuple[bool, Optional[str]]: + async def execute(self) -> Tuple[bool, Optional[str], bool]: """执行Command的抽象方法,子类必须实现 Returns: - Tuple[bool, Optional[str]]: (是否执行成功, 可选的回复消息) + Tuple[bool, Optional[str], bool]: (是否执行成功, 可选的回复消息, 是否拦截消息 不进行 后续处理) """ pass @@ -231,7 +225,4 @@ class BaseCommand(ABC): component_type=ComponentType.COMMAND, description=cls.command_description, command_pattern=cls.command_pattern, - command_help=cls.command_help, - command_examples=cls.command_examples.copy() if cls.command_examples else [], - intercept_message=cls.intercept_message, ) diff --git a/src/plugin_system/base/component_types.py b/src/plugin_system/base/component_types.py index 774daa598..eeb2a5a08 100644 --- a/src/plugin_system/base/component_types.py +++ b/src/plugin_system/base/component_types.py @@ -140,14 +140,9 @@ class CommandInfo(ComponentInfo): """命令组件信息""" command_pattern: str = "" # 命令匹配模式(正则表达式) - command_help: str = "" # 命令帮助信息 - command_examples: List[str] = field(default_factory=list) # 命令使用示例 - intercept_message: bool = True # 是否拦截消息处理(默认拦截) def __post_init__(self): super().__post_init__() - if self.command_examples is None: - self.command_examples = [] self.component_type = ComponentType.COMMAND diff --git a/src/plugin_system/core/events_manager.py b/src/plugin_system/core/events_manager.py index 1f01b4ab4..3c215a7ff 100644 --- a/src/plugin_system/core/events_manager.py +++ b/src/plugin_system/core/events_manager.py @@ -182,17 +182,17 @@ class EventsManager: async def cancel_handler_tasks(self, handler_name: str) -> None: tasks_to_be_cancelled = self._handler_tasks.get(handler_name, []) - remaining_tasks = [task for task in tasks_to_be_cancelled if not task.done()] - for task in remaining_tasks: - task.cancel() - try: - await asyncio.wait_for(asyncio.gather(*remaining_tasks, return_exceptions=True), timeout=5) - logger.info(f"已取消事件处理器 {handler_name} 的所有任务") - except asyncio.TimeoutError: - logger.warning(f"取消事件处理器 {handler_name} 的任务超时,开始强制取消") - except Exception as e: - logger.error(f"取消事件处理器 {handler_name} 的任务时发生异常: {e}") - finally: + if remaining_tasks := [task for task in tasks_to_be_cancelled if not task.done()]: + for task in remaining_tasks: + task.cancel() + try: + await asyncio.wait_for(asyncio.gather(*remaining_tasks, return_exceptions=True), timeout=5) + logger.info(f"已取消事件处理器 {handler_name} 的所有任务") + except asyncio.TimeoutError: + logger.warning(f"取消事件处理器 {handler_name} 的任务超时,开始强制取消") + except Exception as e: + logger.error(f"取消事件处理器 {handler_name} 的任务时发生异常: {e}") + if handler_name in self._handler_tasks: del self._handler_tasks[handler_name] async def unregister_event_subscriber(self, handler_name: str) -> bool: diff --git a/src/plugins/built_in/plugin_management/plugin.py b/src/plugins/built_in/plugin_management/plugin.py index 67e2a5f66..cbdf567ac 100644 --- a/src/plugins/built_in/plugin_management/plugin.py +++ b/src/plugins/built_in/plugin_management/plugin.py @@ -18,9 +18,8 @@ class ManagementCommand(BaseCommand): command_name: str = "management" description: str = "管理命令" command_pattern: str = r"(?P^/pm(\s[a-zA-Z0-9_]+)*\s*$)" - intercept_message: bool = True - async def execute(self) -> Tuple[bool, str]: + async def execute(self) -> Tuple[bool, str, bool]: # sourcery skip: merge-duplicate-blocks if ( not self.message @@ -29,11 +28,11 @@ class ManagementCommand(BaseCommand): or str(self.message.message_info.user_info.user_id) not in self.get_config("plugin.permission", []) # type: ignore ): await self.send_text("你没有权限使用插件管理命令") - return False, "没有权限" + return False, "没有权限", True command_list = self.matched_groups["manage_command"].strip().split(" ") if len(command_list) == 1: await self.show_help("all") - return True, "帮助已发送" + return True, "帮助已发送", True if len(command_list) == 2: match command_list[1]: case "plugin": @@ -44,7 +43,7 @@ class ManagementCommand(BaseCommand): await self.show_help("all") case _: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if len(command_list) == 3: if command_list[1] == "plugin": match command_list[2]: @@ -58,7 +57,7 @@ class ManagementCommand(BaseCommand): await self._rescan_plugin_dirs() case _: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True elif command_list[1] == "component": if command_list[2] == "list": await self._list_all_registered_components() @@ -66,10 +65,10 @@ class ManagementCommand(BaseCommand): await self.show_help("component") else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if len(command_list) == 4: if command_list[1] == "plugin": match command_list[2]: @@ -83,28 +82,28 @@ class ManagementCommand(BaseCommand): await self._add_dir(command_list[3]) case _: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True elif command_list[1] == "component": if command_list[2] != "list": await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if command_list[3] == "enabled": await self._list_enabled_components() elif command_list[3] == "disabled": await self._list_disabled_components() else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if len(command_list) == 5: if command_list[1] != "component": await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if command_list[2] != "list": await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if command_list[3] == "enabled": await self._list_enabled_components(target_type=command_list[4]) elif command_list[3] == "disabled": @@ -113,11 +112,11 @@ class ManagementCommand(BaseCommand): await self._list_registered_components_by_type(command_list[4]) else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if len(command_list) == 6: if command_list[1] != "component": await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True if command_list[2] == "enable": if command_list[3] == "global": await self._globally_enable_component(command_list[4], command_list[5]) @@ -125,7 +124,7 @@ class ManagementCommand(BaseCommand): await self._locally_enable_component(command_list[4], command_list[5]) else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True elif command_list[2] == "disable": if command_list[3] == "global": await self._globally_disable_component(command_list[4], command_list[5]) @@ -133,12 +132,12 @@ class ManagementCommand(BaseCommand): await self._locally_disable_component(command_list[4], command_list[5]) else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True else: await self.send_text("插件管理命令不合法") - return False, "命令不合法" + return False, "命令不合法", True - return True, "命令执行完成" + return True, "命令执行完成", True async def show_help(self, target: str): help_msg = ""