Files
auto_control/core/device_pool.py
T

136 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""设备池:SQLite devices 表 = 设备清单,本地 adb = 在线状态(STF 替代数据源)。
设计:
- list_configured() — devices 表里 enabled 的设备(清单,管理页维护)
- list_online() — 本机 `adb devices` 里 state=device 的设备(实时;
池内有 USB 设备时合并 220 远程 adb server 状态)
- list_ready() — configured ∩ online(任务调度用)
- CRUD — add/update/remove/set_enabled(设备池管理页用)
红线:全模块不 connect / 不 kill-server / 不 disconnect,遵守既有技术约束。
后台线程(task_manager 等)调用时由本模块自行推 app context,调用方无需关心。
"""
import time
from config import USB_ADB_HOST, USB_ADB_PORT
from core.adb_helper import _adb, _adb_remote
from core.logger import get_logger
from core.models import db, Device
_log = get_logger("core.device_pool")
_app = None
def init_app(app):
"""web_server 启动时调用:绑定 Flask app(供后台线程推 db context)。"""
global _app
_app = app
def _ctx():
"""后台线程访问 db 需自行推 app context(与 task_manager._db 同思路)。"""
if _app is None:
raise RuntimeError("device_pool 未关联 Flask app(web_server 启动时调用 init_app)")
return _app.app_context()
# ================== 清单 ==================
def list_configured(enabled_only=True):
"""devices 表里的设备清单(serial 列表)。"""
with _ctx():
q = Device.query
if enabled_only:
q = q.filter_by(enabled=True)
return [d.serial for d in q.order_by(Device.serial).all()]
def list_devices():
"""全量设备行(设备池管理页用)。"""
with _ctx():
return [d.to_dict() for d in Device.query.order_by(Device.serial).all()]
# ================== 在线状态 ==================
def list_online():
"""本机 adb 中 state=device 的设备 + 池内 USB 设备(经 220 远程 adb server)。
池内无 USB 设备(serial 无冒号)时不查远程 server,零额外开销。
"""
out = _adb("devices") or ""
serials = []
for line in out.splitlines()[1:]:
parts = line.split()
if len(parts) >= 2 and parts[0] and parts[1] == "device":
serials.append(parts[0])
# 池内有 USB 设备时,补查远程 adb server(220,host 网络 5037 全接口监听)
try:
usb = [s for s in list_configured() if ":" not in s]
except Exception:
usb = []
if usb:
try:
out = _adb_remote(USB_ADB_HOST, USB_ADB_PORT, "devices") or ""
for line in out.splitlines()[1:]:
parts = line.split()
if len(parts) >= 2 and parts[0] and parts[1] == "device":
if parts[0] not in serials:
serials.append(parts[0])
except Exception:
pass
return serials
def is_online(serial):
"""设备当前是否在线(本机 adb 可达且状态正常)。"""
return serial in list_online()
def list_ready():
"""可调度设备:清单 ∩ 在线(取代 STF list_free_devices)。"""
online = set(list_online())
return [s for s in list_configured() if s in online]
# ================== 管理(CRUD) ==================
def add_device(serial, name="", note="", enabled=True):
"""添加/更新设备(upsert)。返回 True 新增 / False 已存在并更新。"""
serial = (serial or "").strip()
if not serial:
return False
with _ctx():
d = Device.query.get(serial)
if d:
d.name, d.note, d.enabled = name or "", note or "", enabled
db.session.commit()
return False
db.session.add(Device(serial=serial, name=name or "", note=note or "",
enabled=enabled,
created_at=time.strftime("%Y-%m-%d %H:%M")))
db.session.commit()
_log.info(f"设备池新增设备: {serial}")
return True
def remove_device(serial):
"""删除设备。返回是否删除成功。"""
with _ctx():
d = Device.query.get(serial)
if not d:
return False
db.session.delete(d)
db.session.commit()
_log.info(f"设备池删除设备: {serial}")
return True
def set_enabled(serial, enabled):
"""启用/停用设备(停用后不参与调度)。返回是否成功。"""
with _ctx():
d = Device.query.get(serial)
if not d:
return False
d.enabled = enabled
db.session.commit()
return True