# -*- coding: utf-8 -*- r'''单次请求失败不再立刻判"离线",改成连续失败 3 次才算。 == 为什么 == 实测单个请求会有 2~4% 的偶发失败(4G 丢包打在一条隧道连接上, 或者那条连接正在重连)。原来的逻辑是**一失败就 online = false**, 于是: 手表/电脑的界面上会闪一下"已断开" 用户点按钮时正好撞上那一闪 -> 看起来像"又连不上了" 而实际上链路 1.5~15 秒后就自己恢复了(客户端本来就有退避重试)。 改成"连续失败 3 次才判离线",效果是: * 单次抖动完全不影响界面显示 * 真的断了(连续 3 次,至少 4.5 秒都没通)仍然会如实显示离线 这不是掩盖问题,而是把"是否可用"的判断从"一次采样"改成 "连续采样"—— 单点采样在有丢包的链路上噪声太大。 == 两边都要改 == 1. android/src/com/lanremote/watch/RelayTransport.java (手表轮询) 2. windows/lanremote/relay.py (电脑轮询) ''' from __future__ import annotations import sys from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") BOM = b"\xef\xbb\xbf" # ---------------------------------------------------------------- 手表 WATCH = ROOT / "android/src/com/lanremote/watch/RelayTransport.java" WATCH_CONST_OLD = " private static final int RETRY_MAX_MS = 15000;" WATCH_CONST_NEW = """ private static final int RETRY_MAX_MS = 15000; /** * 连续失败几次才判定"离线"。 * *

单次失败就报离线太敏感:4G 链路上随手就有 2~4% 的偶发失败, * 而链路通常一两秒就自己恢复,界面却已经闪了一下"已断开"。 * 改成连续 3 次(至少 4.5 秒都不通)才判离线 —— * 真的断了仍然会如实显示。 */ private static final int OFFLINE_AFTER = 3;""" WATCH_FIELD_OLD = " private Thread pollThread;" WATCH_FIELD_NEW = """ private Thread pollThread; /** 连续失败次数(成功一次就清零)。 */ private volatile int failStreak;""" # 401/403 分支 W_401_OLD = """ if (result.code == 401 || result.code == 403) { // 会话过期(中转重启等)—— 这种可以自动重连 online = false; lastError = "会话已失效,正在重新接入";""" W_401_NEW = """ if (result.code == 401 || result.code == 403) { // 会话过期(中转重启等)—— 这种可以自动重连。 // 会话失效是明确的状态,直接标离线。 online = false; lastError = "会话已失效,正在重新接入";""" # 非 200 分支 W_OTHER_OLD = """ if (result.code != 200) { online = false; lastError = "轮询返回 " + result.code; sleep(backoff); backoff = Math.min(RETRY_MAX_MS, backoff * 2); continue; } online = true; lastError = ""; backoff = RETRY_MIN_MS;""" W_OTHER_NEW = """ if (result.code != 200) { // 偶发的 502/504 不算断线,连续几次才算 failStreak++; if (failStreak >= OFFLINE_AFTER) { online = false; } lastError = "轮询返回 " + result.code; sleep(backoff); backoff = Math.min(RETRY_MAX_MS, backoff * 2); continue; } online = true; failStreak = 0; lastError = ""; backoff = RETRY_MIN_MS;""" # 异常分支 W_EXC_OLD = """ } catch (Exception exc) { if (closed) { return; } online = false; lastError = "轮询出错:" + exc.getClass().getSimpleName(); sleep(backoff); backoff = Math.min(RETRY_MAX_MS, backoff * 2); }""" W_EXC_NEW = """ } catch (Exception exc) { if (closed) { return; } // 连接超时/重置很常见(隧道在重连),连续几次才算真断 failStreak++; if (failStreak >= OFFLINE_AFTER) { online = false; } lastError = "轮询出错:" + exc.getClass().getSimpleName(); sleep(backoff); backoff = Math.min(RETRY_MAX_MS, backoff * 2); }""" # ---------------------------------------------------------------- 电脑 AGENT = ROOT / "windows/lanremote/relay.py" A_CONST_OLD = "RETRY_MAX = 20.0" A_CONST_NEW = """RETRY_MAX = 20.0 # 连续失败几次才判定"离线"。 # 单次失败就报离线太敏感:4G 链路上有 2~4% 的偶发失败, # 而链路通常一两秒就自己恢复,界面却已经闪了一下"已断开"。 # 连续 3 次(至少 6 秒都不通)才判离线,真的断了仍然如实显示。 OFFLINE_AFTER = 3""" A_FAIL_OLD = """ except Exception as exc: # noqa: BLE001 self.online = False self.last_error = f"{type(exc).__name__}: {exc}" self._log(f"中转连接出问题:{self.last_error}")""" A_FAIL_NEW = """ except Exception as exc: # noqa: BLE001 # 偶发的连接超时/重置不算断线,连续几次才算 self._fail_streak = getattr(self, "_fail_streak", 0) + 1 if self._fail_streak >= OFFLINE_AFTER: self.online = False self.last_error = f"{type(exc).__name__}: {exc}" self._log(f"中转连接出问题(第 {self._fail_streak} 次):" f"{self.last_error}")""" A_OK_OLD = """ self.online = True self.last_ok = time.time() self.last_error = \"\"""" A_OK_NEW = """ self.online = True self._fail_streak = 0 self.last_ok = time.time() self.last_error = \"\"""" def patch(text: str, old: str, new: str, label: str) -> tuple: if old not in text: if new.strip() and new.splitlines()[-1].strip() in text: print(" • %s 已经是新值" % label) return text, True print(" ✗ 没找到:%s" % label) return text, False if text.count(old) != 1: print(" ! 出现 %d 次:%s" % (text.count(old), label)) return text, False print(" ✓ %s" % label) return text.replace(old, new, 1), True def main() -> int: ok_all = True print(" 手表 RelayTransport.java:") raw = WATCH.read_bytes() text = raw.decode("utf-8-sig") for old, new, label in ( (WATCH_CONST_OLD, WATCH_CONST_NEW, "加 OFFLINE_AFTER 常量"), (WATCH_FIELD_OLD, WATCH_FIELD_NEW, "加 failStreak 字段"), (W_OTHER_OLD, W_OTHER_NEW, "非 200 用连续计数"), (W_EXC_OLD, W_EXC_NEW, "异常用连续计数"), ): text, ok = patch(text, old, new, label) ok_all = ok_all and ok if ok_all: WATCH.write_text(text, encoding="utf-8", newline="\n") print() print(" 电脑 relay.py:") araw = AGENT.read_bytes() atext = araw.decode("utf-8-sig") for old, new, label in ( (A_CONST_OLD, A_CONST_NEW, "加 OFFLINE_AFTER 常量"), (A_FAIL_OLD, A_FAIL_NEW, "异常用连续计数"), (A_OK_OLD, A_OK_NEW, "成功时清零"), ): atext, ok = patch(atext, old, new, label) ok_all = ok_all and ok if not ok_all: print() print(" 有失败项,没写回电脑端") return 1 AGENT.write_text(atext, encoding="utf-8", newline="\n") print() print(" 两边都改好了") return 0 if __name__ == "__main__": sys.exit(main())