From edfd529c595028c1081f1848b3cb73bedfc8616f Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Sat, 5 Sep 2026 09:58:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=AD=A3=E5=BC=8F=E6=B1=A0=E6=96=AD?= =?UTF-8?q?=E8=81=94=E8=AE=BE=E5=A4=87=E8=87=AA=E5=8A=A8=E9=87=8D=E8=BF=9E?= =?UTF-8?q?=E2=80=94=E2=80=94=E2=91=A0=E6=89=AB=E6=8F=8F=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E6=AF=8F=E8=BD=AE=E9=A1=BA=E5=B8=A6=E5=AF=B9=E6=96=AD=E8=81=94?= =?UTF-8?q?=E7=9A=84=E7=BD=91=E7=BB=9C=E8=AE=BE=E5=A4=87=20adb=5Fconnect?= =?UTF-8?q?=5Flight=EF=BC=88=E5=B9=82=E7=AD=89=EF=BC=8C=E8=BF=9E=E4=B8=8A?= =?UTF-8?q?=E5=8D=B3=E6=81=A2=E5=A4=8D=EF=BC=8C=E6=97=A0=E9=9C=80=E4=BA=BA?= =?UTF-8?q?=E5=B7=A5=EF=BC=9B=E6=AD=A4=E5=89=8D=E5=8F=AA=E6=9C=89=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E6=97=B6=E9=A2=84=E8=BF=9E=E6=8E=A5=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=EF=BC=8C=E6=96=AD=E8=81=94=E5=90=8E=E4=B8=8D=E4=BC=9A=E8=87=AA?= =?UTF-8?q?=E5=B7=B1=E5=9B=9E=E6=9D=A5=EF=BC=89=EF=BC=9B=E2=91=A1=E6=96=AD?= =?UTF-8?q?=E8=81=94=E8=AE=BE=E5=A4=87=E4=B8=8D=E5=88=A0=E4=B8=8D=E8=BF=9B?= =?UTF-8?q?=E5=BE=85=E8=BF=9E=E6=8E=A5=E6=B1=A0=EF=BC=88pending=20?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=3D=E6=9C=AA=E6=8E=88=E6=9D=83=E6=96=B0?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=EF=BC=89=EF=BC=8CGET=20discovery=20=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=20pool=5Foffline=EF=BC=88serial/=E5=9E=8B=E5=8F=B7/?= =?UTF-8?q?=E5=A4=87=E6=B3=A8=EF=BC=89=EF=BC=9B=E2=91=A2POST=20/api/device?= =?UTF-8?q?s/discovery/reconnect=20=E6=89=8B=E5=8A=A8=E7=AB=8B=E5=8D=B3?= =?UTF-8?q?=E9=87=8D=E8=BF=9E=EF=BC=9B=E2=91=A3=E5=8F=91=E7=8E=B0=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E5=8A=A0=E3=80=8C=E8=AE=BE=E5=A4=87=E6=B1=A0=E6=96=AD?= =?UTF-8?q?=E8=81=94=E8=AE=BE=E5=A4=87=E3=80=8D=E5=8C=BA=E5=9D=97=EF=BC=88?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=87=8D=E8=BF=9E=E4=B8=AD=20+=20=E7=AB=8B?= =?UTF-8?q?=E5=8D=B3=E9=87=8D=E8=BF=9E=E6=8C=89=E9=92=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/device_discovery.py | 43 ++++++++++++++++++++++++++++++++++-- static/admin/tools.js | 23 +++++++++++++++++++ templates/admin/monitor.html | 9 ++++++++ web/devices_api.py | 36 +++++++++++++++++++++++++++++- 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/core/device_discovery.py b/core/device_discovery.py index 410dfe9..60cde19 100644 --- a/core/device_discovery.py +++ b/core/device_discovery.py @@ -22,7 +22,7 @@ from config import (USB_ADB_HOST, DISCOVERY_PORT, DISCOVERY_SUBNETS, DISCOVERY_INTERVAL) from core.adb_helper import _adb, adb_connect_light from core.logger import get_logger -from core.models import db, PendingDevice +from core.models import db, Device, PendingDevice _log = get_logger("core.disc") @@ -220,8 +220,14 @@ def scan_once(manual=False): first_seen=now, last_seen=now)) added += 1 db.session.commit() + # 6. 正式池断联设备自动重连:adb connect 会因 WiFi 波动/设备重启/ + # adb 服务重启而断开——扫描线程每轮顺带重试(幂等轻量,内部 + # 全局锁串行),连上即恢复在线,无需人工干预。pending 池是给 + # 「未授权新设备」的,正式池设备断联不进 pending,而是自动重连。 + back = _reconnect_offline(configured) _log.info(f"发现: 探测开放 {len(open_ips)} 台,可连 {len(verified)} 台," - f"新增待连接 {added} 台") + f"新增待连接 {added} 台" + + (f",自动重连恢复 {len(back)} 台 {back}" if back else "")) _last_scan = (now, len(open_ips), len(verified), added) _last_error = "" return True, {"found": len(open_ips), "verified": len(verified), "new": added} @@ -240,6 +246,39 @@ def device_pool_list_configured(): return device_pool.list_configured() +# ================== 正式池断联设备:自动重连 ================== +def _reconnect_offline(configured): + """对正式池中断联的网络设备逐个 adb 重连,返回恢复的 serial 列表。 + + 只重连网络设备(IP:5555;USB 设备插着就在,无需 connect)。 + 幂等轻量:内部 adb 全局锁串行,失败静默(下轮扫描再试)。 + """ + online_now = _parse_adb_devices(_adb("devices")) + targets = [s for s in (configured or []) + if ":" in s and s not in online_now] + if not targets: + return [] + for serial in targets: + adb_connect_light(serial) + online_after = _parse_adb_devices(_adb("devices")) + return [s for s in targets if s in online_after] + + +def list_pool_offline(): + """正式设备池中断联的设备(serial + 型号 + 备注名),面板展示用。 + + 断联设备仍是正式池成员(不删除、不进 pending)——pending 是给未授权 + 新设备的;它们由扫描线程每轮自动重连,也可前端手动立即重连。 + """ + online = _parse_adb_devices(_adb("devices")) + with _ctx(): + rows = [d.to_dict() for d in Device.query.filter_by(enabled=True) + .order_by(Device.serial).all()] + return [{"serial": r["serial"], "model": r.get("model") or "", + "name": r.get("name") or ""} + for r in rows if r["serial"] not in online] + + # ================== 定时扫描线程 ================== def _discovery_loop(): """定时扫描 daemon 线程。每轮重读配置(开关/周期即时生效)。 diff --git a/static/admin/tools.js b/static/admin/tools.js index d81aaf2..1d1a714 100644 --- a/static/admin/tools.js +++ b/static/admin/tools.js @@ -81,6 +81,29 @@ function loadDiscovery(){ +''; }).join(''); } + // 正式池断联设备:仍在设备池(不删除),扫描线程自动重连,可手动立即重连 + const offTb=document.getElementById('tb-pool-offline'); + if(offTb){ + const off=(r.pool_offline||[]); + if(!off.length){ + offTb.innerHTML='
| serial | 型号 | 备注 | 状态 | 操作 |
|---|---|---|---|---|
| 全部在线 | ||||