""" 插件基类模块 提供插件的基础功能: - 生命周期钩子(on_load, on_enable, on_disable, on_unload, on_reload) - 定时任务管理 - 依赖声明 - 插件元数据 """ from abc import ABC from enum import Enum from typing import Any, Dict, List, Optional, TYPE_CHECKING from loguru import logger from .decorators import scheduler, add_job_safe, remove_job_safe if TYPE_CHECKING: from utils.plugin_manager import PluginManager class PluginState(Enum): """插件状态""" UNLOADED = "unloaded" # 未加载 LOADED = "loaded" # 已加载(未启用) ENABLED = "enabled" # 已启用 DISABLED = "disabled" # 已禁用 ERROR = "error" # 错误状态 class PluginBase(ABC): """ 插件基类 生命周期: 1. __init__() - 构造函数(同步) 2. on_load() - 加载时调用(异步,可访问其他插件) 3. async_init() - 异步初始化(异步,加载配置、资源等) 4. on_enable() - 启用时调用(异步,注册定时任务) 5. on_disable() - 禁用时调用(异步,清理定时任务) 6. on_unload() - 卸载时调用(异步,释放资源) 7. on_reload() - 重载前调用(异步,保存状态) 使用示例: class MyPlugin(PluginBase): description = "我的插件" author = "作者" version = "1.0.0" dependencies = ["AIChat"] # 依赖的插件 load_priority = 60 # 加载优先级 async def on_load(self, plugin_manager): # 可以访问其他插件 aichat = plugin_manager.plugins.get("AIChat") async def async_init(self): # 加载配置、初始化资源 self.config = load_config() async def on_enable(self, bot): await super().on_enable(bot) # 注册定时任务 # 额外的启用逻辑 async def on_disable(self): await super().on_disable() # 清理定时任务 # 额外的禁用逻辑 async def on_unload(self): # 释放资源、关闭连接 await self.close_connections() async def on_reload(self) -> dict: # 返回需要保存的状态 return {"counter": self.counter} async def restore_state(self, state: dict): # 重载后恢复状态 self.counter = state.get("counter", 0) """ # ==================== 插件元数据 ==================== description: str = "暂无描述" author: str = "未知" version: str = "1.0.0" # 插件依赖(填写依赖的插件类名列表) dependencies: List[str] = [] # 加载优先级(数值越大越先加载,默认50) load_priority: int = 50 # ==================== 实例属性 ==================== def __init__(self): self.enabled = False self.state = PluginState.UNLOADED self._scheduled_jobs: set = set() self._bot = None self._plugin_manager: Optional["PluginManager"] = None self._saved_state: Dict[str, Any] = {} # ==================== 生命周期钩子 ==================== async def on_load(self, plugin_manager: "PluginManager"): """ 插件加载时调用 此时其他依赖的插件已经加载完成,可以安全访问。 Args: plugin_manager: 插件管理器实例 """ self._plugin_manager = plugin_manager self.state = PluginState.LOADED logger.debug(f"[{self.__class__.__name__}] on_load 调用") async def async_init(self): """ 插件异步初始化 用于加载配置、初始化资源等耗时操作。 在 on_load 之后、on_enable 之前调用。 """ pass async def on_enable(self, bot=None): """ 插件启用时调用 注册定时任务、启动后台服务等。 Args: bot: WechatHookClient 实例 """ self._bot = bot self.enabled = True self.state = PluginState.ENABLED # 注册定时任务 for method_name in dir(self): method = getattr(self, method_name) if hasattr(method, '_is_scheduled'): job_id = getattr(method, '_job_id') trigger = getattr(method, '_schedule_trigger') trigger_args = getattr(method, '_schedule_args') add_job_safe(scheduler, job_id, method, bot, trigger, **trigger_args) self._scheduled_jobs.add(job_id) if self._scheduled_jobs: logger.success(f"插件 {self.__class__.__name__} 已加载定时任务: {self._scheduled_jobs}") async def on_disable(self): """ 插件禁用时调用 清理定时任务、停止后台服务等。 """ self.enabled = False self.state = PluginState.DISABLED # 移除定时任务 for job_id in self._scheduled_jobs: remove_job_safe(scheduler, job_id) if self._scheduled_jobs: logger.info(f"已卸载定时任务: {self._scheduled_jobs}") self._scheduled_jobs.clear() async def on_unload(self): """ 插件卸载时调用 释放资源、关闭连接、保存数据等。 在 on_disable 之后调用。 """ self.state = PluginState.UNLOADED self._bot = None self._plugin_manager = None logger.debug(f"[{self.__class__.__name__}] on_unload 调用") async def on_reload(self) -> Dict[str, Any]: """ 插件重载前调用 返回需要在重载后恢复的状态数据。 Returns: 需要保存的状态字典 """ logger.debug(f"[{self.__class__.__name__}] on_reload 调用") return {} async def restore_state(self, state: Dict[str, Any]): """ 重载后恢复状态 Args: state: on_reload 返回的状态字典 """ self._saved_state = state logger.debug(f"[{self.__class__.__name__}] 状态已恢复: {list(state.keys())}") # ==================== 辅助方法 ==================== def get_plugin(self, plugin_name: str) -> Optional["PluginBase"]: """ 获取其他插件实例 Args: plugin_name: 插件类名 Returns: 插件实例,不存在返回 None """ if self._plugin_manager: return self._plugin_manager.plugins.get(plugin_name) return None def get_bot(self): """获取 bot 实例""" return self._bot @property def plugin_name(self) -> str: """获取插件名称""" return self.__class__.__name__ def __repr__(self) -> str: return f"<{self.__class__.__name__} v{self.version} state={self.state.value}>"