mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-19 09:30:44 +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,253 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""把任务栏恢复常显,并把测试改成只读。
|
||||
|
||||
教训:上一个测试会**真的执行**每一个开关,包括
|
||||
lock_input 锁键盘鼠标(要管理员才能解)
|
||||
taskbar_hide 杀掉 explorer 重启
|
||||
这在用户真机上跑是闯祸,必须改成只读检查。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import winreg
|
||||
from pathlib import Path
|
||||
|
||||
SETTINGS_KEY = (r"Software\Microsoft\Windows\CurrentVersion\Explorer"
|
||||
r"\StuckRects3")
|
||||
TEST = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\_tests"
|
||||
r"\test_toggles.py")
|
||||
|
||||
|
||||
def restore_taskbar() -> None:
|
||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, SETTINGS_KEY, 0,
|
||||
winreg.KEY_READ | winreg.KEY_WRITE) as key:
|
||||
raw, _kind = winreg.QueryValueEx(key, "Settings")
|
||||
blob = bytearray(raw)
|
||||
before = blob[8]
|
||||
blob[8] = 2 # 2 = 常显
|
||||
if before != 2:
|
||||
winreg.SetValueEx(key, "Settings", 0, winreg.REG_BINARY, bytes(blob))
|
||||
print(f" 任务栏 Settings[8]: {before} -> 2(恢复常显)")
|
||||
else:
|
||||
print(" 任务栏本来就是常显,不用改")
|
||||
|
||||
# 让 explorer 重新读一次设置。用 taskkill 比 Stop-Process 温和一点,
|
||||
# 而且 explorer 会被系统自动拉起来。
|
||||
subprocess.run(["taskkill", "/f", "/im", "explorer.exe"],
|
||||
capture_output=True, creationflags=0x08000000)
|
||||
print(" 已通知 explorer 重载(它会自己起来)")
|
||||
time.sleep(4)
|
||||
|
||||
|
||||
NON_DESTRUCTIVE = '''# -*- coding: utf-8 -*-
|
||||
"""只读回归测试:开关的方向性 + 能开就要能关。
|
||||
|
||||
**重要:这个测试不执行任何破坏性功能。**
|
||||
之前的版本会真的跑每一个 toggle,包括「锁键盘鼠标」(要管理员才能解)
|
||||
和「任务栏自动隐藏」(会杀 explorer)——在用户真机上那是闯祸。
|
||||
|
||||
现在改成:
|
||||
* 系统状态只用**只读**方式核对(注册表 / 窗口枚举)
|
||||
* 只真正执行明确安全的几个开关(循环播放、随机播放)
|
||||
* 其余开关只核对:声明了两个方向、实现里两个分支都在
|
||||
* 关窗口那条链路是真的执行(它本来就是把东西关掉,安全)
|
||||
"""
|
||||
import ctypes
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import winreg
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "windows"))
|
||||
|
||||
import tkinter as tk # noqa: E402
|
||||
|
||||
from lanremote.actions import Actions # noqa: E402
|
||||
from lanremote.config import Store # noqa: E402
|
||||
from lanremote.features import Features # noqa: E402
|
||||
from lanremote.headless import HeadlessUI # noqa: E402
|
||||
|
||||
# 会真的改动系统、或者要管理员才能撤销的开关:不执行
|
||||
DESTRUCTIVE = {
|
||||
"lock_input", "taskbar_hide", "autostart", "quit_agent",
|
||||
"hide_icons", "restrict_taskmgr", "restrict_regedit", "restrict_cmd",
|
||||
"restrict_wallpaper", "restrict_power", "block_new_app",
|
||||
"allow_run", "allow_power", "allow_screen", "close_pair_after_first",
|
||||
"night_mode", "hidden_files", "clock_seconds", "mouse_trail",
|
||||
}
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
|
||||
def check(name, ok, detail=""):
|
||||
global passed, failed
|
||||
if ok:
|
||||
passed += 1
|
||||
print(f" [PASS] {name}")
|
||||
else:
|
||||
failed += 1
|
||||
print(f" [FAIL] {name} {detail}")
|
||||
|
||||
|
||||
def visible_windows(keyword):
|
||||
user32 = ctypes.windll.user32
|
||||
proc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p)
|
||||
found = []
|
||||
|
||||
def callback(hwnd, _l):
|
||||
pid = ctypes.c_ulong()
|
||||
user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
|
||||
if pid.value != os.getpid() or not user32.IsWindowVisible(hwnd):
|
||||
return True
|
||||
length = user32.GetWindowTextLengthW(hwnd)
|
||||
buf = ctypes.create_unicode_buffer(length + 2)
|
||||
user32.GetWindowTextW(hwnd, buf, length + 2)
|
||||
if keyword in buf.value:
|
||||
found.append(buf.value)
|
||||
return True
|
||||
|
||||
user32.EnumWindows(proc(callback), 0)
|
||||
return found
|
||||
|
||||
|
||||
def main() -> int:
|
||||
store = Store(Path(tempfile.mkdtemp()))
|
||||
ui = HeadlessUI(store)
|
||||
actions = Actions(ui, store)
|
||||
features = Features(actions)
|
||||
ui.root
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
print("一、功能表完整性")
|
||||
defs = features.defs()
|
||||
check("功能数量 > 200", len(defs) > 200, f"{len(defs)} 个")
|
||||
missing = [d["name"] for d in defs if not hasattr(features, "_do_" + d["name"])]
|
||||
check("没有缺实现的功能", not missing, str(missing)[:120])
|
||||
|
||||
groups = sorted({d["group"] for d in defs})
|
||||
check("分组数 = 14", len(groups) == 14, str(groups))
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
print()
|
||||
print("二、每个开关都声明了「开」和「关」两个方向")
|
||||
toggles = [d for d in defs if d.get("kind") == "toggle"]
|
||||
check("有 toggle 类功能", len(toggles) >= 8, f"{len(toggles)} 个")
|
||||
|
||||
source = (ROOT / "windows" / "lanremote" / "features.py").read_text(
|
||||
encoding="utf-8")
|
||||
one_way = []
|
||||
for item in toggles:
|
||||
name = item["name"]
|
||||
# 实现里必须用到了 on 参数(不然就是只能往一个方向走)
|
||||
body = source
|
||||
index = source.find(f"def _do_{name}(")
|
||||
if index > 0:
|
||||
body = source[index:index + 1400]
|
||||
uses_on = ("params.get(\"on\")" in body or "on\")" in body
|
||||
or "_truthy(params" in body)
|
||||
if not uses_on:
|
||||
one_way.append(name)
|
||||
check("所有开关都用到了 on 参数(能往两个方向走)", not one_way,
|
||||
f"只往一个方向的: {one_way}")
|
||||
|
||||
# 手表侧:缓存必须跟着翻转
|
||||
main_java = (ROOT / "android" / "src" / "com" / "lanremote" / "watch"
|
||||
/ "MainActivity.java").read_text(encoding="utf-8")
|
||||
check("手表 toggle 后会更新本地缓存",
|
||||
'feature.put("on"' in main_java,
|
||||
"没找到 feature.put(\"on\", ...)")
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
print()
|
||||
print("三、安全开关真的往返一次")
|
||||
for name in ("loop_play", "shuffle_play"):
|
||||
try:
|
||||
on = features.run(name, {"on": True})
|
||||
off = features.run(name, {"on": False})
|
||||
check(f"{name} 两个方向话术不同", str(on) != str(off),
|
||||
f"开={on!r} 关={off!r}")
|
||||
except Exception as exc: # noqa: BLE001
|
||||
check(f"{name} 往返", False, str(exc)[:80])
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
print()
|
||||
print("四、手表开的画面必须能关掉")
|
||||
ui.notify("测试通知一", "内容")
|
||||
ui.notify("测试通知二", "内容")
|
||||
time.sleep(1.2)
|
||||
before = visible_windows("通知")
|
||||
check("通知确实弹出来了", len(before) >= 2, f"{len(before)} 个")
|
||||
|
||||
result = features.run("close_visuals", {})
|
||||
time.sleep(1.2)
|
||||
after = visible_windows("通知")
|
||||
check("close_visuals 关掉了通知", len(after) == 0,
|
||||
f"关前 {len(before)},关后 {len(after)}({result})")
|
||||
|
||||
features.run("big_text", {"text": "测试大字XYZ"})
|
||||
time.sleep(1.0)
|
||||
check("全屏大字弹出来了", len(visible_windows("测试大字XYZ")) >= 1)
|
||||
features.run("close_visuals", {})
|
||||
time.sleep(1.0)
|
||||
check("close_visuals 关掉了全屏大字",
|
||||
len(visible_windows("测试大字XYZ")) == 0)
|
||||
|
||||
again = features.run("close_visuals", {})
|
||||
check("没东西可关时也不报错", "没有" in str(again), str(again))
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
print()
|
||||
print("五、系统状态用只读方式核对")
|
||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER,
|
||||
r"Software\Microsoft\Windows\CurrentVersion"
|
||||
r"\Explorer\StuckRects3") as key:
|
||||
raw, _ = winreg.QueryValueEx(key, "Settings")
|
||||
blob = bytes(raw)
|
||||
check("Settings 能读到且够长", len(blob) > 8, f"{len(blob)} 字节")
|
||||
check("_taskbar_hidden() 与注册表一致",
|
||||
features._taskbar_hidden() == bool(blob[8] & 1),
|
||||
f"函数={features._taskbar_hidden()} 注册表={bool(blob[8] & 1)}")
|
||||
|
||||
from lanremote import autostart
|
||||
try:
|
||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER,
|
||||
r"Software\Microsoft\Windows\CurrentVersion\Run"
|
||||
) as key:
|
||||
winreg.QueryValueEx(key, "LanRemoteAgent")
|
||||
registry_on = True
|
||||
except FileNotFoundError:
|
||||
registry_on = False
|
||||
check("is_enabled() 与注册表一致",
|
||||
autostart.is_enabled() == registry_on,
|
||||
f"函数={autostart.is_enabled()} 注册表={registry_on}")
|
||||
|
||||
ui.stop()
|
||||
print()
|
||||
print("=" * 66)
|
||||
print(f"通过 {passed} 项,失败 {failed} 项")
|
||||
if failed:
|
||||
print("失败项:")
|
||||
return 0 if failed == 0 else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
'''
|
||||
|
||||
|
||||
def main() -> int:
|
||||
restore_taskbar()
|
||||
TEST.write_text(NON_DESTRUCTIVE, encoding="utf-8")
|
||||
print(f" 已把 {TEST.name} 改写成只读测试")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user