refactor: web_server 模块化拆分(web/ 蓝图包 auth/monitor/tasks/admin/tools/devices/apks/tailscale + context/common,web_server 1796→193 行仅留装配与启动)+ 大屏优化(网格 5s 轮询、弹窗独占缩略图、流支持 q/fps)+ 三修复(MIUI 屏幕状态检测改 dumpsys power、补 ADB_PATH 导入修复一键亮屏、renderGrid 增量渲染不重载缩略图)

This commit is contained in:
2026-08-19 14:55:29 +08:00
parent e07b339a51
commit ce47a5b83d
16 changed files with 1922 additions and 1780 deletions
+119
View File
@@ -0,0 +1,119 @@
"""设备池管理 API(本地 SQLite 清单)。"""
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
from flask import Blueprint, jsonify, request
from core import device_pool
from core.adb_helper import adb_connect
from core.logger import get_logger
from web.auth import perm_required, PERM_DEVICES
_log = get_logger("web")
bp = Blueprint("devices", __name__)
@bp.route("/api/devices/pool", methods=["GET"])
@perm_required(PERM_DEVICES)
def api_devices_pool_list():
"""设备池清单(SQLite,含实时在线状态)。"""
try:
online = set(device_pool.list_online())
except Exception:
online = set()
rows = device_pool.list_devices()
for r in rows:
r["online"] = r["serial"] in online
return jsonify({"ok": True, "devices": rows})
@bp.route("/api/devices/pool/add", methods=["POST"])
@perm_required(PERM_DEVICES)
def api_devices_pool_add():
"""添加/更新设备:{serial, name?, note?}。
IP:5555 设备添加后立即尝试 adb connect(不可达显示离线,不影响其他设备)。
"""
data = request.json or {}
serial = (data.get("serial") or "").strip()
if not serial:
return jsonify({"ok": False, "error": "请输入设备 serial(如 100.100.10.20:5555)"}), 400
is_new = device_pool.add_device(serial,
name=(data.get("name") or "").strip(),
note=(data.get("note") or "").strip())
msg = "已添加" if is_new else "已更新"
if ":" in serial:
try:
adb_connect(serial)
except Exception:
pass
# 后台采集型号(不阻塞添加响应)
import threading
threading.Thread(target=device_pool.refresh_model, args=(serial,),
daemon=True).start()
_log.info(f"设备池管理: {msg} {serial}")
return jsonify({"ok": True, "msg": msg, "is_new": is_new})
@bp.route("/api/devices/pool/remove", methods=["POST"])
@perm_required(PERM_DEVICES)
def api_devices_pool_remove():
"""从设备池删除(不再参与调度;不影响其他系统)。"""
serial = (request.json or {}).get("serial", "").strip()
if not serial:
return jsonify({"ok": False, "error": "缺少 serial"}), 400
ok = device_pool.remove_device(serial)
if not ok:
return jsonify({"ok": False, "error": "设备不存在"}), 404
return jsonify({"ok": True, "msg": "已删除"})
@bp.route("/api/devices/pool/toggle", methods=["POST"])
@perm_required(PERM_DEVICES)
def api_devices_pool_toggle():
"""启用/停用设备(停用后不参与调度)。"""
data = request.json or {}
serial = (data.get("serial") or "").strip()
enabled = data.get("enabled")
if not serial or enabled is None:
return jsonify({"ok": False, "error": "缺少参数"}), 400
ok = device_pool.set_enabled(serial, bool(enabled))
if not ok:
return jsonify({"ok": False, "error": "设备不存在"}), 404
return jsonify({"ok": True, "msg": "已" + ("启用" if enabled else "停用")})
@bp.route("/api/devices/pool/reconnect", methods=["POST"])
@perm_required(PERM_DEVICES)
def api_devices_pool_reconnect():
"""一键重连:并发 adb connect 池内全部 IP:5555 设备(后台执行,不阻塞)。"""
def _run():
try:
serials = [s for s in device_pool.list_configured() if ":" in s]
except Exception:
return
if not serials:
return
from concurrent.futures import ThreadPoolExecutor, as_completed
with ThreadPoolExecutor(max_workers=10) as pool:
futures = {pool.submit(adb_connect, s): s for s in serials}
for _ in as_completed(futures):
pass
_log.info(f"设备池一键重连完成({len(serials)} 台)")
# 重连后顺手刷新型号
try:
device_pool.refresh_all_models()
except Exception:
pass
import threading
threading.Thread(target=_run, daemon=True).start()
return jsonify({"ok": True, "msg": "重连已启动(后台并发,约 10-20 秒)"})
@bp.route("/api/devices/pool/refresh_models", methods=["POST"])
@perm_required(PERM_DEVICES)
def api_devices_pool_refresh_models():
"""批量采集池内在线设备的型号(后台执行,不阻塞)。"""
import threading
threading.Thread(target=device_pool.refresh_all_models, daemon=True).start()
return jsonify({"ok": True, "msg": "型号采集已启动(后台并发,约 10 秒)"})
# ================== API:Tailscale 管理(仅管理员) ==================
# 通过 Tailscale 官方 API v2 管理 tailnet 设备(列表/改名/授权/密钥不过期/删除/生成 auth key)。
# 设备 IP 由 tailnet 自动分配,API 无法修改,列表只读展示。