2.2.0:手表端连上后先到「远控 / 静默更新被控端」选择页

== 用户要求 ==

"安卓那个逻辑也要改一下,就是你输入配对码后,进入一个页面,
 页面有两个按钮,第一个按钮是远控,第二个按钮是静默更新被控端"

== 做成什么样 ==

新增 choicePanel,连接成功后先进这一页:

    已连接「电脑名」
    电脑端 2.1.5 → 可更新到 2.2.0

    [        远控        ]   <- 第一个按钮
    [   静默更新被控端    ]   <- 第二个按钮

按钮顺序按用户说的来(远控在前)。

页面顶上显示电脑名和**电脑端当前版本** —— 用户之前要求
"手表端连接那个电脑端也可以查看电脑端目前所处的版本",
这里是最自然的展示位置(不弹框,只显示一行)。

为什么不让它直接进控制页:老版本的被控端可能缺功能或有 bug,
"先更新再远控"是更合理的顺序 —— 但不强制,给用户自己选。

== 一个刻意不改的地方 ==

自动切到中转服务器**恢复**时的 `showControlPanel()` **没动** ——
用户本来就在远控页,中途弹一层选择页会打断他。
测试里专门断言了这一点,免得以后有人"顺手统一一下"改坏。

== 顺手修的几个问题 ==

1. **忘了定义 lastDeviceName** —— 写选择页时凭直觉用了这个变量,
   编译报"找不到符号"。补上字段并在连接回调里赋值。
   (教训:写代码时要用的变量,先确认它存在。)

2. **泄漏闸门拦下我自己** —— 这两天写的一批服务器诊断/配置脚本里
   硬编码了服务器 IP(26 处,5 个文件)。规则是 IP 不能进任何
   被跟踪的文件。已全部改成占位符,真实值仍从
   _build/.lightsail_host(已 gitignore)读。

3. **verify_all.ps1 删掉「锁屏时记 SKIP」的逻辑** ——
   用户明确要求删。那个好意带来一个更糟的后果:锁屏时几关根本不跑,
   回归"全绿"了但关键测试其实一跳而过。
   **"因为环境不满足所以不测"比"测了发现失败"更危险。**
   删掉之后果然暴露出 3 个 FAIL —— 屏幕解锁后重跑全部通过,
   确认是环境问题而不是代码问题。

== 服务器这边(不在这份提交里,但同一天做的)==

  * nginx 按用户要求重排:
      IP(80) 任何路径 -> 404(没东西)
      域名 / -> 官网;/zhongzhuanzhan -> 中转站设置
      9100 -> 同样的内容(等 AWS 开防火墙)
  * 删掉早年 Cloudflare Tunnel 的 systemd 残留
  * **补上 ACME 挑战例外** —— 这是最要紧的一条:
    80 端口原来把所有请求都 301 到 https,包括
    /.well-known/acme-challenge/,**续期时会失败**。
    而且它是延迟爆发的(最长 90 天后证书到期才暴露)。
  * 清理 1Panel 安装包残留(223MB)

== 验证 ==

    全量回归 21 关全部 PASS(零 FAIL,桌面可用状态)
    Java 编译通过(android-34, --release 8)
    623+ Python 文件语法通过
    泄漏闸门通过
    全部产物重建,Win7 兼容校验通过
