ykxmz 1.5.0:修复手表端 TLS 证书校验 + MTU 修复网络稳定性

被控端
- 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%)
- 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败)
- 每分钟回头找局域网,自动切回快 400 倍的路径
- 画面心跳帧:静止时省流量,客户端仍知道流是活的
- 锁屏时给出可操作的提示

手表端
- 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException
- 连接错误翻译成人话(证书/时间/解析/超时分别提示)
- 经中转连上后用服务器报的地址刷新已配对记录
- 新增局域网连接页面、服务器延迟检测

服务器端
- 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502)
- 网络调优脚本 net-tune.sh(开机自动应用)
- 管理页:批量删除、网络体检、下载区
- 隧道改 HTTP/2 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
This commit is contained in:
xmz7891
2026-10-06 19:01:05 +08:00
commit b62ac865ea
3195 changed files with 203292 additions and 0 deletions
+220
View File
@@ -0,0 +1,220 @@
# -*- coding: utf-8 -*-
"""验证「配对码被占用」的处理。
用户的要求:
一个设备设了 789113,另一台也想设 789113 -> 不行,
要弹通知说「该配对码已被使用,请换一个配对码」。
分两层验证:
1. 中转服务器层:第二台设备报同一个码 -> 必须被拒,且带 codeTaken
2. 被控端层:RelayLink 必须抛 RelayCodeTaken,并且**调用 on_alert 弹通知**
而且不能反复重试刷屏(换了码才继续)
"""
from __future__ import annotations
import json
import os
import shutil
import subprocess
import sys
import tempfile
import time
import urllib.error
import urllib.request
from pathlib import Path
_UA = {"User-Agent": "LanRemote/1.4.0"}
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "windows"))
RELAY_PORT = 8093
RELAY_URL = f"http://127.0.0.1:{RELAY_PORT}"
CODE = "789113"
OTHER_CODE = "654321"
passed = 0
failed = 0
def check(name, ok, detail=""):
global passed, failed
if ok:
passed += 1
print(" [PASS] " + name)
else:
failed += 1
print(" [FAIL] " + name + " " + str(detail))
def post(path, payload):
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
req = urllib.request.Request(RELAY_URL + path, data=body,
method="POST", headers=_UA)
try:
with urllib.request.urlopen(req, timeout=15) as resp:
return resp.status, json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as exc:
return exc.code, json.loads(exc.read().decode("utf-8", "replace"))
def main() -> int:
work = Path(tempfile.mkdtemp(prefix="code_conflict_"))
relay = None
try:
# ---------- 起本地中转 ----------
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": "6",
"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)
up = False
for _ in range(40):
time.sleep(0.5)
try:
with urllib.request.urlopen(
urllib.request.Request(RELAY_URL + "/v1/health",
headers=_UA),
timeout=2) as resp:
if resp.status == 200:
up = True
break
except Exception: # noqa: BLE001
continue
check("本地中转起来了", up)
if not up:
print((work / "relay.log").read_text(encoding="utf-8",
errors="replace")[-600:])
return 1
print()
print("一、中转服务器层")
status, first = post("/v1/agent/register", {
"deviceId": "pc-A", "code": CODE, "name": "电脑A",
"version": "1.4.0"})
check("第一台设备登记成功", first.get("ok") is True, first)
check("第一台拿到了令牌", bool(first.get("token")))
check("第一台的码就是它设的", first.get("code") == CODE,
first.get("code"))
status, second = post("/v1/agent/register", {
"deviceId": "pc-B", "code": CODE, "name": "电脑B",
"version": "1.4.0"})
check("第二台用同一个码被拒", second.get("ok") is False, second)
check("返回了 codeTaken 标记", second.get("codeTaken") is True, second)
check("错误说明了要换码",
"已被使用" in str(second.get("error"))
and "换一个" in str(second.get("error")),
second.get("error"))
check("第二台没拿到令牌", not second.get("token"), second)
status, third = post("/v1/agent/register", {
"deviceId": "pc-B", "code": OTHER_CODE, "name": "电脑B",
"version": "1.4.0"})
check("第二台换个码就能登记", third.get("ok") is True, third)
check("它拿到的是新码", third.get("code") == OTHER_CODE,
third.get("code"))
# 单设备单码仍然有效:A 报新码应被改回
status, again = post("/v1/agent/register", {
"deviceId": "pc-A", "code": "111222", "name": "电脑A",
"version": "1.4.0"})
check("A 报新码被改回原来的(单设备单码)",
again.get("code") == CODE, again.get("code"))
print()
print("二、被控端层(RelayLink 要弹通知)")
from lanremote.config import Store
from lanremote.relay import RelayCodeTaken, RelayLink
alerts = []
def on_alert(title, text):
alerts.append((title, text))
# A 的 store
store_a = Store(work / "store_a")
store_a.set_pairing_code(CODE)
store_a.set("server_name", "电脑A")
store_a.set("relay_device_id", "pc-A")
link_a = RelayLink(store_a, log=lambda _m: None, on_alert=on_alert)
link_a.start(RELAY_URL)
time.sleep(4)
check("A 连上并登记", link_a.status().get("online") is True
or link_a.token != "", link_a.status())
check("A 没有冲突", not link_a.status().get("codeConflict"),
link_a.status().get("codeConflict"))
# B 故意用同一个码
store_b = Store(work / "store_b")
store_b.set_pairing_code(CODE)
store_b.set("server_name", "电脑B")
store_b.set("relay_device_id", "pc-B")
alerts.clear()
link_b = RelayLink(store_b, log=lambda _m: None, on_alert=on_alert)
link_b.start(RELAY_URL)
time.sleep(6)
check("B 弹了通知", len(alerts) >= 1, f"{len(alerts)} 次: {alerts[:2]}")
if alerts:
title, text = alerts[0]
check("通知标题说了配对码", "配对码" in title, title)
check("通知正文说要换码",
"已被使用" in text and "换" in text, text)
check("B 停在冲突状态(没有反复重试刷屏)",
bool(link_b.status().get("codeConflict")),
link_b.status().get("codeConflict"))
check("B 的冲突信息里带着要换码的提示",
"已被使用" in str(link_b.status().get("codeConflict")),
link_b.status().get("codeConflict"))
count_before = len(alerts)
time.sleep(6)
check("同一个码不会反复弹通知",
len(alerts) == count_before,
f"又弹了 {len(alerts) - count_before} 次")
print()
print("三、用户换码之后要能自己恢复")
store_b.set_pairing_code(OTHER_CODE)
time.sleep(8)
check("换了码之后 B 连上了",
link_b.status().get("online") is True or link_b.token != "",
link_b.status())
check("冲突标记被清掉",
not link_b.status().get("codeConflict"),
link_b.status().get("codeConflict"))
for link in (link_a, link_b):
try:
link.stop()
except Exception: # noqa: BLE001
pass
print()
print("=" * 62)
print(f"通过 {passed} 项,失败 {failed} 项")
return 0 if failed == 0 else 1
finally:
if relay is not None:
try:
relay.terminate()
relay.wait(timeout=8)
except Exception: # noqa: BLE001
try:
relay.kill()
except Exception: # noqa: BLE001
pass
time.sleep(0.5)
shutil.rmtree(work, ignore_errors=True)
if __name__ == "__main__":
raise SystemExit(main())