mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-19 02:30:43 +00:00
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:
@@ -0,0 +1,207 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""两件事:
|
||||
|
||||
【1】修「弹通知」在静默模式下不显示
|
||||
HeadlessUI.notify 之前只写日志,什么都不弹,所以手表点「弹通知」
|
||||
电脑上一点反应都没有。
|
||||
静默模式的意思是"开机不弹控制窗口",不代表手表**明确要求显示**的
|
||||
东西也不显示 —— 投图、全屏大字、通知都属于这一类。
|
||||
|
||||
【2】把网络自检 / 修防火墙做进 EXE
|
||||
原来的 网络自检.bat 会去找 python,没装 Python 的电脑用不了。
|
||||
现在改成调用 LanRemote-Agent.exe --netcheck。
|
||||
因为是 --windowed 程序没有控制台,所以要先 AllocConsole 自己开一个。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows")
|
||||
HEADLESS = ROOT / "lanremote" / "headless.py"
|
||||
RUN = ROOT / "run_agent.py"
|
||||
|
||||
# ---------------- 1. notify 真的弹窗 ----------------
|
||||
|
||||
NOTIFY_OLD = ''' def notify(self, title: str, text: str) -> None:
|
||||
"""静默模式下不弹气泡,只记日志。
|
||||
|
||||
真正的"提醒"由功能自己用 actions.notify 决定要不要显示窗口。
|
||||
"""
|
||||
self.log(f"[通知] {title}: {text}")'''
|
||||
|
||||
NOTIFY_NEW = ''' def notify(self, title: str, text: str) -> None:
|
||||
"""弹一个小通知窗(屏幕右下角,几秒后自动消失)。
|
||||
|
||||
之前这里只写日志,所以手表点「弹通知」电脑上毫无反应。
|
||||
静默模式的意思是"开机不弹控制窗口",而不是
|
||||
"手表明确要求显示的东西也不显示" —— 投图、全屏大字、通知
|
||||
都属于"明确要求",照常显示。
|
||||
"""
|
||||
self.log(f"[通知] {title}: {text}")
|
||||
root = self._ensure_root()
|
||||
if root is None:
|
||||
return
|
||||
|
||||
def build():
|
||||
try:
|
||||
win = tk.Toplevel(root)
|
||||
win.title(f"通知 - {title}")
|
||||
win.overrideredirect(True)
|
||||
win.attributes("-topmost", True)
|
||||
win.configure(bg="#ffffff")
|
||||
|
||||
box = tk.Frame(win, bg="#ffffff", highlightthickness=1,
|
||||
highlightbackground="#d0d7de")
|
||||
box.pack(fill="both", expand=True)
|
||||
tk.Frame(box, bg="#185ce8", height=4).pack(fill="x")
|
||||
tk.Label(box, text=title or "通知", bg="#ffffff",
|
||||
fg="#1f2328", font=("Microsoft YaHei UI", 11, "bold"),
|
||||
anchor="w").pack(fill="x", padx=14, pady=(10, 2))
|
||||
tk.Label(box, text=text or "", bg="#ffffff", fg="#656d76",
|
||||
font=("Microsoft YaHei UI", 10), anchor="w",
|
||||
justify="left", wraplength=260).pack(
|
||||
fill="x", padx=14, pady=(0, 12))
|
||||
win.update_idletasks()
|
||||
|
||||
screen_w, screen_h = self.screen_size()
|
||||
width = max(240, win.winfo_reqwidth())
|
||||
height = win.winfo_reqheight()
|
||||
win.geometry(f"+{screen_w - width - 24}+{screen_h - height - 72}")
|
||||
|
||||
def close(_event=None):
|
||||
try:
|
||||
win.destroy()
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
win.bind("<Button-1>", close)
|
||||
win.after(6000, close)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self.log(f"通知显示失败: {exc}")
|
||||
|
||||
try:
|
||||
self._queue.put(build)
|
||||
except Exception: # noqa: BLE001
|
||||
pass'''
|
||||
|
||||
# ---------------- 2. run_agent 加 --netcheck / --fix-firewall ----------------
|
||||
|
||||
ARGS_OLD = ''' parser.add_argument("--setup", action="store_true",
|
||||
help="重新打开设置窗口")'''
|
||||
ARGS_NEW = ''' parser.add_argument("--setup", action="store_true",
|
||||
help="重新打开设置窗口")
|
||||
parser.add_argument("--netcheck", nargs="?", type=int, const=90,
|
||||
default=None, metavar="秒",
|
||||
help="网络自检(自开控制台,不需要装 Python)")
|
||||
parser.add_argument("--fix-firewall", action="store_true",
|
||||
help="提权修复防火墙")'''
|
||||
|
||||
MAIN_OLD = ''' if args.autostart:
|
||||
return cli_autostart(args.autostart)
|
||||
if args.status:
|
||||
return cli_status()'''
|
||||
MAIN_NEW = ''' if args.autostart:
|
||||
return cli_autostart(args.autostart)
|
||||
if args.status:
|
||||
return cli_status()
|
||||
|
||||
# 这两个是给 .bat 调的:EXE 自带功能,不需要系统装 Python
|
||||
if args.netcheck is not None:
|
||||
return cli_netcheck(args.netcheck)
|
||||
if args.fix_firewall:
|
||||
return cli_fix_firewall()'''
|
||||
|
||||
CLI_ANCHOR = '''def cli_status() -> int:'''
|
||||
|
||||
CLI_NEW = '''def attach_console() -> None:
|
||||
"""给 --windowed 程序自己开一个控制台窗口。
|
||||
|
||||
打包成 --windowed 后进程没有控制台,直接 print 什么都看不到。
|
||||
AllocConsole 可以临时开一个,并把 stdout/stderr 接过去。
|
||||
"""
|
||||
if os.name != "nt":
|
||||
return
|
||||
try:
|
||||
import ctypes
|
||||
ctypes.windll.kernel32.AllocConsole()
|
||||
sys.stdout = open("CONOUT$", "w", encoding="utf-8", buffering=1)
|
||||
sys.stderr = open("CONOUT$", "w", encoding="utf-8", buffering=1)
|
||||
try:
|
||||
sys.stdin = open("CONIN$", "r", encoding="utf-8")
|
||||
except OSError:
|
||||
pass
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
|
||||
def wait_key() -> None:
|
||||
try:
|
||||
print()
|
||||
input("按回车键关闭这个窗口…")
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
|
||||
def cli_netcheck(seconds: int) -> int:
|
||||
"""网络自检:监听端口,看手表的包到底有没有到这台电脑。"""
|
||||
attach_console()
|
||||
try:
|
||||
from lanremote import netcheck
|
||||
return netcheck.run_check(int(seconds or 90))
|
||||
except Exception as exc: # noqa: BLE001
|
||||
print(f"自检运行失败: {exc}")
|
||||
return 1
|
||||
finally:
|
||||
wait_key()
|
||||
|
||||
|
||||
def cli_fix_firewall() -> int:
|
||||
"""提权修复防火墙(会弹一次 UAC,然后黑终端一闪)。"""
|
||||
store = Store(data_dir())
|
||||
ok, detail = fix_firewall_with_flash(store)
|
||||
attach_console()
|
||||
print(("已修复:" if ok else "未完成:") + str(detail))
|
||||
wait_key()
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
def cli_status() -> int:'''
|
||||
|
||||
|
||||
def main() -> int:
|
||||
# 1
|
||||
text = HEADLESS.read_text(encoding="utf-8")
|
||||
if NOTIFY_OLD not in text:
|
||||
print(" [失败] headless notify 锚点没找到")
|
||||
return 1
|
||||
HEADLESS.write_text(text.replace(NOTIFY_OLD, NOTIFY_NEW, 1), encoding="utf-8")
|
||||
print(" headless.notify: 已改成真的弹通知窗")
|
||||
|
||||
# 2
|
||||
text = RUN.read_text(encoding="utf-8")
|
||||
for old, new, tag in ((ARGS_OLD, ARGS_NEW, "--netcheck/--fix-firewall 参数"),
|
||||
(MAIN_OLD, MAIN_NEW, "main 分发"),
|
||||
(CLI_ANCHOR, CLI_NEW, "cli_netcheck/cli_fix_firewall")):
|
||||
if old not in text:
|
||||
print(f" [跳过] {tag} —— 锚点没找到")
|
||||
continue
|
||||
text = text.replace(old, new, 1)
|
||||
print(f" {tag}: OK")
|
||||
RUN.write_text(text, encoding="utf-8")
|
||||
|
||||
import ast
|
||||
ok = True
|
||||
for label, path in (("headless.py", HEADLESS), ("run_agent.py", RUN),
|
||||
("netcheck.py", ROOT / "lanremote" / "netcheck.py")):
|
||||
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())
|
||||
Reference in New Issue
Block a user