# -*- coding: utf-8 -*- """诊断:为什么被控端登记不到本地中转。 只读诊断,不动任何仓库文件。 """ from __future__ import annotations import json import os import shutil import socket import subprocess import sys import tempfile import time import urllib.request from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "windows")) def free_port() -> int: with socket.socket() as s: s.bind(("127.0.0.1", 0)) return s.getsockname()[1] def get(url, timeout=5): try: with urllib.request.urlopen(url, timeout=timeout) as r: return r.status, r.read().decode("utf-8", "replace") except Exception as exc: # noqa: BLE001 return 0, str(exc) def main() -> int: work = Path(tempfile.mkdtemp(prefix="diag_relay_")) relay_port = free_port() agent_port = free_port() relay_url = "http://127.0.0.1:%d" % relay_port print(" 中转 %s 被控端端口 %d" % (relay_url, agent_port)) from lanremote.config import Store # ⚠ 关键:run_agent.py 读的是 data_dir(),不是我们随手建的目录。 # 第一次诊断就栽在这儿 —— 配置写进了临时目录,agent 却读 # windows/data,于是"怎么都不登记"。 # data_dir() 优先认 YKXMZ_DATA,所以用环境变量把它指到临时目录, # 这样两边看到的是同一份配置。 real_data = work / "agentdata" real_data.mkdir(parents=True, exist_ok=True) os.environ["YKXMZ_DATA"] = str(real_data) store = Store(real_data) store.set_pairing_code("135790") store.set("setup_done", True) store.set("allow_new_pairing", True) store.set("close_pair_after_first", False) store.set("server_name", "诊断电脑") store.set("relay_url", relay_url) store.set("port", agent_port) print(" store 里的 relay_url = %r" % store.get("relay_url")) relay_data = work / "relaydata" relay_data.mkdir(parents=True, exist_ok=True) env = dict(os.environ) env.update({ "RELAY_PORT": str(relay_port), "RELAY_BIND": "127.0.0.1", "RELAY_DATA": str(relay_data), "RELAY_POLL": "4", "PYTHONIOENCODING": "utf-8", "PYTHONUNBUFFERED": "1", }) relay = subprocess.Popen( [sys.executable, "-u", str(ROOT / "relay" / "relay.py")], env=env, stdout=open(work / "relay.log", "wb"), stderr=subprocess.STDOUT) for _ in range(40): time.sleep(0.5) if get(relay_url + "/v1/health")[0] == 200: break print(" 中转: %s" % ("起来了" if get(relay_url + "/v1/health")[0] == 200 else "没起来")) agent_log = open(work / "agent_stdout.log", "wb") agent_env = dict(os.environ) agent_env["YKXMZ_DATA"] = str(real_data) agent_env["PYTHONIOENCODING"] = "utf-8" agent = subprocess.Popen( [sys.executable, "-u", str(ROOT / "windows" / "run_agent.py"), "--silent", "--port", str(agent_port)], cwd=str(ROOT / "windows"), env=agent_env, stdout=agent_log, stderr=subprocess.STDOUT) deadline = time.time() + 45 online = None while time.time() < deadline: time.sleep(1.5) st, body = get(relay_url + "/v1/health") if st == 200: try: snap = json.loads(body) except Exception: # noqa: BLE001 continue devs = snap.get("devices", []) if devs: online = devs break if agent.poll() is not None: print(" ! 被控端进程已退出,退出码 %s" % agent.returncode) break print() print(" ==== 中转看到的设备 ====") if online: for d in online: print(" %s" % json.dumps(d, ensure_ascii=False)[:200]) else: print(" (空 —— 没登记上)") print() print(" ==== 被控端 stdout(最后 800 字)====") agent_log.flush() try: print((work / "agent_stdout.log").read_text( encoding="utf-8", errors="replace")[-800:]) except Exception as exc: # noqa: BLE001 print(" 读不到: %s" % exc) print() print(" ==== 被控端 silent.log(HeadlessUI 写这里)====") try: txt = (real_data / "silent.log").read_text(encoding="utf-8", errors="replace") print(txt[-2000:]) except Exception as exc: # noqa: BLE001 print(" 读不到: %s" % exc) print() print(" ==== 中转日志里的注册相关 ====") try: txt = (work / "relay.log").read_text(encoding="utf-8", errors="replace") for line in txt.splitlines(): if any(k in line for k in ("register", "注册", "被控端", "poll", "上线", "Traceback", "Error")): print(" " + line[:150]) except Exception as exc: # noqa: BLE001 print(" 读不到: %s" % exc) for proc in (agent, relay): try: proc.terminate() proc.wait(timeout=5) except Exception: # noqa: BLE001 try: proc.kill() except Exception: # noqa: BLE001 pass time.sleep(0.3) shutil.rmtree(work, ignore_errors=True) return 0 if __name__ == "__main__": raise SystemExit(main())