阶段1+2:恢复 HTTP/2 加速 + 重做官网

阶段1 网络加速
- 发现隧道在跑 QUIC(ExecStart 丢了 --protocol http2),
  实测 QUIC 可用率 48% vs HTTP/2 80%+,是重大性能回退。
  恢复后公网延迟从 4141ms 降到 690ms(快 6 倍),可用率 92%。
- 优选 IP 结论:无效。hosts 覆盖确实生效了(日志里连的就是指定 IP),
  但落点仍是 lax —— 运营商把所有 Cloudflare anycast 都路由到美西。
  已清掉这段无效配置。
- BBR 不可用:设备是自定义内核 6.4.0-rc4-jsbsbxjxh66,
  没编 tcp_bbr 模块也没配置项。改用 cubic + 调优:
  TCP 缓冲 4MB、tcp_fastopen=3、tcp_slow_start_after_idle=0
  (长轮询场景关键)、tcp_tw_reuse=1。

阶段2 官网重做
- 拆出独立模块 relay/landing.py(relay.py 已两千多行,
  再塞 HTML 没法看)
- 信息结构参考成熟产品站:吸顶导航 / Hero / 九宫格功能 /
  三步上手 / 下载 / FAQ / 页脚
- 保持白色简洁:底白、浅灰面板、细边框、大量留白
- logo 用内联 SVG(ICO 放 img 里实测是破图)
- 管理入口从官网移除(管理不对外开放)

