# -*- coding: utf-8 -*- """配对码被占用时,在电脑上弹通知。 用户的要求: "如果一个设备设置了配对码 789113,另一个设备也想设置 789113, 那不可以,你就弹通知,说该配对码已被使用,请换一个配对码" 现状: 中转服务器**已经**会拒绝(返回 "这个配对码已经被另一台设备用了,换一个"), 被控端也抛了这个错误 —— 但只是写进日志,用户根本看不到。 而且主循环会当成网络错误一直重试,刷屏。 要做的: 1. 中转返回里加 codeTaken 标记(让客户端能精确识别,不靠匹配中文) 2. 被控端加 RelayCodeTaken 异常 3. 加 on_alert 回调 —— 服务器把它接到界面通知上 4. 主循环遇到冲突时:**弹一次通知就停下来等**,不要反复重试刷屏 用户换了配对码之后自动继续。 """ from __future__ import annotations import sys from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") RELAY_SERVER = ROOT / "relay" / "relay.py" RELAY_CLIENT = ROOT / "windows" / "lanremote" / "relay.py" SERVER = ROOT / "windows" / "lanremote" / "server.py" # ============ 1. 中转:返回加 codeTaken ============ SRV_OLD = ''' known = self.codes.get(code) if known and known != device_id: return {"ok": False, "error": "这个配对码已经被另一台设备用了,换一个"}''' SRV_NEW = ''' known = self.codes.get(code) if known and known != device_id: # codeTaken 让客户端能精确识别这种冲突, # 不用去匹配中文错误文案(文案一改就坏)。 self.log(f"配对码 {code} 已被 {known} 占用,拒绝 {device_id}") return {"ok": False, "codeTaken": True, "error": "该配对码已被使用,请换一个配对码"}''' # ============ 2. 被控端:异常类 ============ EXC_ANCHOR = '''class _AuthLost(Exception):''' EXC_NEW = '''class RelayCodeTaken(RelayError): """配对码被别的设备占了。 这**不是网络问题**,重试没用 —— 要等用户换一个配对码。 所以主循环遇到它不能当成普通错误一直重试(会刷屏), 而是弹一次通知然后停下等。 """ class _AuthLost(Exception):''' # ============ 3. 被控端:__init__ 加 on_alert ============ INIT_OLD = ''' def __init__(self, store, log=None, on_session=None) -> None: self.store = store self._log = log or (lambda _m: None) self._on_session = on_session''' INIT_NEW = ''' def __init__(self, store, log=None, on_session=None, on_alert=None) -> None: self.store = store self._log = log or (lambda _m: None) self._on_session = on_session # 出需要用户处理的事(比如配对码被占)时调这个,用来弹通知 self._on_alert = on_alert''' INIT2_OLD = ''' self.sessions_served = 0''' INIT2_NEW = ''' self.sessions_served = 0 # 配对码冲突的说明。非空表示现在卡在这,等用户换码。 self.code_conflict = "" self._alerted_code = ""''' # ============ 4. 被控端:_register 抛专用异常 ============ REG_OLD = ''' if not reply.get("ok"): raise RelayError(str(reply.get("error") or "登记被拒"))''' REG_NEW = ''' if not reply.get("ok"): message = str(reply.get("error") or "登记被拒") # 配对码被占:精确判断(服务端会带 codeTaken), # 兼容老服务端就匹配关键字。 if reply.get("codeTaken") or "已被" in message and "配对码" in message: raise RelayCodeTaken(message) raise RelayError(message) # 登记成功 -> 之前的冲突解除了 self.code_conflict = ""''' # ============ 5. 被控端:主循环处理冲突 ============ RUN_OLD = ''' except _AuthLost: self._log("中转说令牌失效,重新登记") self.token = "" time.sleep(1)''' RUN_NEW = ''' except _AuthLost: self._log("中转说令牌失效,重新登记") self.token = "" time.sleep(1) except RelayCodeTaken as exc: # 配对码被别的设备占了。这不是网络问题,重试没用。 # 弹一次通知,然后**停下来等用户换码**。 message = str(exc) or "该配对码已被使用,请换一个配对码" self.online = False self.token = "" self.last_error = message self.code_conflict = message current = self.store.pairing_code() if current != self._alerted_code: # 只在换了新码之后再弹,避免反复弹同一个码的通知 self._alerted_code = current self._log(f"配对码冲突:{message}") if self._on_alert: try: self._on_alert("配对码被占用", message) except Exception: # noqa: BLE001 pass # 等用户换码。每 5 秒看一次配对码变没变。 for _ in range(12): if not self._running: return time.sleep(0.5) if self.store.pairing_code() != current: self._log("配对码变了,重新登记") self._alerted_code = "" break continue''' # ============ 6. 被控端:status 里带上冲突信息 ============ STATUS_OLD = ''' "candidates": list(self.candidates),''' STATUS_NEW = ''' "candidates": list(self.candidates), "codeConflict": self.code_conflict,''' # ============ 7. 服务器:把 on_alert 接到界面通知 ============ WIRE_OLD = ''' self._relay = RelayLink(self.store, log=self._log, on_session=self.adopt_relay_socket)''' WIRE_NEW = ''' self._relay = RelayLink(self.store, log=self._log, on_session=self.adopt_relay_socket, on_alert=self._alert)''' def patch(path: Path, pairs, label: str) -> bool: text = path.read_text(encoding="utf-8") ok = True for old, new, tag in pairs: if old not in text: print(f" [{label}] [跳过] {tag} —— 锚点没找到") ok = False continue text = text.replace(old, new, 1) print(f" [{label}] {tag}") path.write_text(text, encoding="utf-8", newline="\n") return ok def main() -> int: ok = True ok &= patch(RELAY_SERVER, [(SRV_OLD, SRV_NEW, "冲突返回加 codeTaken")], "中转") ok &= patch(RELAY_CLIENT, [ (EXC_ANCHOR, EXC_NEW, "RelayCodeTaken 异常"), (INIT_OLD, INIT_NEW, "__init__ 加 on_alert"), (INIT2_OLD, INIT2_NEW, "__init__ 加冲突字段"), (REG_OLD, REG_NEW, "_register 抛专用异常"), (RUN_OLD, RUN_NEW, "主循环处理冲突"), (STATUS_OLD, STATUS_NEW, "status 带冲突信息"), ], "被控端") # 服务器:加 _alert 方法 + 接线 text = SERVER.read_text(encoding="utf-8") if WIRE_OLD in text: text = text.replace(WIRE_OLD, WIRE_NEW, 1) print(" [服务器] on_alert 接线") else: print(" [服务器] [跳过] 接线锚点没找到") ok = False alert_method = ''' def _alert(self, title: str, text: str) -> None: """给用户看的通知(配对码被占这类必须让人知道的事)。 走界面的通知,用户在电脑上能直接看到。 界面还没起来时退回写日志,至少不丢信息。 """ self._log(f"[需要处理] {title}:{text}") try: ui = getattr(self.actions, "ui", None) if ui is not None and hasattr(ui, "notify"): ui.notify(title, text) except Exception: # noqa: BLE001 pass def relay_status(self) -> dict:''' if "def _alert(" in text: print(" [服务器] 已经有 _alert") elif " def relay_status(self) -> dict:" in text: text = text.replace(" def relay_status(self) -> dict:", alert_method, 1) print(" [服务器] 加了 _alert 方法") else: print(" [服务器] [失败] 找不到 relay_status") ok = False SERVER.write_text(text, encoding="utf-8", newline="\n") import ast for label, path in (("中转", RELAY_SERVER), ("被控端", RELAY_CLIENT), ("服务器", SERVER)): try: ast.parse(path.read_text(encoding="utf-8")) print(f" {label} 语法 OK") except SyntaxError as exc: print(f" {label} 语法错误: {exc}") ok = False return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())