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
+231
View File
@@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-
"""配对码被占用时,在电脑上弹通知。
用户的要求:
"如果一个设备设置了配对码 789113,另一个设备也想设置 789113,
那不可以,你就弹通知,说该配对码已被使用,请换一个配对码"
现状:
中转服务器**已经**会拒绝(返回 "这个配对码已经被另一台设备用了,换一个"),
被控端也抛了这个错误 —— 但只是写进日志,用户根本看不到。
而且主循环会当成网络错误一直重试,刷屏。
要做的:
1. 中转返回里加 codeTaken 标记(让客户端能精确识别,不靠匹配中文)
2. 被控端加 RelayCodeTaken 异常
3. 加 on_alert 回调 —— 服务器把它接到界面通知上
4. 主循环遇到冲突时:**弹一次通知就停下来等**,不要反复重试刷屏
用户换了配对码之后自动继续。
"""
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"
SERVER = ROOT / "windows" / "lanremote" / "server.py"
# ============ 1. 中转:返回加 codeTaken ============
SRV_OLD = ''' known = self.codes.get(code)
if known and known != device_id:
return {"ok": False,
"error": "这个配对码已经被另一台设备用了,换一个"}'''
SRV_NEW = ''' known = self.codes.get(code)
if known and known != device_id:
# codeTaken 让客户端能精确识别这种冲突,
# 不用去匹配中文错误文案(文案一改就坏)。
self.log(f"配对码 {code} 已被 {known} 占用,拒绝 {device_id}")
return {"ok": False,
"codeTaken": True,
"error": "该配对码已被使用,请换一个配对码"}'''
# ============ 2. 被控端:异常类 ============
EXC_ANCHOR = '''class _AuthLost(Exception):'''
EXC_NEW = '''class RelayCodeTaken(RelayError):
"""配对码被别的设备占了。
这**不是网络问题**,重试没用 —— 要等用户换一个配对码。
所以主循环遇到它不能当成普通错误一直重试(会刷屏),
而是弹一次通知然后停下等。
"""
class _AuthLost(Exception):'''
# ============ 3. 被控端:__init__ 加 on_alert ============
INIT_OLD = ''' def __init__(self, store, log=None, on_session=None) -> None:
self.store = store
self._log = log or (lambda _m: None)
self._on_session = on_session'''
INIT_NEW = ''' def __init__(self, store, log=None, on_session=None, on_alert=None) -> None:
self.store = store
self._log = log or (lambda _m: None)
self._on_session = on_session
# 出需要用户处理的事(比如配对码被占)时调这个,用来弹通知
self._on_alert = on_alert'''
INIT2_OLD = ''' self.sessions_served = 0'''
INIT2_NEW = ''' self.sessions_served = 0
# 配对码冲突的说明。非空表示现在卡在这,等用户换码。
self.code_conflict = ""
self._alerted_code = ""'''
# ============ 4. 被控端:_register 抛专用异常 ============
REG_OLD = ''' if not reply.get("ok"):
raise RelayError(str(reply.get("error") or "登记被拒"))'''
REG_NEW = ''' if not reply.get("ok"):
message = str(reply.get("error") or "登记被拒")
# 配对码被占:精确判断(服务端会带 codeTaken),
# 兼容老服务端就匹配关键字。
if reply.get("codeTaken") or "已被" in message and "配对码" in message:
raise RelayCodeTaken(message)
raise RelayError(message)
# 登记成功 -> 之前的冲突解除了
self.code_conflict = ""'''
# ============ 5. 被控端:主循环处理冲突 ============
RUN_OLD = ''' except _AuthLost:
self._log("中转说令牌失效,重新登记")
self.token = ""
time.sleep(1)'''
RUN_NEW = ''' except _AuthLost:
self._log("中转说令牌失效,重新登记")
self.token = ""
time.sleep(1)
except RelayCodeTaken as exc:
# 配对码被别的设备占了。这不是网络问题,重试没用。
# 弹一次通知,然后**停下来等用户换码**。
message = str(exc) or "该配对码已被使用,请换一个配对码"
self.online = False
self.token = ""
self.last_error = message
self.code_conflict = message
current = self.store.pairing_code()
if current != self._alerted_code:
# 只在换了新码之后再弹,避免反复弹同一个码的通知
self._alerted_code = current
self._log(f"配对码冲突:{message}")
if self._on_alert:
try:
self._on_alert("配对码被占用", message)
except Exception: # noqa: BLE001
pass
# 等用户换码。每 5 秒看一次配对码变没变。
for _ in range(12):
if not self._running:
return
time.sleep(0.5)
if self.store.pairing_code() != current:
self._log("配对码变了,重新登记")
self._alerted_code = ""
break
continue'''
# ============ 6. 被控端:status 里带上冲突信息 ============
STATUS_OLD = ''' "candidates": list(self.candidates),'''
STATUS_NEW = ''' "candidates": list(self.candidates),
"codeConflict": self.code_conflict,'''
# ============ 7. 服务器:把 on_alert 接到界面通知 ============
WIRE_OLD = ''' self._relay = RelayLink(self.store, log=self._log,
on_session=self.adopt_relay_socket)'''
WIRE_NEW = ''' self._relay = RelayLink(self.store, log=self._log,
on_session=self.adopt_relay_socket,
on_alert=self._alert)'''
def patch(path: Path, pairs, label: str) -> bool:
text = path.read_text(encoding="utf-8")
ok = True
for old, new, tag in pairs:
if old not in text:
print(f" [{label}] [跳过] {tag} —— 锚点没找到")
ok = False
continue
text = text.replace(old, new, 1)
print(f" [{label}] {tag}")
path.write_text(text, encoding="utf-8", newline="\n")
return ok
def main() -> int:
ok = True
ok &= patch(RELAY_SERVER, [(SRV_OLD, SRV_NEW, "冲突返回加 codeTaken")],
"中转")
ok &= patch(RELAY_CLIENT, [
(EXC_ANCHOR, EXC_NEW, "RelayCodeTaken 异常"),
(INIT_OLD, INIT_NEW, "__init__ 加 on_alert"),
(INIT2_OLD, INIT2_NEW, "__init__ 加冲突字段"),
(REG_OLD, REG_NEW, "_register 抛专用异常"),
(RUN_OLD, RUN_NEW, "主循环处理冲突"),
(STATUS_OLD, STATUS_NEW, "status 带冲突信息"),
], "被控端")
# 服务器:加 _alert 方法 + 接线
text = SERVER.read_text(encoding="utf-8")
if WIRE_OLD in text:
text = text.replace(WIRE_OLD, WIRE_NEW, 1)
print(" [服务器] on_alert 接线")
else:
print(" [服务器] [跳过] 接线锚点没找到")
ok = False
alert_method = ''' def _alert(self, title: str, text: str) -> None:
"""给用户看的通知(配对码被占这类必须让人知道的事)。
走界面的通知,用户在电脑上能直接看到。
界面还没起来时退回写日志,至少不丢信息。
"""
self._log(f"[需要处理] {title}:{text}")
try:
ui = getattr(self.actions, "ui", None)
if ui is not None and hasattr(ui, "notify"):
ui.notify(title, text)
except Exception: # noqa: BLE001
pass
def relay_status(self) -> dict:'''
if "def _alert(" in text:
print(" [服务器] 已经有 _alert")
elif " def relay_status(self) -> dict:" in text:
text = text.replace(" def relay_status(self) -> dict:",
alert_method, 1)
print(" [服务器] 加了 _alert 方法")
else:
print(" [服务器] [失败] 找不到 relay_status")
ok = False
SERVER.write_text(text, encoding="utf-8", newline="\n")
import ast
for label, path in (("中转", RELAY_SERVER), ("被控端", RELAY_CLIENT),
("服务器", SERVER)):
try:
ast.parse(path.read_text(encoding="utf-8"))
print(f" {label} 语法 OK")
except SyntaxError as exc:
print(f" {label} 语法错误: {exc}")
ok = False
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())