diff --git a/Module/DeviceInfo.py b/Module/DeviceInfo.py index bdc9906..7a8ba1f 100644 --- a/Module/DeviceInfo.py +++ b/Module/DeviceInfo.py @@ -10,7 +10,7 @@ import threading import subprocess import socket from pathlib import Path -from typing import Dict, Optional +from typing import Dict, Optional, List, Any import platform import psutil import http.client @@ -116,45 +116,62 @@ class DeviceInfo: self._iproxy_path = self._find_iproxy() LogManager.info("DeviceInfo 初始化完成", udid="system") print("[Init] DeviceInfo 初始化完成") - # 延迟执行删除设备方法 - threading.Thread(target=self.readdDevice).start() - # 清空所有设备 - def readdDevice(self): - print("开始自动删除设备") - second = 0 + threading.Thread(target=self.check_iproxy_ports).start() + + + # =============== 核心:端口连通性检测 ================= + def _is_local_port_open(self, port: int,udid:str, timeout: float = 5) -> bool: + print("开始监听剪口") + """ + Windows: 尝试连接 127.0.0.1:port,能连上即认为端口可用(iproxy 正在监听/转发)。 + 不抛异常,返回 True/False。 + """ + if not isinstance(port, int) or port <= 0 or port > 65535: + LogManager.error("端口不可用",udid=udid) + return False + + try: + print("尝试监听") + # create_connection 会在连接成功时立即返回 socket + with socket.create_connection(("127.0.0.1", int(port)), timeout=timeout): + print("端口正常") + return True + except OSError: + LogManager.error("端口不可用",udid=udid) + return False + + # =============== 一轮检查:发现不通就移除 ================= + def check_iproxy_ports(self, connect_timeout: float = 3) -> None: + time.sleep(60) + print("开始监听投屏端口") while True: - second += 1 - if second == 3555: - with self._lock: - # 先拍一张快照,避免“边遍历边修改” - udids = list(self._models.keys()) - for udid in udids: - print(f"[Remove] 正在移除设备 {udid}") - # 以 udid 为主键,逐个 pop - model = self._models.pop(udid, None) - proc = self._iproxy.pop(udid, None) - self._port_by_udid.pop(udid, None) - self._first_seen.pop(udid, None) - self._last_seen.pop(udid, None) - # 安全结束进程 - self._kill(proc) - # 组一个“下线通知”的占位模型 - if model is None: - model = DeviceModel( - deviceId=udid, screenPort=-1, width=0, height=0, scale=0.0, type=2 - ) - # 标记为“已移除/离线” - model.type = 2 - model.ready = False - model.screenPort = -1 - # 通知上层 - self._manager_send(model) - print(f"[Remove] 已移除设备 {udid}") - second = 0 - print(f"[Remove] 设备移除完成,总数: {len(udids)}") - time.sleep(1) + snapshot = list(self._models.items()) # [(deviceId, DeviceModel), ...] + for device_id, model in snapshot: + try: + # 只处理在线且端口合法的设备 + if model.type != 1: + continue + port = int(model.screenPort) + if port <= 0 or port > 65535: + continue + ok = self._is_local_port_open(port, timeout=connect_timeout, udid=device_id) + if not ok: + print(f"[iproxy-check] 端口不可连,移除设备 deviceId={device_id} port={port}") + try: + self._remove_device(device_id) # 这里面可安全地改 self._models + except Exception as e: + print(f"[iproxy-check] _remove_device 异常 deviceId={device_id}: {e}") + else: + # 心跳日志按需开启,避免刷屏 + # print(f"[iproxy-check] OK deviceId={device_id} port={port}") + pass + + except Exception as e: + print(f"[iproxy-check] 单设备检查异常: {e}") + # 8秒间隔 + time.sleep(10) def listen(self): LogManager.method_info("进入主循环", "listen", udid="system") @@ -242,10 +259,7 @@ class DeviceInfo: if not self._wda_http_status_ok_once(udid): if major > 17: print("进入iOS17设备的分支") - print(f"[WDA] iOS>17 调用 IOSActivator (port={wdaScreenPort})") - print("准备启动隧道") out = IOSActivator().activate(udid) - print("------------------",out) print("wda启动完成") else: print(f"[WDA] iOS<=17 启动 WDA app_start (port={wdaScreenPort})") @@ -293,8 +307,13 @@ class DeviceInfo: print(f"[Add] 设备添加成功 {udid}, port={port}, {w}x{h}@{s}") def _remove_device(self, udid: str): - method = "_remove_device" + """ + 移除设备及其转发,通知上层。 + 幂等:重复调用不会出错。 + """ print(f"[Remove] 正在移除设备 {udid}") + + # --- 1. 锁内执行所有轻量字典操作 --- with self._lock: model = self._models.pop(udid, None) proc = self._iproxy.pop(udid, None) @@ -302,14 +321,30 @@ class DeviceInfo: self._first_seen.pop(udid, None) self._last_seen.pop(udid, None) - self._kill(proc) + # --- 2. 锁外执行重操作 --- + # 杀进程 + try: + self._kill(proc) + except Exception as e: + print(f"[Remove] 杀进程异常 {udid}: {e}") + # 准备下线模型(model 可能为 None) if model is None: - model = DeviceModel(deviceId=udid, screenPort=-1, width=0, height=0, scale=0.0, type=2) + model = DeviceModel( + deviceId=udid, screenPort=-1, width=0, height=0, scale=0.0, type=2 + ) + + # 标记状态为离线 model.type = 2 model.ready = False model.screenPort = -1 - self._manager_send(model) + + # 通知上层 + try: + self._manager_send(model) + except Exception as e: + print(f"[Remove] 通知上层异常 {udid}: {e}") + print(f"[Remove] 设备移除完成 {udid}") def _trusted(self, udid: str) -> bool: diff --git a/Module/Main.py b/Module/Main.py index 92de576..11b32b7 100644 --- a/Module/Main.py +++ b/Module/Main.py @@ -50,7 +50,7 @@ if __name__ == "__main__": # 清空日志 LogManager.clearLogs() - main(sys.argv) + # main(sys.argv) # 添加iOS开发包到电脑上 deployer = DevDiskImageDeployer(verbose=True) diff --git a/Module/__pycache__/DeviceInfo.cpython-312.pyc b/Module/__pycache__/DeviceInfo.cpython-312.pyc index 7d2a348..6bf4488 100644 Binary files a/Module/__pycache__/DeviceInfo.cpython-312.pyc and b/Module/__pycache__/DeviceInfo.cpython-312.pyc differ diff --git a/Module/__pycache__/Main.cpython-312.pyc b/Module/__pycache__/Main.cpython-312.pyc index 497bbf9..c670ff1 100644 Binary files a/Module/__pycache__/Main.cpython-312.pyc and b/Module/__pycache__/Main.cpython-312.pyc differ diff --git a/Utils/LogManager.py b/Utils/LogManager.py index 3981133..0c8bb94 100644 --- a/Utils/LogManager.py +++ b/Utils/LogManager.py @@ -26,7 +26,7 @@ def _force_utf8_everywhere(): except Exception: pass -_force_utf8_everywhere() +# _force_utf8_everywhere() class LogManager: """ diff --git a/Utils/__pycache__/LogManager.cpython-312.pyc b/Utils/__pycache__/LogManager.cpython-312.pyc index 4b44dc5..46aff74 100644 Binary files a/Utils/__pycache__/LogManager.cpython-312.pyc and b/Utils/__pycache__/LogManager.cpython-312.pyc differ diff --git a/script/__pycache__/ScriptManager.cpython-312.pyc b/script/__pycache__/ScriptManager.cpython-312.pyc index 5fe13b3..402a034 100644 Binary files a/script/__pycache__/ScriptManager.cpython-312.pyc and b/script/__pycache__/ScriptManager.cpython-312.pyc differ