diff --git a/app/core/config.py b/app/core/config.py index 5e45ce6..7213658 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -124,22 +124,37 @@ class GlobalConfig(ConfigBase): Data_UID = ConfigItem("Data", "UID", str(uuid.uuid4()), UUIDValidator()) Data_LastStatisticsUpload = ConfigItem( - "Data", "LastStatisticsUpload", "2000-01-01 00:00:00", DateTimeValidator() + "Data", + "LastStatisticsUpload", + "2000-01-01 00:00:00", + DateTimeValidator("%Y-%m-%d %H:%M:%S"), ) Data_LastStageUpdated = ConfigItem( - "Data", "LastStageUpdated", "2000-01-01 00:00:00", DateTimeValidator() + "Data", + "LastStageUpdated", + "2000-01-01 00:00:00", + DateTimeValidator("%Y-%m-%d %H:%M:%S"), ) Data_StageTimeStamp = ConfigItem( - "Data", "StageTimeStamp", "2000-01-01 00:00:00", DateTimeValidator() + "Data", + "StageTimeStamp", + "2000-01-01 00:00:00", + DateTimeValidator("%Y-%m-%d %H:%M:%S"), ) Data_Stage = ConfigItem("Data", "Stage", "{ }", JSONValidator()) Data_LastNoticeUpdated = ConfigItem( - "Data", "LastNoticeUpdated", "2000-01-01 00:00:00", DateTimeValidator() + "Data", + "LastNoticeUpdated", + "2000-01-01 00:00:00", + DateTimeValidator("%Y-%m-%d %H:%M:%S"), ) Data_IfShowNotice = ConfigItem("Data", "IfShowNotice", True, BoolValidator()) Data_Notice = ConfigItem("Data", "Notice", "{ }", JSONValidator()) Data_LastWebConfigUpdated = ConfigItem( - "Data", "LastWebConfigUpdated", "2000-01-01 00:00:00", DateTimeValidator() + "Data", + "LastWebConfigUpdated", + "2000-01-01 00:00:00", + DateTimeValidator("%Y-%m-%d %H:%M:%S"), ) Data_WebConfig = ConfigItem("Data", "WebConfig", "{ }", JSONValidator()) @@ -265,11 +280,15 @@ class MaaUserConfig(ConfigBase): "Info", "SklandToken", "", EncryptValidator() ) - self.Data_LastProxyDate = ConfigItem("Data", "LastProxyDate", "2000-01-01") - self.Data_LastAnnihilationDate = ConfigItem( - "Data", "LastAnnihilationDate", "2000-01-01" + self.Data_LastProxyDate = ConfigItem( + "Data", "LastProxyDate", "2000-01-01", DateTimeValidator("%Y-%m-%d") + ) + self.Data_LastAnnihilationDate = ConfigItem( + "Data", "LastAnnihilationDate", "2000-01-01", DateTimeValidator("%Y-%m-%d") + ) + self.Data_LastSklandDate = ConfigItem( + "Data", "LastSklandDate", "2000-01-01", DateTimeValidator("%Y-%m-%d") ) - self.Data_LastSklandDate = ConfigItem("Data", "LastSklandDate", "2000-01-01") self.Data_ProxyTimes = ConfigItem( "Data", "ProxyTimes", 0, RangeValidator(0, 9999) ) diff --git a/app/models/ConfigBase.py b/app/models/ConfigBase.py index 67c263d..40d6c28 100644 --- a/app/models/ConfigBase.py +++ b/app/models/ConfigBase.py @@ -30,7 +30,7 @@ from typing import List, Any, Dict, Union, Optional from app.utils import dpapi_encrypt, dpapi_decrypt -from app.utils.constants import RESERVED_NAMES, ILLEGAL_CHARS +from app.utils.constants import RESERVED_NAMES, ILLEGAL_CHARS, DEFAULT_DATETIME class ConfigValidator: @@ -114,24 +114,30 @@ class UUIDValidator(ConfigValidator): class DateTimeValidator(ConfigValidator): + """日期时间验证器""" + + def __init__(self, date_format: str) -> None: + if not date_format: + raise ValueError("日期时间格式不能为空") + self.date_format = date_format def validate(self, value: Any) -> bool: if not isinstance(value, str): return False try: - datetime.strptime(value, "%Y-%m-%d %H:%M:%S") + datetime.strptime(value, self.date_format) return True except ValueError: return False def correct(self, value: Any) -> str: if not isinstance(value, str): - return "2000-01-01 00:00:00" + return DEFAULT_DATETIME.strftime(self.date_format) try: - datetime.strptime(value, "%Y-%m-%d %H:%M:%S") + datetime.strptime(value, self.date_format) return value except ValueError: - return "2000-01-01 00:00:00" + return DEFAULT_DATETIME.strftime(self.date_format) class JSONValidator(ConfigValidator): diff --git a/app/utils/constants.py b/app/utils/constants.py index 2877126..dac3cbf 100644 --- a/app/utils/constants.py +++ b/app/utils/constants.py @@ -20,6 +20,8 @@ # Contact: DLmaster_361@163.com +from datetime import datetime + RESOURCE_STAGE_INFO = [ {"value": "-", "text": "当前/上次", "days": [1, 2, 3, 4, 5, 6, 7]}, {"value": "1-7", "text": "1-7", "days": [1, 2, 3, 4, 5, 6, 7]}, @@ -270,3 +272,6 @@ MIRROR_ERROR_INFO = { 1: "未知错误类型", } """MirrorChyan错误代码映射表""" + +DEFAULT_DATETIME = datetime.strptime("2000-01-01 00:00:00", "%Y-%m-%d %H:%M:%S") +"""默认日期时间""" diff --git a/docs/Backend_Task_Scheduling_and_WebSocket_Messages.md b/docs/Backend_Task_Scheduling_and_WebSocket_Messages.md new file mode 100644 index 0000000..4f291ba --- /dev/null +++ b/docs/Backend_Task_Scheduling_and_WebSocket_Messages.md @@ -0,0 +1,388 @@ +# AUTO-MAS 后端任务调度逻辑与WebSocket消息格式说明 + +## 1. 任务调度架构概览 + +AUTO-MAS 后端采用基于 AsyncIO 的异步任务调度系统,主要由以下核心组件构成: + +### 1.1 核心组件 + +- **TaskManager**: 任务调度器,负责任务的创建、运行、停止和清理 +- **Broadcast**: 消息广播系统,负责在不同组件间传递消息 +- **WebSocket**: 与前端的实时通信通道 +- **Config**: 配置管理系统,包含脚本配置、队列配置等 + +### 1.2 任务类型 + +系统支持三种主要任务模式: + +1. **设置脚本** - 直接执行单个脚本配置 +2. **自动代理** - 按队列顺序自动执行多个脚本 +3. **人工排查** - 手动排查和执行任务 + +## 2. 任务调度流程 + +### 2.1 任务创建流程 + +``` +前端请求 → API接口 → TaskManager.add_task() → 任务验证 → 创建异步任务 → 返回任务ID +``` + +**具体步骤:** + +1. **任务验证**: 根据模式和UID验证任务配置是否存在 +2. **重复检查**: 确保相同任务未在运行中 +3. **任务创建**: 使用`asyncio.create_task()`创建异步任务 +4. **回调设置**: 添加任务完成回调用于清理工作 + +### 2.2 任务执行流程 + +#### 设置脚本模式 +``` +获取脚本配置 → 确定脚本类型(MAA/General) → 创建对应Manager → 执行任务 +``` + +#### 自动代理模式 +``` +获取队列配置 → 构建任务列表 → 逐个执行脚本 → 更新状态 → 发送完成信号 +``` + +### 2.3 任务状态管理 + +- **等待**: 任务已加入队列但未开始执行 +- **运行**: 任务正在执行中 +- **跳过**: 任务因重复或其他原因被跳过 +- **完成**: 任务执行完毕 + +## 3. WebSocket 消息系统 + +### 3.1 消息基础结构 + +所有WebSocket消息都遵循统一的JSON格式: + +```json +{ + "id": "消息ID或任务ID", + "type": "消息类型", + "data": { + "具体数据": "根据类型而定" + } +} +``` + +### 3.2 消息类型详解 + +#### 3.2.1 Update 类型 - 数据更新 + +**用途**: 通知前端更新界面数据 + +**常见数据格式:** + +```json +{ + "id": "task-uuid", + "type": "Update", + "data": { + "user_list": [ + { + "name": "用户名", + "status": "运行状态", + "config": "配置信息" + } + ] + } +} +``` + +```json +{ + "id": "task-uuid", + "type": "Update", + "data": { + "task_list": [ + { + "script_id": "脚本ID", + "status": "等待/运行/完成/跳过", + "name": "脚本名称" + } + ] + } +} +``` + +```json +{ + "id": "task-uuid", + "type": "Update", + "data": { + "log": "任务执行日志内容" + } +} +``` + +#### 3.2.2 Info 类型 - 信息显示 + +**用途**: 向前端发送需要显示的信息,包括普通信息、警告和错误 + +**数据格式:** + +```json +{ + "id": "task-uuid", + "type": "Info", + "data": { + "Error": "错误信息内容" + } +} +``` + +```json +{ + "id": "task-uuid", + "type": "Info", + "data": { + "Warning": "警告信息内容" + } +} +``` + +```json +{ + "id": "task-uuid", + "type": "Info", + "data": { + "Info": "普通信息内容" + } +} +``` + +#### 3.2.3 Message 类型 - 对话框请求 + +**用途**: 请求前端弹出对话框显示重要信息 + +**数据格式:** + +```json +{ + "id": "task-uuid", + "type": "Message", + "data": { + "title": "对话框标题", + "content": "对话框内容", + "type": "info/warning/error" + } +} +``` + +#### 3.2.4 Signal 类型 - 程序信号 + +**用途**: 发送程序控制信号和状态通知 + +**常见信号:** + +**任务完成信号:** +```json +{ + "id": "task-uuid", + "type": "Signal", + "data": { + "Accomplish": "任务完成后调度台显示的日志内容" + } +} +``` + +**电源操作信号:** +```json +{ + "id": "task-uuid", + "type": "Signal", + "data": { + "power": "NoAction/KillSelf/Sleep/Hibernate/Shutdown/ShutdownForce", + } +} +``` + +**心跳信号:** +```json +{ + "id": "Main", + "type": "Signal", + "data": { + "Ping": "无描述" + } +} +``` + +```json +{ + "id": "Main", + "type": "Signal", + "data": { + "Pong": "无描述" + } +} +``` + +## 4. 任务管理器详细说明 + +### 4.1 TaskManager 核心方法 + +#### add_task(mode: str, uid: str) +- **功能**: 添加新任务到调度队列 +- **参数**: + - `mode`: 任务模式 ("设置脚本", "自动代理", "人工排查") + - `uid`: 任务唯一标识符 +- **返回**: 任务UUID + +#### stop_task(task_id: str) +- **功能**: 停止指定任务 +- **参数**: + - `task_id`: 任务ID,支持 "ALL" 停止所有任务 + +#### run_task(mode: str, task_id: UUID, actual_id: Optional[UUID]) +- **功能**: 执行具体任务逻辑 +- **流程**: 根据模式选择相应的执行策略 + +### 4.2 任务执行器 + +#### GeneralManager +- **用途**: 处理通用脚本任务 +- **特点**: 支持自定义脚本路径和参数 +- **配置**: 基于 GeneralConfig 和 GeneralUserConfig + +#### MaaManager +- **用途**: 处理MAA (明日方舟助手) 专用任务 +- **特点**: 支持模拟器控制、ADB连接、游戏自动化 +- **配置**: 基于 MaaConfig 和 MaaUserConfig + +## 5. 消息广播系统 + +### 5.1 Broadcast 机制 + +- **设计模式**: 发布-订阅模式 +- **功能**: 实现组件间解耦的消息传递 +- **特点**: 支持多个订阅者同时接收消息 + +### 5.2 消息流向 + +``` +任务执行器 → Broadcast → WebSocket → 前端界面 + ↓ + 其他订阅者 +``` + +## 6. 配置管理系统 + +### 6.1 配置类型 + +- **ScriptConfig**: 脚本配置,包含MAA和General两种类型 +- **QueueConfig**: 队列配置,定义自动代理任务的执行顺序 +- **GlobalConfig**: 全局系统配置 + +### 6.2 配置操作 + +- **锁机制**: 防止配置在使用时被修改 +- **实时更新**: 支持动态加载配置变更 +- **类型验证**: 确保配置数据的正确性 + +## 7. API 接口说明 + +### 7.1 任务控制接口 + +**创建任务** +- **端点**: `POST /api/dispatch/start` +- **请求体**: + ```json + { + "mode": "自动代理|人工排查|设置脚本", + "taskId": "目标任务ID" + } + ``` +- **响应**: + ```json + { + "code": 200, + "status": "success", + "message": "操作成功", + "websocketId": "新任务ID" + } + ``` + +**停止任务** +- **端点**: `POST /api/dispatch/stop` +- **请求体**: + ```json + { + "taskId": "要停止的任务ID" + } + ``` + +**电源操作** +- **端点**: `POST /api/dispatch/power` +- **请求体**: + ```json + { + "signal": "NoAction|Shutdown|ShutdownForce|Hibernate|Sleep|KillSelf" + } + ``` + +### 7.2 WebSocket 连接 + +**端点**: `WS /api/core/ws` + +**连接特性**: +- 同时只允许一个WebSocket连接 +- 自动心跳检测 (15秒超时) +- 连接断开时自动清理资源 + +## 8. 错误处理机制 + +### 8.1 异常类型 + +- **ValueError**: 配置验证失败 +- **RuntimeError**: 任务状态冲突 +- **TimeoutError**: 操作超时 +- **ConnectionError**: 连接相关错误 + +### 8.2 错误响应格式 + +```json +{ + "id": "相关任务ID", + "type": "Info", + "data": { + "Error": "具体错误描述" + } +} +``` + +## 9. 性能和监控 + +### 9.1 日志系统 + +- **分层日志**: 按模块划分日志记录器 +- **实时监控**: 支持日志实时推送到前端 +- **文件轮转**: 自动管理日志文件大小 + +### 9.2 资源管理 + +- **进程管理**: 自动清理子进程 +- **内存监控**: 防止内存泄漏 +- **连接池**: 复用数据库和网络连接 + +## 10. 安全考虑 + +### 10.1 输入验证 + +- **参数校验**: 使用 Pydantic 模型验证 +- **路径安全**: 防止路径遍历攻击 +- **命令注入**: 严格控制执行的命令参数 + +### 10.2 权限控制 + +- **单一连接**: 限制WebSocket连接数量 +- **操作限制**: 防止重复或冲突操作 +- **资源保护**: 防止资源滥用 + +--- + +*此文档基于 AUTO-MAS v5.0.0 版本编写,详细的API文档和配置说明请参考相关配置文件和源代码注释。* diff --git a/frontend/src/components/ScriptTable.vue b/frontend/src/components/ScriptTable.vue index 7ddb8d7..b1ecdce 100644 --- a/frontend/src/components/ScriptTable.vue +++ b/frontend/src/components/ScriptTable.vue @@ -37,24 +37,24 @@ type="primary" ghost size="middle" - @click="handleMAAConfig(script)" + @click="handleStartMAAConfig(script)" > - 设置MAA全局配置 + 配置MAA - 断开配置连接 + 保存配置