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
+272
View File
@@ -0,0 +1,272 @@
# -*- coding: utf-8 -*-
"""Bug 1:配对码被占用时,要求在**装防火墙之前**就发现。
用户原话:
"如果配对码被占用了,你输入进去以后你不应该是先检查没有占用,
然后有占用去改,然后再去放行防火墙吗?你现在如果占用的话,你改不了"
现在的流程(错):
设置窗口 -> 存码 -> 开自启 -> 修防火墙 -> 静默运行
^ ^
这里没检查 等转静默才发现码被占,
但防火墙已经改了,用户也没法改码
要改成:
设置窗口 -> 检查码 -> 可用就继续;被占就弹框让他换,重新开设置窗口
-> 通过之后才 开自启 / 修防火墙 / 静默
关键点:**检查不能真的去注册那个码** —— 注册就等于占用了它。
所以给中转加一个只读接口:
GET /v1/code/check?code=123456
-> {"ok": true, "taken": false}
-> {"ok": true, "taken": true, "deviceName": "某台电脑"}
"""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
RELAY_SERVER = ROOT / "relay" / "relay.py"
RELAY_CLIENT = ROOT / "windows" / "lanremote" / "relay.py"
RUN = ROOT / "windows" / "run_agent.py"
# ================= 1. 中转:只读查询接口 =================
SRV_ANCHOR = ''' if path in ("/v1/health", "/health"):'''
SRV_NEW = ''' # 只读查询:这个配对码有没有被别的电脑占?
# 安装时要"先检查再决定要不要改防火墙",而检查不能真去注册
# (一注册就等于自己占了它)。所以单独开一个只读接口。
if path in ("/v1/code/check", "/v1/check"):
query = urllib.parse.urlparse(self.path).query
wanted = (urllib.parse.parse_qs(query).get("code") or [""])[0]
wanted = wanted.strip()
if not CODE_RE.match(wanted):
self._json(400, {"ok": False, "error": "配对码要是 6 位数字"})
return
with RELAY.lock:
owner = RELAY.codes.get(wanted)
device = RELAY.devices.get(owner) if owner else None
self._json(200, {
"ok": True,
"code": wanted,
"taken": bool(owner),
"deviceName": device.name if device else "",
"online": bool(device and device.online()),
})
return
if path in ("/v1/health", "/health"):'''
# ================= 2. 被控端:调用这个接口 =================
CLIENT_ANCHOR = ''' def _ensure_device_id(self) -> str:'''
CLIENT_NEW = ''' def _check_code(self, code: str) -> dict:
"""问中转:这个码被占了吗?(只读,不会占用它)
返回 {"ok": True, "taken": bool, "deviceName": str}
连不上中转就返回 {"ok": False},调用方自己决定怎么办。
"""
bases = list(self.candidates) or ([self.url] if self.url else [])
if not bases:
return {"ok": False, "error": "还没配置中转地址"}
quoted = urllib.parse.quote(code)
for base in bases:
try:
request = urllib.request.Request(
f"{base}/v1/code/check?code={quoted}",
headers={"User-Agent": USER_AGENT})
context = (_ssl_context() if base.startswith("https://")
else None)
with urllib.request.urlopen(request, timeout=10,
context=context) as response:
return json.loads(response.read(4096).decode(
"utf-8", "replace"))
except Exception as exc: # noqa: BLE001
last = f"{type(exc).__name__}: {exc}"
continue
return {"ok": False, "error": last if "last" in dir() else "连不上中转"}
def _ensure_device_id(self) -> str:'''
# ================= 3. run_setup:先检查再改防火墙 =================
RUN_OLD = ''' result = SetupWindow(store).show()
if result is None:
return 0 # 用户关掉了窗口
store.set_pairing_code(result["code"])
store.set("setup_done", True)'''
RUN_NEW = ''' # 先检查配对码能不能用,**通过了才去改防火墙**。
#
# 踩过的坑:以前是先存码、开自启、修防火墙,最后才转静默——
# 而"码被别的电脑占了"这件事要等转静默之后才发现。
# 那时防火墙已经改完了,用户在设置窗口里也没机会换码。
result = None
while True:
window = SetupWindow(store).show()
if window is None:
return 0 # 用户关掉了窗口(放弃安装)
code = window.get("code", "")
problem = check_code_available(store, code)
if problem is None:
result = window
break
# 被占了:说清楚,让他回去换一个
_tell_code_problem(problem)
store.set_pairing_code(result["code"])
store.set("setup_done", True)'''
# 在 run_setup 前面插入两个辅助函数
HELPER_ANCHOR = '''def run_setup(store) -> int:'''
HELPER_NEW = '''def check_code_available(store, code: str):
"""这个配对码能用吗?
能用(或没法判断)返回 None;被别的电脑占了返回一段说明文字。
检查走中转的只读接口 /v1/code/check —— 不注册,所以不会误占。
连不上中转时返回 None(放行):不能因为服务器连不上就装不了,
真有问题等转静默之后还会再提示一次。
"""
if not code or len(code) != 6 or not code.isdigit():
return "配对码必须是 6 位数字"
target = str(store.get("relay_url") or "") or DEFAULT_RELAY_URL
if not target.strip():
return None # 没配中转,没法检查
try:
from lanremote.relay import RelayLink
link = RelayLink(store, log=lambda _m: None)
# start() 会去连中转并登记 —— 但我们只用它的 candidate 解析,
# 不用它登记(登记会占用配对码)。
link.candidates = []
for piece in target.replace(",", ";").split(";"):
piece = piece.strip().rstrip("/")
if not piece:
continue
if not piece.startswith(("http://", "https://")):
from lanremote.relay import _guess_scheme
piece = _guess_scheme(piece) + piece
link.candidates.append(piece)
link.url = link.candidates[0] if link.candidates else ""
reply = link._check_code(code)
except Exception: # noqa: BLE001
return None # 检查失败就当没问题
if not reply.get("ok"):
return None # 服务器没回应,放行
if not reply.get("taken"):
return None # 没人用,可以用
where = reply.get("deviceName") or "另一台电脑"
return (
f"配对码 {code} 已经被「{where}」占用了。\\n\\n"
f"一个配对码同时只能给一台电脑用。\\n"
f"请换一个别的 6 位数字。\\n\\n"
f"(想继续用这个码的话,可以去中转管理页把占用它的那台设备删掉)"
)
def _tell_code_problem(message: str) -> None:
"""把配对码的问题告诉用户。有界面就弹窗,没有就打印。"""
try:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
root.withdraw()
root.attributes("-topmost", True)
messagebox.showerror("配对码不能用", message)
root.destroy()
return
except Exception: # noqa: BLE001
pass
print("=" * 56)
print("配对码不能用")
print(message)
print("=" * 56)
def run_setup(store) -> int:'''
def main() -> int:
ok = True
# ---- 中转 ----
text = RELAY_SERVER.read_text(encoding="utf-8")
if "/v1/code/check" in text:
print(" 中转:已经有 /v1/code/check")
elif SRV_ANCHOR in text:
text = text.replace(SRV_ANCHOR, SRV_NEW, 1)
RELAY_SERVER.write_text(text, encoding="utf-8", newline="\n")
print(" 中转:加了只读查询 /v1/code/check")
else:
print(" [失败] 中转锚点没找到")
ok = False
# 确认 urllib.parse 已导入
if "import urllib.parse" not in text:
text = text.replace("import urllib.request",
"import urllib.parse\nimport urllib.request", 1)
RELAY_SERVER.write_text(text, encoding="utf-8", newline="\n")
print(" 中转:补了 import urllib.parse")
# ---- 被控端 ----
text = RELAY_CLIENT.read_text(encoding="utf-8")
if "_check_code" in text:
print(" 被控端:已经有 _check_code")
elif CLIENT_ANCHOR in text:
text = text.replace(CLIENT_ANCHOR, CLIENT_NEW, 1)
RELAY_CLIENT.write_text(text, encoding="utf-8", newline="\n")
print(" 被控端:加了 _check_code()")
else:
print(" [失败] 被控端锚点没找到")
ok = False
if "import urllib.parse" not in text:
text = text.replace("import urllib.request",
"import urllib.parse\nimport urllib.request", 1)
RELAY_CLIENT.write_text(text, encoding="utf-8", newline="\n")
print(" 被控端:补了 import urllib.parse")
# ---- run_agent ----
text = RUN.read_text(encoding="utf-8")
if "check_code_available" in text:
print(" run_agent:已经有检查逻辑")
else:
if HELPER_ANCHOR in text:
text = text.replace(HELPER_ANCHOR, HELPER_NEW, 1)
print(" run_agent:加了 check_code_available / _tell_code_problem")
else:
print(" [失败] run_agent 锚点没找到")
ok = False
if RUN_OLD in text:
text = text.replace(RUN_OLD, RUN_NEW, 1)
print(" run_agent:run_setup 改成先检查再改防火墙")
else:
print(" [失败] 找不到 run_setup 的那一段")
ok = False
RUN.write_text(text, encoding="utf-8", newline="\n")
# ---- 语法 ----
import ast
for label, path in (("中转", RELAY_SERVER), ("被控端", RELAY_CLIENT),
("run_agent", RUN)):
try:
ast.parse(path.read_text(encoding="utf-8"))
print(f" {label} 语法 OK")
except SyntaxError as exc:
print(f" {label} 语法错误: 行 {exc.lineno}: {exc.msg}")
ok = False
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())