This commit is contained in:
2025-12-31 17:47:39 +08:00
38 changed files with 4435 additions and 1343 deletions

View File

@@ -1,35 +1,144 @@
"""
插件基类模块
提供插件的基础功能:
- 生命周期钩子on_load, on_enable, on_disable, on_unload, on_reload
- 定时任务管理
- 依赖声明
- 插件元数据
"""
from abc import ABC
from typing import List
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 = ["MessageLogger", "AIChat"]
dependencies: List[str] = []
# 加载优先级数值越大越先加载默认50
# 基础插件设置高优先级,依赖其他插件的设置低优先级
load_priority: int = 50
# ==================== 实例属性 ====================
def __init__(self):
self.enabled = False
self._scheduled_jobs = set()
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'):
@@ -39,18 +148,85 @@ class PluginBase(ABC):
add_job_safe(scheduler, job_id, method, bot, trigger, **trigger_args)
self._scheduled_jobs.add(job_id)
if self._scheduled_jobs:
logger.success("插件 {} 已加载定时任务: {}", self.__class__.__name__, 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)
logger.info("已卸载定时任务: {}", self._scheduled_jobs)
if self._scheduled_jobs:
logger.info(f"已卸载定时任务: {self._scheduled_jobs}")
self._scheduled_jobs.clear()
async def async_init(self):
"""插件异步初始化"""
return
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}>"