This commit is contained in:
xmz7891
2026-10-10 17:13:24 +08:00
parent 48bc392466
commit 1d368979aa
29 changed files with 2000 additions and 122 deletions
+121
View File
@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
r'''把 verify_all.ps1 里的「锁屏检测 + SKIP」删掉。
== 用户要求 ==
"然后把全量中锁屏这个环节删了"
== 原来是什么 ==
脚本开头检测当前输入桌面是不是 Winlogon(锁屏),是的话
把标记了 needsDesktop 的阶段记成 `SKIP(锁屏)` 而不是 FAIL ——
本意是"锁屏时截屏类测试必然失败,那是环境限制不是代码问题,
别把真问题淹没"。
== 为什么删 ==
那个好意带来一个更糟的后果:**锁屏时那几关根本不跑,于是回归
"全绿"了但实际什么都没验**。用户看到"全部通过"会以为没问题,
而关键的 Java 端到端、协议回归那几关其实一跳而过。
**"因为环境不满足所以不测"比"测了发现失败"更危险** ——
失败至少是信息,跳过是假的安全感。
== 怎么改 ==
* 删掉整段桌面检测(OpenInputDesktop / GetUserObjectInformationW /
HasDesktop 那套 P/Invoke)
* `Record` 不再有 SKIP 分支,只有 PASS / FAIL
* **保留 `$needsDesktop` 这个参数**(签名不变)——
6 个调用点还在传它,留着就不用改它们;只是现在它被忽略。
为什么不把那 6 处也改掉:改调用点增加出错面,而参数留着完全无害。
以后真要重新引入"某些阶段在特定环境下跳过",签名还在。
== 顺带 ==
`_tests/hidden_desktop.py` 那套(在隐藏桌面上跑窗口类测试)
**不动** —— 那是为了让测试不打扰用户,跟"锁屏跳过"是两回事。
'''
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
VERIFY = ROOT / "_tests" / "verify_all.ps1"
OLD_START = "# 当前会话是不是锁屏 / 没有交互桌面?"
OLD_END = '''function Banner($text) {'''
NEW_BLOCK = '''# ⚠ 这里**原来有一段锁屏检测**,锁屏时把 needsDesktop 的阶段记成
# `SKIP(锁屏)` 而不是 FAIL。**已经按用户要求删掉了。**
#
# 删的理由:那个好意带来一个更糟的后果 —— 锁屏时那几关根本不跑,
# 于是回归"全绿"了,但关键的 Java 端到端、协议回归其实一跳而过。
# 用户看到"全部通过"会以为没问题。
#
# **"因为环境不满足所以不测"比"测了发现失败"更危险**:
# 失败至少是信息,跳过是假的安全感。
#
# 现在一律真跑、真记。环境不合适导致失败的话,就去修环境或改测试,
# 而不是让它变成 SKIP。
function Record($name, $ok, $needsDesktop = $false) {
# ⚠ $needsDesktop 参数**保留但不再使用** ——
# 6 个调用点还在传它,留着就不用改那些地方。
# 以后真要重新引入"特定环境下跳过",签名已经在了。
$script:results += [pscustomobject]@{
项目 = $name; 结果 = $(if ($ok) { "PASS" } else { "FAIL" }) }
}
'''
def main() -> int:
print("=" * 58)
print(" 删掉全量里的锁屏 SKIP")
print("=" * 58)
print()
raw = VERIFY.read_bytes()
bom = raw.startswith(b"\xef\xbb\xbf")
t = raw.decode("utf-8-sig")
if "已经按用户要求删掉了" in t:
print(" 已经删过了")
return 0
i = t.find(OLD_START)
j = t.find(OLD_END)
if i < 0 or j < 0 or j < i:
print(" ✗ 找不到起止锚点(i=%d j=%d)" % (i, j))
return 1
print(" 要删第 %d-%d 行" % (t[:i].count("\n") + 1,
t[:j].count("\n") + 1))
# 往上吃掉紧邻的 $script:results = @() 之后的空行(把那行留着)
t = t[:i] + NEW_BLOCK + t[j:]
VERIFY.write_bytes((b"\xef\xbb\xbf" if bom else b"") + t.encode("utf-8"))
print(" ✓ 删掉了锁屏检测和 SKIP 分支")
# 复核
back = VERIFY.read_text(encoding="utf-8-sig")
checks = [
("没有 desktopAvailable", "desktopAvailable" not in back),
("没有 SKIP(锁屏)", "SKIP(锁屏)" not in back),
("没有 OpenInputDesktop", "OpenInputDesktop" not in back),
("没有 Winlogon", "Winlogon" not in back),
("Record 还在", "function Record(" in back),
("$needsDesktop 参数保留", "$needsDesktop = $false" in back),
("Banner 还在", "function Banner(" in back),
]
print()
for label, ok in checks:
print(" [%s] %s" % ("PASS" if ok else "FAIL", label))
return 0 if all(ok for _l, ok in checks) else 1
if __name__ == "__main__":
sys.exit(main())