"""清理 STF 上残留的设备占用(强杀进程导致没正常释放时用)。 运行:python scripts/cleanup.py """ import os import sys # 让脚本既能直接运行(python scripts/cleanup.py)又能作为模块运行。 # scripts/ 的上一级是项目根目录(core 包的父目录),需加入 sys.path。 _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if _PROJECT_ROOT not in sys.path: sys.path.insert(0, _PROJECT_ROOT) import requests from config import STF_URL, STF_TOKEN headers = {"Authorization": f"Bearer {STF_TOKEN}"} # /user/devices 返回当前用户正在占用的设备 resp = requests.get(f"{STF_URL}/api/v1/user/devices", headers=headers) resp.raise_for_status() data = resp.json() mine = data.get("devices", []) print(f"当前账户占用的设备数: {len(mine)}") for d in mine: print(f" - {d.get('serial')} using={d.get('using')}") # 全部释放 for d in mine: serial = d["serial"] try: requests.post( f"{STF_URL}/api/v1/user/devices/{serial}/remoteDisconnect", headers=headers, ) except Exception: pass r = requests.delete(f"{STF_URL}/api/v1/user/devices/{serial}", headers=headers) print(f"释放 {serial}: HTTP {r.status_code}") # 再看一次总设备池 resp = requests.get(f"{STF_URL}/api/v1/devices", headers=headers) resp.raise_for_status() free = [d for d in resp.json().get("devices", []) if d.get("present") and d.get("ready") and not d.get("using") and d.get("owner") is None] print(f"\n清理后空闲设备数: {len(free)}") for d in free: print(f" - {d.get('serial')}")