feat: 添加Discord适配器与跨平台消息互通功能
新增Discord适配器支持,实现Discord与QQ之间的消息互通 添加通用数据模型用于跨平台消息转换 扩展配置系统以支持Discord和日志配置 重构日志系统以使用配置中的日志级别 在反向WebSocket管理器中注册Bot实例 更新主程序以支持Discord客户端启动 添加测试脚本验证核心功能
This commit is contained in:
@@ -7,7 +7,7 @@ from pathlib import Path
|
||||
|
||||
import tomllib
|
||||
from pydantic import ValidationError
|
||||
from .config_models import ConfigModel, NapCatWSModel, BotModel, RedisModel, DockerModel, ImageManagerModel, MySQLModel, ReverseWSModel, ThreadingModel, BilibiliModel, LocalFileServerModel
|
||||
from .config_models import ConfigModel, NapCatWSModel, BotModel, RedisModel, DockerModel, ImageManagerModel, MySQLModel, ReverseWSModel, ThreadingModel, BilibiliModel, LocalFileServerModel, DiscordModel, LoggingModel
|
||||
from .utils.logger import ModuleLogger
|
||||
from .utils.exceptions import ConfigError, ConfigNotFoundError, ConfigValidationError
|
||||
|
||||
@@ -156,7 +156,20 @@ class Config:
|
||||
获取本地文件服务器配置
|
||||
"""
|
||||
return self._model.local_file_server
|
||||
|
||||
@property
|
||||
def discord(self) -> DiscordModel:
|
||||
"""
|
||||
获取 Discord 配置
|
||||
"""
|
||||
return self._model.discord
|
||||
|
||||
@property
|
||||
def logging(self) -> LoggingModel:
|
||||
"""
|
||||
获取日志配置
|
||||
"""
|
||||
return self._model.logging
|
||||
|
||||
|
||||
# 实例化全局配置对象
|
||||
|
||||
@@ -107,6 +107,23 @@ class LocalFileServerModel(BaseModel):
|
||||
port: int = 3003
|
||||
|
||||
|
||||
class DiscordModel(BaseModel):
|
||||
"""
|
||||
对应 `config.toml` 中的 `[discord]` 配置块。
|
||||
"""
|
||||
enabled: bool = False
|
||||
token: str = ""
|
||||
|
||||
|
||||
class LoggingModel(BaseModel):
|
||||
"""
|
||||
对应 `config.toml` 中的 `[logging]` 配置块。
|
||||
"""
|
||||
level: str = "DEBUG"
|
||||
file_level: str = "DEBUG"
|
||||
console_level: str = "INFO"
|
||||
|
||||
|
||||
class ConfigModel(BaseModel):
|
||||
"""
|
||||
顶层配置模型,整合了所有子配置块。
|
||||
@@ -121,5 +138,7 @@ class ConfigModel(BaseModel):
|
||||
threading: ThreadingModel = Field(default_factory=ThreadingModel)
|
||||
bilibili: BilibiliModel = Field(default_factory=BilibiliModel)
|
||||
local_file_server: LocalFileServerModel = Field(default_factory=LocalFileServerModel)
|
||||
discord: DiscordModel = Field(default_factory=DiscordModel)
|
||||
logging: LoggingModel = Field(default_factory=LoggingModel)
|
||||
|
||||
|
||||
|
||||
@@ -317,6 +317,7 @@ class ReverseWSManager:
|
||||
|
||||
# 为事件注入Bot实例
|
||||
from ..ws import ReverseWSClient
|
||||
from .bot_manager import bot_manager
|
||||
|
||||
# 为每个前端创建独立的Bot实例
|
||||
with self._bots_lock:
|
||||
@@ -325,6 +326,10 @@ class ReverseWSManager:
|
||||
temp_ws = ReverseWSClient(self, client_id)
|
||||
temp_ws.self_id = event.self_id if hasattr(event, 'self_id') else 0
|
||||
self.bots[client_id] = Bot(temp_ws)
|
||||
|
||||
# 注册到 BotManager
|
||||
if event.self_id:
|
||||
bot_manager.register_bot(self.bots[client_id])
|
||||
|
||||
event.bot = self.bots[client_id]
|
||||
|
||||
@@ -465,7 +470,7 @@ class ReverseWSManager:
|
||||
clients_to_send.append((cid, self.clients[cid]))
|
||||
|
||||
for cid, websocket in clients_to_send:
|
||||
await websocket.send(orjson.dumps(payload))
|
||||
await websocket.send(orjson.dumps(payload).decode('utf-8'))
|
||||
|
||||
return await asyncio.wait_for(future, timeout=30.0)
|
||||
except asyncio.TimeoutError:
|
||||
|
||||
@@ -8,6 +8,13 @@ import os
|
||||
from pathlib import Path
|
||||
from loguru import logger
|
||||
|
||||
# 导入全局配置
|
||||
try:
|
||||
from ..config_loader import global_config
|
||||
USE_CONFIG = True
|
||||
except ImportError:
|
||||
USE_CONFIG = False
|
||||
|
||||
# 定义日志格式,添加进程ID和线程ID作为上下文信息
|
||||
LOG_FORMAT = (
|
||||
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
||||
@@ -30,14 +37,21 @@ DEBUG_LOG_FORMAT = (
|
||||
# 移除 loguru 默认的处理器
|
||||
logger.remove()
|
||||
|
||||
# 获取当前环境
|
||||
ENVIRONMENT = os.getenv("NEOBOT_ENV", "development")
|
||||
# 获取日志级别配置
|
||||
if USE_CONFIG:
|
||||
LOG_LEVEL = global_config.logging.level
|
||||
FILE_LEVEL = global_config.logging.file_level
|
||||
CONSOLE_LEVEL = global_config.logging.console_level
|
||||
else:
|
||||
LOG_LEVEL = "DEBUG"
|
||||
FILE_LEVEL = "DEBUG"
|
||||
CONSOLE_LEVEL = "INFO"
|
||||
|
||||
# 添加控制台输出处理器
|
||||
logger.add(
|
||||
sys.stderr,
|
||||
level="INFO" if ENVIRONMENT == "production" else "DEBUG",
|
||||
format=LOG_FORMAT if ENVIRONMENT == "production" else DEBUG_LOG_FORMAT,
|
||||
level=CONSOLE_LEVEL,
|
||||
format=LOG_FORMAT,
|
||||
colorize=True,
|
||||
enqueue=True # 异步写入
|
||||
)
|
||||
@@ -50,7 +64,7 @@ log_file_path = log_dir / "{time:YYYY-MM-DD}.log"
|
||||
# 添加文件输出处理器
|
||||
logger.add(
|
||||
log_file_path,
|
||||
level="DEBUG",
|
||||
level=FILE_LEVEL,
|
||||
format=DEBUG_LOG_FORMAT,
|
||||
colorize=False,
|
||||
rotation="00:00", # 每天午夜创建新文件
|
||||
|
||||
@@ -291,7 +291,7 @@ class WS:
|
||||
self._pending_requests[echo_id] = future
|
||||
|
||||
try:
|
||||
await self.ws.send(orjson.dumps(payload))
|
||||
await self.ws.send(orjson.dumps(payload).decode('utf-8'))
|
||||
return await asyncio.wait_for(future, timeout=30.0)
|
||||
except asyncio.TimeoutError:
|
||||
with self._pending_requests_lock:
|
||||
|
||||
Reference in New Issue
Block a user