feat: 后端添加电源操作逻辑

This commit is contained in:
DLmaster361
2025-09-23 16:00:13 +08:00
parent 1a541cbc63
commit 76f330e4d3
10 changed files with 112 additions and 26 deletions

View File

@@ -22,7 +22,7 @@
from fastapi import APIRouter, Body
from app.core import TaskManager
from app.core import Config, TaskManager
from app.services import System
from app.models.schema import *
@@ -58,11 +58,27 @@ async def stop_task(task: DispatchIn = Body(...)) -> OutBase:
return OutBase()
@router.post("/power", summary="电源操作", response_model=OutBase, status_code=200)
async def power_task(task: PowerIn = Body(...)) -> OutBase:
@router.post(
"/set/power", summary="设置电源标志", response_model=OutBase, status_code=200
)
async def set_power(task: PowerIn = Body(...)) -> OutBase:
try:
await System.set_power(task.signal)
Config.power_sign = task.signal
except Exception as e:
return OutBase(
code=500, status="error", message=f"{type(e).__name__}: {str(e)}"
)
return OutBase()
@router.post(
"/cancel/power", summary="取消电源任务", response_model=OutBase, status_code=200
)
async def cancel_power_task() -> OutBase:
try:
await System.cancel_power_task()
except Exception as e:
return OutBase(
code=500, status="error", message=f"{type(e).__name__}: {str(e)}"

View File

@@ -659,6 +659,9 @@ class AppConfig(GlobalConfig):
self.server: Optional[uvicorn.Server] = None
self.websocket: Optional[WebSocket] = None
self.power_sign: Literal[
"NoAction", "Shutdown", "ShutdownForce", "Hibernate", "Sleep", "KillSelf"
] = "NoAction"
self.silence_dict: Dict[Path, datetime] = {}
self.if_ignore_silence: List[uuid.UUID] = []
self.temp_task: List[asyncio.Task] = []
@@ -1924,7 +1927,7 @@ class AppConfig(GlobalConfig):
try:
response = requests.get(
"https://download.auto-mas.top/d/AUTO_MAA/Server/notice.json",
"https://download.auto-mas.top/d/AUTO_MAS/Server/notice.json",
timeout=10,
proxies=self.get_proxies(),
)

View File

@@ -25,9 +25,11 @@ from functools import partial
from typing import Dict, Optional, Literal
from .config import Config, MaaConfig, GeneralConfig, QueueConfig
from app.services import System
from app.models.schema import WebSocketMessage
from app.utils import get_logger
from app.task import *
from app.utils.constants import POWER_SIGN_MAP
logger = get_logger("业务调度")
@@ -321,17 +323,25 @@ class _TaskManager:
if mode == "自动代理" and task_id in Config.QueueConfig:
await Config.send_json(
WebSocketMessage(
id=str(task_id),
type="Signal",
data={
"power": Config.QueueConfig[task_id].get(
"Info", "AfterAccomplish"
)
},
).model_dump()
)
if Config.power_sign != "NoAction":
Config.power_sign = Config.QueueConfig[task_id].get(
"Info", "AfterAccomplish"
)
if len(self.task_dict) == 0 and Config.power_sign != "NoAction":
logger.info(f"所有任务已结束,准备执行电源操作: {Config.power_sign}")
await Config.send_json(
WebSocketMessage(
id="Main",
type="Message",
data={
"type": "Countdown",
"title": f"{POWER_SIGN_MAP[Config.power_sign]}倒计时",
"message": f"程序将在倒计时结束后执行 {POWER_SIGN_MAP[Config.power_sign]} 操作",
},
).model_dump()
)
await System.start_power_task()
async def start_startup_queue(self):
"""开始运行启动时运行的调度队列"""

View File

@@ -21,6 +21,7 @@
import sys
import ctypes
import asyncio
import win32gui
import win32process
import psutil
@@ -29,9 +30,10 @@ import tempfile
import getpass
from datetime import datetime
from pathlib import Path
from typing import Literal
from typing import Literal, Optional
from app.core import Config
from app.models.schema import WebSocketMessage
from app.utils.logger import get_logger
logger = get_logger("系统服务")
@@ -41,6 +43,10 @@ class _SystemHandler:
ES_CONTINUOUS = 0x80000000
ES_SYSTEM_REQUIRED = 0x00000001
countdown = 60
def __init__(self) -> None:
self.power_task: Optional[asyncio.Task] = None
async def set_Sleep(self) -> None:
"""同步系统休眠状态"""
@@ -245,6 +251,47 @@ class _SystemHandler:
logger.info("执行退出主程序操作")
Config.server.should_exit = True
async def _power_task(
self,
power_sign: Literal[
"NoAction", "Shutdown", "ShutdownForce", "Hibernate", "Sleep", "KillSelf"
],
) -> None:
"""电源任务"""
await asyncio.sleep(self.countdown)
if power_sign == "KillSelf":
await Config.send_json(
WebSocketMessage(
id="Main", type="Signal", data={"RequestClose": "请求前端关闭"}
).model_dump()
)
await self.set_power(power_sign)
async def start_power_task(self):
"""开始电源任务"""
if self.power_task is None or self.power_task.done():
self.power_task = asyncio.create_task(self._power_task(Config.power_sign))
logger.info(
f"电源任务已启动, {self.countdown}秒后执行: {Config.power_sign}"
)
else:
logger.warning("已有电源任务在运行, 请勿重复启动")
async def cancel_power_task(self):
"""取消电源任务"""
if self.power_task is not None and not self.power_task.done():
self.power_task.cancel()
try:
await self.power_task
except asyncio.CancelledError:
logger.info("电源任务已取消")
else:
logger.warning("当前无电源任务在运行")
raise RuntimeError("当前无电源任务在运行")
async def kill_emulator_processes(self):
"""这里暂时仅支持 MuMu 模拟器"""

View File

@@ -359,7 +359,7 @@ class _UpdateHandler:
await Config.send_json(
WebSocketMessage(
id="Update",
type="Message",
type="Info",
data={"Error": f"解压失败, {type(e).__name__}: {e}"},
).model_dump()
)

View File

@@ -1093,7 +1093,7 @@ class MaaManager:
return result_text
async def get_message(self, message_id: str):
"""获取当前任务的属性值"""
"""获取客户端回应消息"""
logger.info(f"等待客户端回应消息: {message_id}")

View File

@@ -102,28 +102,28 @@ RESOURCE_STAGE_DROP_INFO = {
"Display": "PR-A",
"Value": "PR-A",
"Drop": "PR-A",
"DropName": "医疗/重装芯片",
"DropName": "奶/盾芯片",
"Activity": {"Tip": "一四五日", "StageName": "资源关卡"},
},
"PR-B-1": {
"Display": "PR-B",
"Value": "PR-B",
"Drop": "PR-B",
"DropName": "/狙芯片",
"DropName": "术/狙芯片",
"Activity": {"Tip": "一二五六", "StageName": "资源关卡"},
},
"PR-C-1": {
"Display": "PR-C",
"Value": "PR-C",
"Drop": "PR-C",
"DropName": "/辅芯片",
"DropName": "先/辅芯片",
"Activity": {"Tip": "三四六日", "StageName": "资源关卡"},
},
"PR-D-1": {
"Display": "PR-D",
"Value": "PR-D",
"Drop": "PR-D",
"DropName": "/特芯片",
"DropName": "近/特芯片",
"Activity": {"Tip": "二三六日", "StageName": "资源关卡"},
},
}
@@ -229,6 +229,16 @@ MATERIALS_MAP = {
}
"""掉落物索引表"""
POWER_SIGN_MAP = {
"NoAction": "无动作",
"Shutdown": "关机",
"ShutdownForce": "强制关机",
"Hibernate": "休眠",
"Sleep": "睡眠",
"KillSelf": "退出程序",
}
"""电源操作类型索引表"""
RESERVED_NAMES = {
"CON",
"PRN",

View File

@@ -11,7 +11,7 @@ export function setMainWindow(window: BrowserWindow) {
mainWindow = window
}
const gitDownloadUrl = 'http://221.236.27.82:10197/d/AUTO_MAA/git.zip'
const gitDownloadUrl = 'https://download.auto-mas.top/d/AUTO_MAS/git.zip'
// 递归复制目录,包括文件和隐藏文件
function copyDirSync(src: string, dest: string) {

View File

@@ -68,7 +68,7 @@ async function installPip(pythonPath: string, appRoot: string): Promise<void> {
console.log('pip未安装开始安装...')
const getPipPath = path.join(pythonPath, 'get-pip.py')
const getPipUrl = 'http://221.236.27.82:10197/d/AUTO_MAA/get-pip.py'
const getPipUrl = 'https://download.auto-mas.top/d/AUTO_MAS/get-pip.py'
console.log(`Python可执行文件路径: ${pythonExe}`)
console.log(`get-pip.py下载URL: ${getPipUrl}`)

View File

@@ -104,7 +104,7 @@ def main():
await Config.send_json(
WebSocketMessage(
id="Main", type="Signal", data={"Close": "后端已安全关闭"}
id="Main", type="Signal", data={"Closed": "后端已安全关闭"}
).model_dump()
)