# -*- coding: utf-8 -*- r'''443 开好之后:恢复监测单元 + 全链路验证。 == 为什么现在才恢复监测 == 之前 443 没开,用户层(https://yk.xxmxxs.top)一直不通, 监测会把 fails 一直累加、每 10 分钟白生成一份抢救报告。 所以先停了,等端口开好。 现在 443 通了、用户层 200,可以恢复。 == 顺便验证什么 == 1. 监测单元跑起来后 self-check 是 200(不再误报) 2. 下载走 Cloudflare 有没有缓存(第二次应该 HIT) 3. 长轮询没被 Cloudflare 或 nginx 截断 4. 证书链没问题(真实浏览器视角) ''' from __future__ import annotations import sys import time import urllib.request from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) from lssh import run # noqa: E402 RELAY_DIR = "/opt/ykxmz-relay" DOMAIN = "yk.xxmxxs.top" def fetch(url: str, headers: dict = None) -> tuple: """返回 (状态码, 头字典, 字节数, 耗时秒)。 ⚠ 必须带 User-Agent —— Cloudflare 把 **Python-urllib/3.11** 判为可疑客户端,直接返回 403 + error code 1010。 这个坑仓库里早记过(windows/lanremote/relay.py 文件头): "实测 LanRemote/1.4.0 能过"。这里就带上它。 (curl 的默认 UA 不会被拦,所以服务器上的监测单元不受影响。) """ t0 = time.time() h = {"User-Agent": "LanRemote/1.4.0"} if headers: h.update(headers) req = urllib.request.Request(url, headers=h) try: with urllib.request.urlopen(req, timeout=180) as r: body = r.read() return (r.status, dict(r.headers), len(body), time.time() - t0) except urllib.error.HTTPError as exc: return (exc.code, dict(exc.headers or {}), 0, time.time() - t0) except Exception as exc: # noqa: BLE001 return ("失败: %s" % type(exc).__name__, {}, 0, time.time() - t0) def main() -> int: print("=" * 62) print(" 恢复监测 + 全链路验证") print("=" * 62) print() print(" ── 1. 恢复监测单元 ──") run("sudo systemctl start ykxmz-monitor.timer", timeout=120, quiet=True) time.sleep(3) out = run("systemctl is-active ykxmz-monitor.timer", timeout=60, quiet=True) print(" monitor.timer = " + out[1].strip()) print() print(" ── 2. 手动跑一次监测(看还误报不误报)──") run("bash %s/monitor.sh" % RELAY_DIR, timeout=180, quiet=True) out = run("cat %s/monitor_state.txt" % RELAY_DIR, timeout=60, quiet=True) for ln in out[1].strip().splitlines(): print(" " + ln) print() print(" ── 3. 下载速度(经 Cloudflare,第一次应 MISS)──") url = "https://%s/download/ykxmz-setup-2.1.3.exe" % DOMAIN code, hdr, size, dur = fetch(url) print(" 第 1 次: HTTP %s %.2f MB %.1f 秒 %.0f KB/s" % (code, size / 1048576, dur, size / 1024 / max(dur, 0.001))) print(" CF-Cache-Status = %s" % hdr.get("CF-Cache-Status", "(无)")) time.sleep(2) code, hdr, size, dur = fetch(url) print(" 第 2 次: HTTP %s %.2f MB %.1f 秒 %.0f KB/s" % (code, size / 1048576, dur, size / 1024 / max(dur, 0.001))) print(" CF-Cache-Status = %s <- HIT 就说明 CDN 生效了" % hdr.get("CF-Cache-Status", "(无)")) print() print(" ── 4. APK 下载 ──") url = "https://%s/download/ykxmz-watch-2.1.3.apk" % DOMAIN code, hdr, size, dur = fetch(url) print(" HTTP %s %.0f KB %.2f 秒 %.0f KB/s CF=%s" % (code, size / 1024, dur, size / 1024 / max(dur, 0.001), hdr.get("CF-Cache-Status", "(无)"))) print() print(" ── 5. 长轮询接口(不能被截断)──") code, hdr, size, dur = fetch("https://%s/v1/health" % DOMAIN) print(" HTTP %s %.2f 秒 Cache-Control=%s" % (code, dur, hdr.get("Cache-Control", "(无)"))) print() print(" ── 6. 服务器端状态 ──") out = run("systemctl is-active ykxmz-relay nginx ykxmz-monitor.timer " "certbot.timer", timeout=60, quiet=True) names = ["ykxmz-relay", "nginx", "monitor.timer", "certbot.timer"] for i, ln in enumerate(out[1].strip().splitlines()): if i < len(names): print(" %-20s %s" % (names[i], ln)) have = run("ls -1 %s/rescue_reports 2>/dev/null | wc -l" % RELAY_DIR, timeout=60, quiet=True) print(" %-20s %s 份(应该是 0 —— 之前清掉了)" % ("抢救报告", have[1].strip())) return 0 if __name__ == "__main__": sys.exit(main())