mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-19 08:20:44 +00:00
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:
+94
-27
@@ -60,7 +60,7 @@ from collections import deque
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
|
||||
VERSION = "2.2.0"
|
||||
VERSION = "2.3.0"
|
||||
|
||||
# ---------------- 参数(都能用环境变量覆盖)----------------
|
||||
|
||||
@@ -603,10 +603,23 @@ class Relay:
|
||||
self.retired: dict = {}
|
||||
# 是否允许新设备接入。False 时只有已登记过的 deviceId 能上线。
|
||||
self.allow_new = True
|
||||
# 设备历史名单(只有 deviceId,不含配对码)。
|
||||
# 设备历史:**deviceId -> 配对码**。
|
||||
#
|
||||
# 为什么是字典而不是集合(2.2.1 改):
|
||||
# 集合只能记住"这设备来过",记不住"它该用哪个码"。
|
||||
# 于是这条链会断:
|
||||
# ① 管理员在后台把码 111111 改成 222222
|
||||
# ② 那台电脑关机(或断网)超过 DEVICE_TTL(6 小时)
|
||||
# ③ snapshot() 把设备删了,孤儿的码 222222 也被清掉
|
||||
# ④ 电脑开机,报自己本地的旧码 111111
|
||||
# ⑤ 中转已经不记得改过码 -> 收下 111111
|
||||
# ⑥ **管理员的改码白做了**,手表手里是 222222,连不上
|
||||
# 把码记进历史后,步骤 ⑤ 会变成"你应该是 222222",
|
||||
# 并随 register() 的返回值告诉客户端,客户端写回本地设置。
|
||||
#
|
||||
# **超时清理绝不动它** —— 它是"这台设备曾经被允许过"的唯一凭证。
|
||||
# 详见 register() 里 known_device 的注释。
|
||||
self.known_devices: set = set()
|
||||
self.known_devices: dict = {}
|
||||
self.started = time.time()
|
||||
self.total_requests = 0
|
||||
self.state_file = DATA_DIR / "relay_state.json"
|
||||
@@ -621,11 +634,25 @@ class Relay:
|
||||
return
|
||||
# 是否允许新设备接入(重启不丢)
|
||||
self.allow_new = bool(raw.get("allowNew", True))
|
||||
# 恢复设备历史名单(重启不丢)
|
||||
for did in raw.get("knownDevices", []):
|
||||
did = str(did or "").strip()
|
||||
if did:
|
||||
self.known_devices.add(did)
|
||||
# 恢复设备历史(重启不丢)。
|
||||
#
|
||||
# ⚠ 兼容老格式:2.2.1 之前存的是**纯 ID 列表**
|
||||
# (`"knownDevices": ["abc", "def"]`),
|
||||
# 2.2.1 起是**字典**(`"knownDevices": {"abc": "123456"}`)。
|
||||
# 老格式加载时码记成空串 —— 表示"认识这台设备,但不知道它该用哪个码",
|
||||
# 下次它上报什么就用什么(跟改动之前的行为一致)。
|
||||
raw_known = raw.get("knownDevices") or {}
|
||||
if isinstance(raw_known, dict):
|
||||
for did, code in raw_known.items():
|
||||
did = str(did or "").strip()
|
||||
if did:
|
||||
self.known_devices[did] = str(code or "").strip()
|
||||
elif isinstance(raw_known, list):
|
||||
# 老格式:只有 ID
|
||||
for did in raw_known:
|
||||
did = str(did or "").strip()
|
||||
if did:
|
||||
self.known_devices[did] = ""
|
||||
for item in raw.get("codes", []):
|
||||
device_id = str(item.get("deviceId", ""))
|
||||
code = str(item.get("code", ""))
|
||||
@@ -639,8 +666,9 @@ class Relay:
|
||||
payload = {
|
||||
"allowNew": bool(self.allow_new),
|
||||
# 设备历史:超时清理不会删它,所以关掉接入开关后
|
||||
# 老设备第二天开机仍然能上线
|
||||
"knownDevices": sorted(self.known_devices),
|
||||
# 老设备第二天开机仍然能上线。
|
||||
# 2.2.1 起顺便记住"它该用哪个码",避免改码被超时清理冲掉。
|
||||
"knownDevices": dict(self.known_devices),
|
||||
"codes": [
|
||||
{"deviceId": did, "code": code}
|
||||
for code, did in sorted(self.codes.items())
|
||||
@@ -731,16 +759,45 @@ class Relay:
|
||||
"codeTaken": True,
|
||||
"error": "该配对码已被使用,请换一个配对码"}
|
||||
|
||||
# 这台设备以前配过码吗?
|
||||
old_code = None
|
||||
for existing_code, existing_device in self.codes.items():
|
||||
if existing_device == device_id:
|
||||
old_code = existing_code
|
||||
break
|
||||
# 这台设备该用哪个配对码?**三个来源,按可信度排**:
|
||||
#
|
||||
# ① known_devices[deviceId] —— 设备历史里记着的(最权威)
|
||||
# 管理员在后台改过码 -> set_device_code 会写进这里,
|
||||
# 所以哪怕设备超时被清理、关机过夜,改码也不会丢。
|
||||
# ② self.codes 里的现存绑定 —— 设备在线期间的有效映射
|
||||
# ③ 本次上报的 code —— 前两者都没有时就用它
|
||||
#
|
||||
# ⚠ 不能只看 ②:snapshot() 会把「设备不存在」的码当孤儿清掉,
|
||||
# 关机 >6 小时就必然触发 —— 那时 ② 是空的,改码就丢了。
|
||||
reported_code = str(body.get("code") or "").strip()
|
||||
authoritative = (self.known_devices.get(device_id) or "").strip()
|
||||
if not authoritative:
|
||||
for existing_code, existing_device in self.codes.items():
|
||||
if existing_device == device_id:
|
||||
authoritative = existing_code
|
||||
break
|
||||
if not authoritative:
|
||||
authoritative = reported_code
|
||||
|
||||
if old_code and old_code != code:
|
||||
log(f"设备 {name} 报了新码 {code},按单设备单码制改回 {old_code}")
|
||||
code = old_code
|
||||
# 权威码要是被**别的**设备占着,就不能硬用(否则两台设备抢一个码)。
|
||||
# 这种情况只在"管理员改码后、旧码又被别的设备抢注"时出现,
|
||||
# 属于异常,以本次上报为准,并留一条日志方便排查。
|
||||
owner = self.codes.get(authoritative)
|
||||
if owner and owner != device_id:
|
||||
log(f"设备 {name} 的历史码 {authoritative} 已被 {owner} 占用,"
|
||||
f"改用本次上报的 {reported_code}")
|
||||
authoritative = reported_code
|
||||
# 重新检查上报的码有没有冲突(上面 known 已经查过,
|
||||
# 但 authoritative 换成 reported_code 后要再确认一次)
|
||||
owner2 = self.codes.get(authoritative)
|
||||
if owner2 and owner2 != device_id:
|
||||
return {"ok": False, "codeTaken": True,
|
||||
"error": "该配对码已被使用,请换一个配对码"}
|
||||
|
||||
code = authoritative
|
||||
if code != reported_code:
|
||||
log(f"设备 {name} 报了码 {reported_code},"
|
||||
f"按单设备单码制用回 {code}")
|
||||
|
||||
self.codes[code] = device_id
|
||||
device = self.devices.get(device_id)
|
||||
@@ -753,9 +810,10 @@ class Relay:
|
||||
device.version = version
|
||||
device.token = secrets.token_hex(24)
|
||||
device.last_seen = time.time()
|
||||
# 记进设备历史名单(这是"曾经被允许过"的凭证,只增不减;
|
||||
# 只有管理员显式删除设备时才会被移除)
|
||||
self.known_devices.add(device_id)
|
||||
# 记进设备历史:deviceId -> 权威码。
|
||||
# 这是"曾经被允许过"的凭证,也顺带记住它该用哪个码。
|
||||
# **只有管理员显式删除设备/抹码时才会被移除或清空。**
|
||||
self.known_devices[device_id] = code
|
||||
# 每次登记都刷新局域网信息(IP 可能变,端口也可能改)
|
||||
device.lan_ips = lan_ips
|
||||
device.port = listen_port
|
||||
@@ -763,8 +821,8 @@ class Relay:
|
||||
log(f"被控端上线:{name} 码 {code} ({device_id[:12]}…)")
|
||||
|
||||
note = ""
|
||||
if old_code and old_code != str(body.get("code") or "").strip():
|
||||
note = (f"这台设备之前设过配对码 {old_code},"
|
||||
if code != reported_code:
|
||||
note = (f"这台设备之前设过配对码 {code},"
|
||||
f"已按「单设备单配对码」沿用它")
|
||||
return {"ok": True, "token": device.token, "code": code,
|
||||
"note": note, "pollSeconds": POLL_SECONDS}
|
||||
@@ -814,6 +872,10 @@ class Relay:
|
||||
self.codes.pop(code, None)
|
||||
self.codes[new_code] = device_id
|
||||
device.code = new_code
|
||||
# ⚠ 设备历史里记的码也要同步更新 ——
|
||||
# 否则设备关机 >6 小时被清理后重新登记时,
|
||||
# register() 会拿历史里的**旧码**把它改回去,改码就白做了。
|
||||
self.known_devices[device_id] = new_code
|
||||
|
||||
# 会话绑在码上,旧会话作废,让手表重新配对。
|
||||
#
|
||||
@@ -1144,7 +1206,7 @@ class Relay:
|
||||
# "删除设备"是**真正忘记这台设备** —— 连历史名单一起删。
|
||||
# 不删的话,管理员点了删除、开关又关着,
|
||||
# 那台设备下次来仍然被当成老设备放行,开关就形同虚设。
|
||||
self.known_devices.discard(target.device_id)
|
||||
self.known_devices.pop(target.device_id, None)
|
||||
# 把它的码绑定一起删掉
|
||||
gone_codes = [c for c, owner in list(self.codes.items())
|
||||
if owner == target.device_id]
|
||||
@@ -1169,8 +1231,10 @@ class Relay:
|
||||
def forget(self, code: str) -> bool:
|
||||
"""抹掉一个配对码绑定(让那台设备下次可以设新码)。
|
||||
|
||||
注意:**只抹码,不抹设备历史**。
|
||||
抹码的语义是"这个码我不占了",不是"我不认识这台设备了"。
|
||||
注意:**只抹码,不抹设备历史** ——
|
||||
设备仍然是"认识的"(关了接入开关也能上线),
|
||||
但**码要忘掉**,否则 register() 会把历史里的旧码又塞回去,
|
||||
"抹码"就白做了。
|
||||
"""
|
||||
with self.lock:
|
||||
device_id = self.codes.pop(code, None)
|
||||
@@ -1179,6 +1243,9 @@ class Relay:
|
||||
device = self.devices.get(device_id)
|
||||
if device is not None:
|
||||
self.devices.pop(device_id, None)
|
||||
# 把历史里记的码清空(但保留设备 ID —— 设备还是认识的)
|
||||
if device_id in self.known_devices:
|
||||
self.known_devices[device_id] = ""
|
||||
self._save()
|
||||
return True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user