2.3.0:手表界面精简 + 播放器 + 鼠标重做

手表端
- 功能页从 10 个杂项精简到 7 个(屏幕/鼠标/媒体/文件/电脑/语音/电源)
- 删掉:游戏封锁、待办、掷骰子、抽奖、壁纸、显示器开关、定时关机、
  剪贴板历史、性能/磁盘/电量、文件夹浏览、教室限制等
- 改成显式列按钮,不再把电脑端所有功能组无脑铺到表盘
- 远程鼠标控制重做:滑动区 + 左键/滚轮/右键三按钮
  滚轮点按=中键、上下滑=滚动
- 新增视频/音乐播放器(手表本地播放):进度拖动、左右滑快进退10秒、
  点画面播放暂停、上一/下一、播完自动下一首

电脑端
- 新增 kill_all(结束所有进程),白名单保护系统关键进程和自身
- 新增 media_list / media_pull(播放器数据源)
  安全边界:只允许媒体目录,用 relative_to 判断,防同前缀兄弟目录绕过

中转站
- known_devices 从 ID 集合改成「设备ID -> 配对码」映射
- 修复:管理员改码后关机超过 6 小时,改码会被超时清理冲掉
- 老格式 state 文件平滑升级
This commit is contained in:
xmz7891
2026-10-18 11:39:14 +08:00
parent 1d368979aa
commit 2061f9525f
50 changed files with 13812 additions and 584 deletions
+143
View File
@@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
r'''定位"不稳定"到底在哪一段。
== 已经知道的 ==
从本机连 30 次 `https://yk.xxmxxs.top/v1/health`:
成功 25 / 30(**17% 失败**)
失败的那几次都是 TCP 连接阶段就卡住(14~19 秒)
成功的时候中位只要 0.2 秒
**这说明不是服务器慢,是"有时候连不上"。**
== 要区分三段 ==
我 → Cloudflare边缘 → Cloudflare内部 → 源站(<服务器IP>) → nginx → relay
可能的断点:
A. **我 → Cloudflare 边缘**(我这边的网络 / ISP / 到 CF 的线路)
B. **Cloudflare 边缘 → 源站**(CF 回源;源站在 AWS 东京/新加坡)
C. **源站内部**(nginx / relay)
怎么分:
* 直连 `<服务器IP>:443`(绕过 Cloudflare)—— 稳的话说明 C 没问题
* 连 `yk.xxmxxs.top:443`(走 Cloudflare)—— 不稳的话说明 A 或 B 有问题
* 再对比别的走 Cloudflare 的站(比如 cloudflare.com 自己)——
它也抖的话说明是 **A**(我这边到 CF 的网络)
**这一步很关键**:如果是 A,那"网站不稳定"里**有一部分是本地网络的问题**,
不是服务器的问题 —— 用户在学校用可能是完全不同的情况。
'''
from __future__ import annotations
import socket
import ssl
import statistics
import sys
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "_build"))
HOSTFILE = ROOT / "_build" / ".lightsail_host"
IP = HOSTFILE.read_text(encoding="utf-8").strip()
def probe(host, port=443, path="/", use_tls=True, timeout=8, host_hdr=None):
"""测一次。返回 (结果, TCP耗时, 总耗时, 说明)"""
t0 = time.perf_counter()
try:
s = socket.create_connection((host, port), timeout=timeout)
t_tcp = time.perf_counter() - t0
if use_tls:
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
s = ctx.wrap_socket(s, server_hostname=host_hdr or host)
hdr = (host_hdr or host).encode()
s.send(b"GET " + path.encode() + b" HTTP/1.1\r\nHost: " + hdr +
b"\r\nUser-Agent: probe\r\nConnection: close\r\n\r\n")
data = s.recv(300)
t_all = time.perf_counter() - t0
s.close()
code = data.split(b" ")[1].decode() if b" " in data else "?"
return ("ok", t_tcp, t_all, code)
except Exception as exc: # noqa: BLE001
return (type(exc).__name__, time.perf_counter() - t0, None,
str(exc)[:34])
def batch(label, **kw):
print(" ── %s ──" % label)
n = kw.pop("n", 15)
ok = 0
slow = []
fails = []
for i in range(n):
kind, tcp, total, note = probe(**kw)
if kind == "ok":
ok += 1
if tcp > 1.0:
slow.append((i + 1, tcp))
else:
fails.append((i + 1, kind, tcp, note))
print(" %d/%d 成功 失败 %d" % (ok, n, len(fails)))
if slow:
print(" 慢的:%s" % ", ".join("#%d=%.1fs" % x for x in slow))
if fails:
for i, kind, secs, note in fails[:6]:
print(" ✗ #%d %s %.1fs %s" % (i, kind, secs, note))
return ok, len(fails)
def main() -> int:
print("=" * 62)
print(" 定位不稳定在哪一段")
print("=" * 62)
print()
a = batch("A. 直连源站 IP(绕过 Cloudflare)",
host=IP, port=443, use_tls=False, path="/v1/health",
host_hdr="yk.xxmxxs.top", n=15)
print()
b = batch("B. 走域名(经 Cloudflare)",
host="yk.xxmxxs.top", port=443, path="/v1/health", n=15)
print()
c = batch("C. 对照:Cloudflare 自己的站",
host="cloudflare.com", port=443, path="/", n=15)
print()
d = batch("D. 对照:另一个大站(百度)",
host="www.baidu.com", port=443, path="/", n=15)
print()
print("=" * 62)
print(" 判读")
print("=" * 62)
print(" A=直连源站 B=经Cloudflare C/D=对照")
print(" A:%d失败 B:%d失败 C:%d失败 D:%d失败"
% (a[1], b[1], c[1], d[1]))
print()
if a[1] == 0 and b[1] > 0:
print(" → **源站没问题,问题在 Cloudflare 那一段**(或本地到 CF 的线路)")
if c[1] > 0 or d[1] > 0:
print(" 而且对照组也抖 → 更像是**本地网络到外网**的问题,")
print(" 不是我们服务器或 Cloudflare 的锅。")
else:
print(" 对照组稳定 → 说明是 **Cloudflare ↔ 源站回源**这一段。")
elif a[1] > 0:
print(" → **直连源站也会失败** —— 那问题可能在源站或本地网络")
if d[1] > 0:
print(" 但百度也抖 → 先怀疑**本地网络**(换个网络再测)")
else:
print(" → 这一轮没测出抖动,说明是**间歇性**的(多测几轮)")
return 0
if __name__ == "__main__":
sys.exit(main())