diff --git a/AGENTS.md b/AGENTS.md index 8fd709d..9d9d205 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,8 +31,7 @@ CodeGraph 是一个预构建的知识图谱,包含代码库中每个符号、 #### 入口 handler(第一层/顶层) 插件 Event Listener 与 Command Handler 的定义位置,(受限于 AstrBot 框架的限制)位于根目录的 `main.py` 文件中。\ -该层仅作薄包装,不含任何实际逻辑,此处应当将其转发至中层的业务方法。\ -不应在此层添加错误处理与日志输出。 +该层仅作薄包装,不含任何实际逻辑,此处应当将其转发至中层的业务方法。 #### 主业务逻辑(第二层/中层) @@ -65,6 +64,11 @@ CodeGraph 是一个预构建的知识图谱,包含代码库中每个符号、 对于返回值为 None 的函数/方法,不应添加类型注解。\ 对于一次性操作,除非现有设计需要,否则不应返回任何值而**仅仅为了**表明操作已成功完成。 +### 错误处理 + +插件已接替了框架的错误处理,因此代码中不应捕获任何未知异常,建议直接写裸代码,使其被框架捕获即可。\ +当然,我们遵循 EAFP 风格,你仍然可以大量运用 try-except。 + ## 开发提示 - 项目虽已安装 Ruff,但并非必须要在完成任务后跑一遍 Ruff check。除非用户主动要求,一般情况下你可以偷懒不 Check。 diff --git a/_conf_schema.json b/_conf_schema.json index 8f88b87..4ecbc03 100644 --- a/_conf_schema.json +++ b/_conf_schema.json @@ -276,6 +276,7 @@ "UnknownError": { "type": "string", "description": "发生未知错误时的提示信息", + "hint": "支持占位符 {handler_name}(处理命令的函数名)。", "default": "发生未知错误,请重试。" } } diff --git a/core/ban/command.py b/core/ban/command.py index aa8d59c..96d3e11 100644 --- a/core/ban/command.py +++ b/core/ban/command.py @@ -47,25 +47,19 @@ def add( yield ban_system.add(event, "123456789", "测试封禁") ``` """ - try: - if self.add_ban(user_id, reason): - self._config.save_config() - logger.info(f"已封禁用户 {user_id}。") - return event.plain_result( - self._msg_template.get_msg_template( - "BanSystem", "AddNewBan", user_id=user_id - ) - ) - else: - return event.plain_result( - self._msg_template.get_msg_template( - "BanSystem", "DuplicateBan", user_id=user_id - ) + if self.add_ban(user_id, reason): + self._config.save_config() + logger.info(f"已封禁用户 {user_id}。") + return event.plain_result( + self._msg_template.get_msg_template( + "BanSystem", "AddNewBan", user_id=user_id ) - except Exception: - logger.exception("添加封禁用户时发生错误。") + ) + else: return event.plain_result( - self._msg_template.get_msg_template("General", "UnknownError") + self._msg_template.get_msg_template( + "BanSystem", "DuplicateBan", user_id=user_id + ) ) def remove( @@ -88,20 +82,14 @@ def remove( yield ban_system.remove(event, "123456789") ``` """ - try: - self.remove_ban(user_id) - self._config.save_config() - logger.info(f"已解封用户 {user_id}。") - return event.plain_result( - self._msg_template.get_msg_template( - "BanSystem", "RemoveBan", user_id=user_id - ) - ) - except Exception: - logger.exception("移除封禁用户时发生错误。") - return event.plain_result( - self._msg_template.get_msg_template("General", "UnknownError") + self.remove_ban(user_id) + self._config.save_config() + logger.info(f"已解封用户 {user_id}。") + return event.plain_result( + self._msg_template.get_msg_template( + "BanSystem", "RemoveBan", user_id=user_id ) + ) def list( self, @@ -121,32 +109,26 @@ def list( yield ban_system.list(event) ``` """ - try: - banlist = self.list_ban() - if not banlist: - return event.plain_result( - self._msg_template.get_msg_template("BanSystem", "BanlistEmpty") - ) - banlist_lines = [] - for item in banlist: - user_id = item["User"] - reason = item.get("Reason") or "无" - banlist_lines.append( - self._msg_template.get_msg_template( - "BanSystem", - "BanlistFormat", - user_id=user_id, - reason=reason, - ) - ) - banlist_str = "".join(banlist_lines) + banlist = self.list_ban() + if not banlist: return event.plain_result( + self._msg_template.get_msg_template("BanSystem", "BanlistEmpty") + ) + banlist_lines = [] + for item in banlist: + user_id = item["User"] + reason = item.get("Reason") or "无" + banlist_lines.append( self._msg_template.get_msg_template( - "BanSystem", "ListBan", banlist=banlist_str + "BanSystem", + "BanlistFormat", + user_id=user_id, + reason=reason, ) ) - except Exception: - logger.exception("列出封禁用户列表时发生错误。") - return event.plain_result( - self._msg_template.get_msg_template("General", "UnknownError") + banlist_str = "".join(banlist_lines) + return event.plain_result( + self._msg_template.get_msg_template( + "BanSystem", "ListBan", banlist=banlist_str ) + ) diff --git a/main.py b/main.py index 50cfa3b..e8f96df 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,8 @@ from typing import cast +import astrbot.api.message_components as Comp from astrbot.api import AstrBotConfig, logger -from astrbot.api.event import AstrMessageEvent, filter +from astrbot.api.event import AstrMessageEvent, MessageChain, filter from astrbot.api.star import Context, Star, StarTools from .entry import GlobalEntry @@ -18,12 +19,6 @@ def __init__(self, context: Context, config: AstrBotConfig): self.plugin_data_path = StarTools.get_data_dir() """插件数据目录。""" - # 这是一个 TODO,计划中会使用该方法去创建定时任务。 - # 限定 on_platform_loaded 后再创建是为了利用该 Hook 拿到 CQHTTP 平台客户端实例 - # @filter.on_platform_loaded() - # async def scheduled_task(self, event: AstrMessageEvent): - # """定时任务启动器。""" - async def initialize(self): """初始化插件。""" if not self.config["GlobalEnable"]: @@ -31,16 +26,51 @@ async def initialize(self): "插件全局开关已关闭,将不会进行任何操作。如果这不是预期行为,请检查你的插件配置。" ) else: + self.msg_template = MessageTemplate(self.config["MessageTemplate"]) self.global_entry = await GlobalEntry.init( self.plugin_data_path, self.config, - MessageTemplate(self.config["MessageTemplate"]), + self.msg_template, ) logger.info("插件初始化完成。") async def terminate(self): logger.info("插件已终止。") + # 这是一个 TODO,计划中会使用该方法去创建定时任务。 + # 限定 on_platform_loaded 后再创建是为了利用该 Hook 拿到 CQHTTP 平台客户端实例 + # @filter.on_platform_loaded() + # async def scheduled_task(self, event: AstrMessageEvent): + # """定时任务启动器。""" + + @filter.on_plugin_error(priority=1) + async def err_handler( + self, + event: AstrMessageEvent, + plugin_name: str, + handler_name: str, + error: Exception, + traceback_text: str, + ): + """错误处理器。""" + if plugin_name != self.name: + return + event.stop_event() + logger.exception(f"{handler_name} 处理事件时发生错误。", exc_info=error) + chain = MessageChain( + [ + Comp.Plain( + self.msg_template.get_msg_template( + "General", + "UnknownError", + handler_name=handler_name, + error=str(error), + ) + ) + ] + ) + await event.send(chain) + def _event_filter(self, event: AstrMessageEvent) -> bool: """事件过滤器。 diff --git a/module/send_like/main.py b/module/send_like/main.py index e6ac024..7e65bd4 100644 --- a/module/send_like/main.py +++ b/module/send_like/main.py @@ -55,8 +55,3 @@ async def like( return event.plain_result( self._msg_template.get_msg_template("SendLike", "DailyLimit") ) - except Exception: - logger.exception("点赞用户时发生错误。") - return event.plain_result( - self._msg_template.get_msg_template("General", "UnknownError") - )