Skip to content

生命周期

插件在运行过程中会经历不同的阶段:启动、停止、配置变更等。你可以在这些时刻执行自己的逻辑。

所有生命周期钩子都是可选的。不需要就不写。

启动时做准备

插件进程启动后,startup 钩子会被调用。适合做初始化工作:加载配置、打开连接、准备资源。

python
from plugin.sdk.plugin import NekoPluginBase, neko_plugin, lifecycle, Ok
import aiohttp

@neko_plugin
class MyPlugin(NekoPluginBase):

    @lifecycle(id="startup")
    async def on_startup(self):
        # 加载配置
        cfg = await self.config.dump()
        self.api_url = cfg.get("my_settings", {}).get("api_url", "https://default.com")

        # 打开连接
        self.session = aiohttp.ClientSession()

        self.logger.info("插件已启动,API: {}", self.api_url)
        return Ok({"status": "ready"})

停止时清理

插件被停止或 N.E.K.O 关闭时,shutdown 钩子会被调用。适合关闭连接、保存状态。

python
    @lifecycle(id="shutdown")
    async def on_shutdown(self):
        if self.session:
            await self.session.close()
        self.logger.info("插件已停止")
        return Ok({"status": "stopped"})

用户点击重载

插件管理面板中的重载目前会重启插件:先执行 shutdown,再重新启动插件并执行 startup。清理逻辑放在 shutdown,初始化或配置刷新逻辑放在 startup

SDK 装饰器仍然接受 reload 生命周期 ID 用于兼容,但插件管理面板的重载按钮不会派发它。

配置被外部修改

当配置通过 UI 或 API 被修改时触发。适合不重启就应用新设置。

python
    @lifecycle(id="config_change")
    async def on_config_change(self, old_config, new_config, mode):
        self.timeout = new_config.get("my_settings", {}).get("timeout", 30)
        self.logger.info("配置更新模式: {}", mode)
        self.logger.info("配置已更新,新超时: {}s", self.timeout)
        return Ok({"status": "config_updated"})

生命周期事件和重载行为

事件/操作发生时机典型用途
startup插件进程启动初始化、加载配置、打开连接
shutdown插件进程停止关闭连接、保存状态、释放资源
插件管理面板重载用户点击重载先执行 shutdown,再执行 startup
config_change配置被外部修改应用新设置
freeze插件被挂起暂停定时任务
unfreeze插件被恢复恢复定时任务

完整示例

python
from plugin.sdk.plugin import NekoPluginBase, neko_plugin, lifecycle, plugin_entry, Ok
import aiohttp

@neko_plugin
class WeatherPlugin(NekoPluginBase):

    def __init__(self, ctx):
        super().__init__(ctx)
        self.session = None
        self.api_url = ""

    @lifecycle(id="startup")
    async def on_startup(self):
        cfg = await self.config.dump()
        self.api_url = cfg.get("weather", {}).get("api_url", "https://wttr.in")
        self.session = aiohttp.ClientSession()
        self.logger.info("Weather plugin ready, api={}", self.api_url)
        return Ok({"status": "ready"})

    @lifecycle(id="shutdown")
    async def on_shutdown(self):
        if self.session:
            await self.session.close()
        return Ok({"status": "stopped"})

    @lifecycle(id="config_change")
    async def on_config_change(self, old_config, new_config, mode):
        self.api_url = new_config.get("weather", {}).get("api_url", "https://wttr.in")
        self.logger.info("Config updated with mode={}", mode)
        return Ok({"status": "config_updated"})

    @plugin_entry(id="get_weather", name="查天气", description="查询城市天气")
    async def get_weather(self, city: str = "Beijing"):
        async with self.session.get(f"{self.api_url}/{city}?format=j1") as resp:
            data = await resp.json()
            return Ok({"city": city, "temp": data["current_condition"][0]["temp_C"]})

基于 MIT 许可发布。