过程中被自己的测试抓到两个 bug:
- 模块叫 site.py 会和 Python 标准库重名,import site 拿到的是标准库
- _logo() 里把 % 格式化和字符串拼接混用,直接抛 TypeError
This commit is contained in:
xmz7891
2026-10-06 23:53:19 +08:00
parent 9b1edbf378
commit 566d9e384f
214 changed files with 2879 additions and 1384 deletions
+177
View File
@@ -0,0 +1,177 @@
# -*- coding: utf-8 -*-
'''防回归:抓"定义了但从没被调用"的方法。
为什么值得单独一个测试:
1.7.0 交付后用户装上发现**一片白屏**。根因是
private void initTabs() { ... } // 定义在第 937 行
而 onCreate 里只调了 buildControlPanel(),**从头到尾没人调 initTabs()**。
结果 tabDefs 为 null -> selectTab() 直接 return -> 内容区空白。
这种错误编译能过、别的测试也能过,只有真机跑起来才看得见,
所以必须静态查出来。
判定方法:
统计方法名在文件里出现的次数(定义那一处也算)。
只出现 1 次 = 只有定义没调用。
分两档:
* **硬性失败**:关键路径上的方法(initTabs / 三个面板 / selectTab)。
这些漏了就是白屏或功能全无,必须拦住。
* **仅报告**:其它可疑方法。有些确实是历史遗留的死代码
(下面的 KNOWN_DEAD 记录了已确认的),有些是接口回调
(由框架调用,本文件里当然只有定义)。
报告出来供清理,但不拦构建 —— 免得噪音太大没人看。
'''
from __future__ import annotations
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
MAIN = (ROOT / "android" / "src" / "com" / "lanremote" / "watch"
/ "MainActivity.java")
# 框架/接口回调:由 Android 或 RemoteClient 调用,本文件里只有定义是正常的
WHITELIST = {
"onCreate", "onDestroy", "onResume", "onPause", "onStart", "onStop",
"onRestart", "onNewIntent", "onSaveInstanceState", "onRestoreInstanceState",
"onBackPressed", "onKeyDown", "onKeyUp", "onWindowFocusChanged",
"onRequestPermissionsResult", "onActivityResult", "onOptionsItemSelected",
"onCreateOptionsMenu", "onPrepareOptionsMenu", "onConfigurationChanged",
"onTouchEvent", "onClick", "onLongClick", "onTouch", "onAnimationUpdate",
"onAnimationStart", "onAnimationEnd", "onAnimationCancel", "onAnimationRepeat",
"onPreDraw", "onGlobalLayout", "onScrollChanged", "onItemClick",
"onItemSelected", "onNothingSelected", "onFocusChange", "onEditorAction",
"run", "call", "get", "set", "equals", "hashCode", "toString",
"uncaughtException", "afterTextChanged", "beforeTextChanged",
"onTextChanged", "onProgressChanged", "onStartTrackingTouch",
"onStopTrackingTouch", "onDateSet", "onTimeSet", "onDismiss",
"onCancel", "onShow", "onKey", "onCreateDialog", "onPrepareDialog",
"onReceive", "onServiceConnected", "onServiceDisconnected",
"onBind", "onCreateView", "onViewCreated", "onDestroyView",
"onAttach", "onDetach", "onActivityCreated", "onOptionsMenuClosed",
"onContextItemSelected", "onCreateContextMenu", "handleMessage",
"onChildViewAdded", "onChildViewRemoved", "onGlobalFocusChanged",
"onLayoutChange", "onScrollStateChanged", "onScrolled",
"onPageStarted", "onPageFinished", "shouldOverrideUrlLoading",
"onReceivedError", "onDownloadStart", "onChildDraw",
# RemoteClient.Listener 的实现
"onDisconnected", "onEvent", "onFrame", "onProgress", "onLog",
}
# 已确认的历史遗留死代码:早期版本的实现,后来换成了别的写法,
# 函数留着但没人调。不影响功能,列出来是为了有朝一日清掉。
KNOWN_DEAD = {
"buildFeatureTab": "旧的分页构建方式,已被 renderGroups() 取代",
"pickFolder": "已被 pickFile() 取代",
"pickClipHistory": "功能已移到服务端注册表",
"confirmWallpaper": "功能已移到服务端注册表",
"confirmMonitor": "功能已移到服务端注册表",
"sendMedia": "已被 media() 取代",
"promptRun": "已被 runFeature() 取代",
"showInfo": "已被 feature_run 的 info 取代",
"findSavedToken": "旧的重连逻辑,已被 RelayTransport 取代",
"glassBackground": "旧的美化辅助函数,样式改成 glass() 后没人用了",
"sp": "旧的字号辅助,已被 dp() 取代",
}
# 关键路径:这些漏了就是白屏 / 功能全无,必须硬性拦住
CRITICAL = ("buildConnectPanel", "buildControlPanel", "initTabs",
"buildMirrorPanel", "buildLanPanel")
passed = 0
failed = 0
def check(name, ok, detail=""):
global passed, failed
if ok:
passed += 1
print(" [PASS] " + name)
else:
failed += 1
print(" [FAIL] " + name + " " + str(detail))
def defined_methods(text: str) -> list[str]:
pattern = re.compile(
r"(?:private|public|protected|static|final|\s)+"
r"[\w<>\[\],.\s]+\s+(\w+)\s*\([^)]*\)\s*(?:throws [\w.,\s]+)?\{")
names = []
for match in pattern.finditer(text):
name = match.group(1)
if name in ("if", "for", "while", "switch", "catch", "synchronized",
"try", "return", "new"):
continue
names.append(name)
return names
def main() -> int:
check("MainActivity.java 在", MAIN.is_file())
if not MAIN.is_file():
return 1
text = MAIN.read_text(encoding="utf-8")
print()
print("一、关键路径必须被调用(漏了就是白屏)")
# initTabs 专项:白屏的根因就是它
init_def = len(re.findall(r"private void initTabs\s*\(", text))
init_use = len(re.findall(r"\binitTabs\s*\(\s*\)", text))
check("initTabs() 有定义", init_def >= 1, f"定义 {init_def} 处")
check("initTabs() 被调用(否则连上后一片白屏)",
init_use >= 2, f"出现 {init_use} 次(1 次是定义,>1 才算被调用)")
check("initTabs() 紧跟 buildControlPanel()",
re.search(r"buildControlPanel\(\);\s*(?://[^\n]*\n\s*)*initTabs\(\);",
text) is not None,
"必须在 buildControlPanel() 之后立刻调用")
for method in CRITICAL:
n = len(re.findall(r"\b" + method + r"\s*\(", text))
check(f"{method}() 被调用", n > 1, f"出现 {n} 次")
print()
print("二、分页定义完整性")
tab_names = re.findall(r'new TabDef\("([^"]+)"', text)
check("定义了 10 个分页", len(tab_names) == 10, f"实际 {len(tab_names)} 个")
print(f" 分页: {' '.join(tab_names)}")
check("selectTab 有定义", "private void selectTab(" in text)
check("selectTab 被调用", len(re.findall(r"\bselectTab\s*\(", text)) > 1)
print()
print("三、未调用方法扫描")
names = defined_methods(text)
orphans = []
for name in sorted(set(names)):
if name in WHITELIST or name in KNOWN_DEAD:
continue
n = len(re.findall(r"\b" + re.escape(name) + r"\s*\(", text))
if n <= 1:
orphans.append((name, n))
check("没有**未知**的未调用方法", not orphans,
"\n ".join(f"{n}({c} 次)" for n, c in orphans)
if orphans else "")
if orphans:
print()
print(" 未知的未调用方法(可能是漏接的事件处理,也可能是新的死代码):")
for name, cnt in orphans:
print(f" {name} (出现 {cnt} 次)")
if KNOWN_DEAD:
print()
print(f" 已知死代码 {len(KNOWN_DEAD)} 个(不影响功能,待清理):")
for name, why in sorted(KNOWN_DEAD.items()):
still = len(re.findall(r"\b" + re.escape(name) + r"\s*\(", text))
mark = "" if still else " [已删除]"
print(f" {name}: {why}{mark}")
print()
print("=" * 58)
print(f"通过 {passed} 项,失败 {failed} 项")
return 0 if failed == 0 else 1
if __name__ == "__main__":
sys.exit(main())