feat: 添加测试用例并优化代码结构

refactor(permission_manager): 调整初始化顺序和逻辑
fix(admin_manager): 修复初始化逻辑和目录创建问题
feat(ws): 优化Bot实例初始化条件
feat(message): 增强MessageSegment功能并添加测试
feat(events): 支持字符串格式的消息解析
test: 添加核心功能测试用例
refactor(plugin_manager): 改进插件路径处理
style: 清理无用导入和代码
chore: 更新依赖项
This commit is contained in:
2026-01-09 00:20:30 +08:00
parent 5d07a84283
commit 77348113e3
18 changed files with 754 additions and 73 deletions

View File

@@ -1,3 +1,3 @@
{
"admins": []
"admins": [2221577113]
}

View File

@@ -6,11 +6,12 @@
"""
import inspect
from abc import ABC, abstractmethod
from typing import Any, Callable, Dict, List, Optional, Tuple
from typing import Any, Callable, Dict, List, Optional, Tuple, TYPE_CHECKING
from ..bot import Bot
if TYPE_CHECKING:
from ..bot import Bot
from ..config_loader import global_config
from ..managers.permission_manager import Permission
from ..permission import Permission
from ..utils.executor import run_in_thread_pool
@@ -22,7 +23,7 @@ class BaseHandler(ABC):
self.handlers: List[Dict[str, Any]] = []
@abstractmethod
async def handle(self, bot: Bot, event: Any):
async def handle(self, bot: "Bot", event: Any):
"""
处理事件
"""
@@ -31,7 +32,7 @@ class BaseHandler(ABC):
async def _run_handler(
self,
func: Callable,
bot: Bot,
bot: "Bot",
event: Any,
args: Optional[List[str]] = None,
permission_granted: Optional[bool] = None
@@ -122,7 +123,7 @@ class MessageHandler(BaseHandler):
return func
return decorator
async def handle(self, bot: Bot, event: Any):
async def handle(self, bot: "Bot", event: Any):
"""
处理消息事件,分发给命令处理器或通用消息处理器
"""

View File

@@ -26,8 +26,7 @@ class AdminManager(Singleton):
"""
初始化 AdminManager
"""
super().__init__()
if not self._initialized:
if hasattr(self, '_initialized') and self._initialized:
return
# 管理员数据文件路径
@@ -39,7 +38,12 @@ class AdminManager(Singleton):
)
self._admins: Set[int] = set()
# 确保数据目录存在
os.makedirs(os.path.dirname(self.data_file), exist_ok=True)
logger.info("管理员管理器初始化完成")
super().__init__()
async def initialize(self):
"""

View File

@@ -41,7 +41,6 @@ class PermissionManager(Singleton):
如果已经初始化过,则直接返回。
"""
super().__init__()
if hasattr(self, '_initialized') and self._initialized:
return
@@ -64,7 +63,7 @@ class PermissionManager(Singleton):
self.load()
logger.info("权限管理器初始化完成")
self._initialized = True
super().__init__()
def load(self) -> None:
"""

View File

@@ -30,12 +30,21 @@ class PluginManager:
"""
扫描并加载 `plugins` 目录下的所有插件。
"""
plugin_dir = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "..", "..", "plugins"
)
# 使用 pathlib 获取更可靠的路径
# 当前文件: core/managers/plugin_manager.py
# 目标: plugins/
current_dir = os.path.dirname(os.path.abspath(__file__))
# 回退两级到项目根目录 (core/managers -> core -> root)
root_dir = os.path.dirname(os.path.dirname(current_dir))
plugin_dir = os.path.join(root_dir, "plugins")
package_name = "plugins"
logger.info(f"正在从 {package_name} 加载插件...")
if not os.path.exists(plugin_dir):
logger.error(f"插件目录不存在: {plugin_dir}")
return
logger.info(f"正在从 {package_name} 加载插件 (路径: {plugin_dir})...")
for _, module_name, is_pkg in pkgutil.iter_modules([plugin_dir]):
full_module_name = f"{package_name}.{module_name}"

View File

@@ -33,13 +33,10 @@ class Permission(Enum):
return NotImplemented
return self._level_map[self] < self._level_map[other]
def __eq__(self, other):
if not isinstance(other, Permission):
return NotImplemented
return self is other
def __ge__(self, other):
"""
比较当前权限是否大于等于另一个权限。
"""
if not isinstance(other, Permission):
return NotImplemented
return self._level_map[self] >= self._level_map[other]

View File

@@ -60,7 +60,15 @@ class CodeExecutor:
将代码执行任务添加到队列中。
:param code: 待执行的 Python 代码字符串。
:param callback: 执行完毕后用于回复结果的回调函数。
:raises RuntimeError: 如果 Docker 客户端未初始化。
"""
if not self.docker_client:
logger.warning("[CodeExecutor] 尝试添加任务,但 Docker 客户端未初始化。任务被拒绝。")
# 这里可以选择抛出异常,或者直接调用回调返回错误信息
# 为了用户体验,我们构造一个错误结果并直接调用回调(如果可能)
# 但由于 callback 返回 Future这里简单起见我们记录日志并抛出异常
raise RuntimeError("Docker环境未就绪无法执行代码。")
task = {"code": code, "callback": callback}
await self.task_queue.put(task)
logger.info(f"[CodeExecutor] 新的代码执行任务已入队 (队列当前长度: {self.task_queue.qsize()})。")

View File

@@ -128,8 +128,9 @@ class WS:
# 使用工厂创建事件对象
event = EventFactory.create_event(event_data)
# 在收到第一个 meta_event 时,初始化 Bot 实例
if event.post_type == "meta_event" and self.bot is None:
# 尝试初始化 Bot 实例 (如果尚未初始化且事件包含 self_id)
# 只要事件中包含 self_id我们就可以初始化 Bot不必非要等待 meta_event
if self.bot is None and hasattr(event, 'self_id'):
self.self_id = event.self_id
self.bot = Bot(self)
logger.success(f"Bot 实例初始化完成: self_id={self.self_id}")