跳转到内容

运行时钩子

Lingchu Bot 通过统一的 hooks/ 包注册全部 NoneBot 运行时钩子。导入该包会解析平台适配层、暴露共享钩子接口,并触发各个 handler 模块的注册。业务逻辑与 NoneBot 装饰器分离,便于单独测试 handler。

运行时钩子按能力分组,每个分类对应 hooks/handlers/ 下的一个模块。

分类 模块 NoneBot 钩子
生命周期 hooks/handlers/lifecycle.py driver.on_startupdriver.on_shutdown
Bot 连接 hooks/handlers/bot_connection.py driver.on_bot_connectdriver.on_bot_disconnect
消息存储 hooks/handlers/message_store.py event_preprocessorevent_postprocessorrun_preprocessorrun_postprocessor
API 审计 hooks/handlers/api_audit.py Bot.on_calling_apiBot.on_called_api

生命周期钩子在 NoneBot 驱动器启动时初始化 Lingchu 运行时服务,在驱动器停止时关闭服务。

  • on_startup 调用 start.startup.startup(),加载配置、菜单、权限和调度器。
  • on_shutdown 依次调用 shutdown_scheduler_service()shutdown_message_store()

Bot 连接钩子记录生命周期事件并发送待处理的重启反馈。

  • on_bot_connect 记录 bot_connected 并触发 send_pending_restart_feedback(bot)
  • on_bot_disconnect 记录 bot_disconnected

消息存储钩子记录事件接收与匹配器执行结果。它使用 hooks/adapters.normalize_message_event 将适配器事件转换为稳定的 NormalizedMessageEvent,并把生成的 MessageIdentity 存入 state,供下游钩子关联记录。

  • event_preprocessor 归一化事件并 fire-and-forget 调用 services.message_store.handle_event_received
  • run_postprocessorstate 读取 identity 并 fire-and-forget 调用 services.message_store.handle_matcher_result
  • event_postprocessorrun_preprocessor 为预留占位符,当前无操作。

API 审计钩子记录平台 API 调用完成后的摘要。

  • on_called_api 解析平台上下文,并在消息存储与 API 调用记录均启用时 fire-and-forget 调用 services.message_store.handle_api_called
  • on_calling_api 为预留占位符,当前无操作。

hooks/adapters.py 承载运行时钩子所需的全部平台相关逻辑。

导出 用途
resolve_platform_context(bot) Bot 实例映射为 PlatformContext(platform_id, adapter_id, bot_id, protocol_id);未知适配器返回 None
normalize_message_event(bot, event) 返回包含 identity、事件类型、消息类型、文本摘要和原始 payload 的 NormalizedMessageEvent
MessageIdentity / NormalizedMessageEvent services.message_store 消费的稳定 dataclass。

字段提取辅助函数(如 _conversation_id_user_id_message_id_plain_text)也集中在此模块,避免 handler 重复编写适配器专属逻辑。

新增运行时钩子处理器的步骤如下:

  1. 选择匹配目标生命周期的 NoneBot2 原生装饰器。每个 handler 模块在导入时注册自身的装饰器,因此插件入口只需 from . import hooks

    能力 NoneBot2 装饰器 参考模块
    驱动器启动 / 关闭 @driver.on_startup@driver.on_shutdown hooks/handlers/lifecycle.py
    Bot 连接 / 断开 @driver.on_bot_connect@driver.on_bot_disconnect hooks/handlers/bot_connection.py
    事件 / matcher 处理 @event_preprocessor@event_postprocessor@run_preprocessor@run_postprocessor hooks/handlers/message_store.py
    Bot API 调用 @Bot.on_calling_api@Bot.on_called_api hooks/handlers/api_audit.py
  2. 实现 handler:按 NoneBot2 装饰器签名实现。需要适配器无关身份时调用 hooks/adapters.py 中的 resolve_platform_context(bot),需要稳定消息封装时调用 normalize_message_event(bot, event)

    from nonebot import get_driver
    from nonebot.adapters import Bot
    from ..adapters import resolve_platform_context
    driver = get_driver()
    @driver.on_bot_connect
    async def on_bot_connect(bot: Bot) -> None:
    ctx = resolve_platform_context(bot)
    if ctx is None:
    return
    ...
  3. hooks/handlers/ 下创建模块,例如 hooks/handlers/my_feature.py。在该模块中注册 NoneBot2 装饰器,业务调用保留在 services/repositories/ 中。

  4. hooks/handlers/__init__.py 导出模块,确保 from . import hooks 能加载它:

    from . import my_feature as my_feature