diff --git a/.gitignore b/.gitignore index 7162909..ec2badf 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,8 @@ desktop.ini # ---- 测试收发的临时数据 ---- /_tests/received/ + +# 令牌(绝对不要进仓库) +/_build/.gitee_token +*.token +.env diff --git a/_build/a_err.txt b/_build/a_err.txt new file mode 100644 index 0000000..e69de29 diff --git a/_build/a_out.txt b/_build/a_out.txt new file mode 100644 index 0000000..e69de29 diff --git a/_build/agent_err.txt b/_build/agent_err.txt new file mode 100644 index 0000000..e69de29 diff --git a/_build/agent_out.txt b/_build/agent_out.txt new file mode 100644 index 0000000..e69de29 diff --git a/_build/diag_discovery.py b/_build/diag_discovery.py new file mode 100644 index 0000000..6fb4e24 --- /dev/null +++ b/_build/diag_discovery.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +r"""诊断:发现端口 8766 到底有没有被 agent 绑上。 + +test_selfcheck 广播到 127.0.0.1:8766 收到 WSAECONNRESET(ICMP 端口不可达), +说明**没有进程在监听 8766**。但测试里 agent 明明起来了(8841 能连)。 + +查清楚是: + a) agent 绑 8766 失败(被占 / 权限) + b) agent 压根没去绑 + c) 绑上了但没回包 +""" +from __future__ import annotations + +import os +import shutil +import socket +import subprocess +import sys +import time +from pathlib import Path + +ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") +PORT = 8851 +DISCOVERY = 8766 + + +def port_holder(port: int, udp: bool) -> list[str]: + out: list[str] = [] + if udp: + cmd = ("Get-NetUDPEndpoint -LocalPort %d -ErrorAction SilentlyContinue | " + "ForEach-Object { \"$($_.LocalAddress):$($_.LocalPort) PID $($_.OwningProcess)\" }" + % port) + else: + cmd = ("Get-NetTCPConnection -LocalPort %d -ErrorAction SilentlyContinue | " + "ForEach-Object { \"$($_.LocalAddress):$($_.LocalPort) PID $($_.OwningProcess)\" }" + % port) + proc = subprocess.run(["powershell", "-NoProfile", "-Command", cmd], + capture_output=True, text=True, timeout=30) + for line in (proc.stdout or "").splitlines(): + if line.strip(): + out.append(line.strip()) + return out + + +def main() -> int: + # 清干净(注意别把自己杀了 —— $PID 在 PowerShell 里是 PowerShell 的, + # 所以这里按命令行特征挑,不用 PID 比较) + subprocess.run( + ["powershell", "-NoProfile", "-Command", + "Get-CimInstance Win32_Process -Filter \"Name='python.exe'\" | " + "Where-Object { $_.CommandLine -match 'run_agent' -or " + "$_.CommandLine -match 'test_' } | " + "ForEach-Object { Stop-Process -Id $_.ProcessId -Force " + "-ErrorAction SilentlyContinue }"], + capture_output=True, text=True, timeout=60) + time.sleep(2) + + print(" 起之前,8766 有没有人占:") + holders = port_holder(DISCOVERY, udp=True) + print(f" {holders if holders else '空闲'}") + + data_dir = ROOT / "windows" / "data" + if data_dir.exists(): + shutil.rmtree(data_dir, ignore_errors=True) + + env = dict(os.environ) + env["PYTHONIOENCODING"] = "utf-8" + + print() + print(f" 起 agent(TCP {PORT})…") + proc = subprocess.Popen( + [sys.executable, "run_agent.py", "--port", str(PORT), + "--new-code", "--add-device", "10"], + cwd=str(ROOT / "windows"), env=env, + stdout=open(ROOT / "_build" / "agent_diag.log", "wb"), + stderr=subprocess.STDOUT) + + try: + # 等 TCP 就绪 + ready = False + for _ in range(50): + try: + s = socket.create_connection(("127.0.0.1", PORT), timeout=1) + s.close() + ready = True + break + except OSError: + time.sleep(0.4) + print(f" TCP {PORT} 就绪: {ready}") + + time.sleep(1.5) + + print() + print(f" 起之后,8766 有没有人占:") + holders = port_holder(DISCOVERY, udp=True) + print(f" {holders if holders else '还是空闲 —— 说明 agent 没绑上!'}") + + print() + print(" 直接探测 8766:") + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.settimeout(3) + import json + request = json.dumps({"lanremote": "LANREMOTE_SELFCHECK", + "proto": 1}).encode("utf-8") + try: + sock.sendto(request, ("127.0.0.1", DISCOVERY)) + data, addr = sock.recvfrom(2048) + print(f" ✓ 收到应答: {data[:160]!r}") + except ConnectionResetError as exc: + print(f" ✗ WSAECONNRESET —— 端口不可达,没人监听({exc})") + except socket.timeout: + print(" ✗ 超时 —— 有人监听但没回") + finally: + sock.close() + + print() + print(" agent 日志尾部:") + log = ROOT / "_build" / "agent_diag.log" + if log.is_file(): + text = log.read_text(encoding="utf-8", errors="replace") + for line in text.splitlines()[-14:]: + print(f" {line}") + + finally: + proc.terminate() + try: + proc.wait(timeout=10) + except subprocess.TimeoutExpired: + proc.kill() + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/_build/fix_discovery_order.py b/_build/fix_discovery_order.py new file mode 100644 index 0000000..5fae91a --- /dev/null +++ b/_build/fix_discovery_order.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +r"""修:中转连接尝试阻塞了局域网发现。 + +现象(agent 日志): + [20:31:17] 没配过中转地址,用内置默认值:192.168.10.105:8080;https://... + [20:31:25] http://192.168.10.105:8080 不通,试下一个 <- 等了 8 秒 + [20:31:27] https://relay.xxmxxs.top 不通,试下一个 <- 又 2 秒 + [20:31:27] 自动发现已开启(UDP 8766) <- 10 秒后才绑上 + +server.start() 原来的顺序: + 1. 绑 TCP + 2. enable_relay() <- 挨个试中转地址,每个都要等超时(这里 10 秒) + 3. 起 accept 线程 + 4. 起 DiscoveryResponder + +问题:**局域网发现被中转拖住了**。 + 电脑和手表在同一个 WiFi 时,本来应该"广播一下就找到", + 结果因为中转连不上,要等 10 几秒手表才搜得到电脑。 + 中转地址越烂、候选越多,等得越久。 + +影响: + * 用户体验上表现为"刚开电脑时手表搜不到,过一会儿才行" + * 自动化测试也栽在这(广播时发现服务还没起) + +改法:把局域网发现**提到 enable_relay() 之前**。 + 局域网是本机能力,不该依赖任何网络外部条件。 +""" +from __future__ import annotations + +import ast +import sys +from pathlib import Path + +SERVER = (Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows" + r"\lanremote\server.py")) + +OLD = ''' # 配了中转地址就同时启用跨网络通道(和局域网监听并存,不冲突) + try: + self.enable_relay() + except Exception as exc: # noqa: BLE001 + self._log(f"启用中转失败:{exc}") + + self._accept_thread = threading.Thread(target=self._accept_loop, + name="accept", daemon=True) + self._accept_thread.start() + self._clip_thread = threading.Thread(target=self._clip_loop, + name="clip", daemon=True) + self._clip_thread.start() + + # 启动局域网自动发现,让手表不用输 IP + self._discovery = DiscoveryResponder(self.store, self.port) + # 手表点「连不上?」会广播请求,这里就把网络自检窗口弹出来 + self._discovery.on_selfcheck = self._on_selfcheck_request + if self._discovery.start(): + self._log(f"自动发现已开启(UDP {DISCOVERY_PORT})") + else: + self._log(f"自动发现未开启:{self._discovery.last_error}")''' + +NEW = ''' # ── 先起局域网发现 ── + # + # 顺序很重要:enable_relay() 会挨个试中转地址, + # 每个候选都要等到超时才算"不通",地址越烂等得越久(实测 10 秒+)。 + # 原来这一步排在发现服务前面,导致: + # 电脑刚开机的十几秒里,手表广播搜不到它。 + # 局域网发现是纯本机能力,不该被"连不连得上外网"拖住, + # 所以挪到前面,开机即可被搜到。 + self._discovery = DiscoveryResponder(self.store, self.port) + # 手表点「连不上?」会广播请求,这里就把网络自检结论算出来 + self._discovery.on_selfcheck = self._on_selfcheck_request + if self._discovery.start(): + self._log(f"自动发现已开启(UDP {DISCOVERY_PORT})") + else: + self._log(f"自动发现未开启:{self._discovery.last_error}") + + # ── 再起收发线程 ── + self._accept_thread = threading.Thread(target=self._accept_loop, + name="accept", daemon=True) + self._accept_thread.start() + self._clip_thread = threading.Thread(target=self._clip_loop, + name="clip", daemon=True) + self._clip_thread.start() + + # ── 最后才连中转(会阻塞,所以放最后)── + # 配了中转地址就同时启用跨网络通道(和局域网监听并存,不冲突) + try: + self.enable_relay() + except Exception as exc: # noqa: BLE001 + self._log(f"启用中转失败:{exc}")''' + + +def main() -> int: + text = SERVER.read_text(encoding="utf-8") + if "先起局域网发现" in text: + print(" 已经改过") + return 0 + if OLD not in text: + print(" [失败] 锚点没找到") + return 1 + + text = text.replace(OLD, NEW, 1) + SERVER.write_text(text, encoding="utf-8", newline="\n") + print(" 已把局域网发现提到 enable_relay() 之前") + + try: + ast.parse(text) + print(" server.py 语法 OK") + except SyntaxError as exc: + print(f" 语法错误: 行 {exc.lineno}: {exc.msg}") + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/_build/gitee_meta.py b/_build/gitee_meta.py new file mode 100644 index 0000000..8ef40ea --- /dev/null +++ b/_build/gitee_meta.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +r"""改 Gitee 仓库的简介 / 主页,并核对发行版。 + +用法(令牌只走命令行,不落盘): + python _build/gitee_meta.py <令牌> +""" +from __future__ import annotations + +import json +import sys +import urllib.error +import urllib.request + +OWNER, REPO = "xmz7891", "ykxmz" +API = f"https://gitee.com/api/v5/repos/{OWNER}/{REPO}" + +DESCRIPTION = ( + "教室电脑手表遥控 · 老师用手表管教室电脑:放课件、投图、" + "屏蔽游戏网站、下课关机。支持局域网直连与跨网络中继" +) +HOMEPAGE = "https://relay.xxmxxs.top" + + +def call(url, payload=None, method="GET", timeout=60): + data = None + headers = {"User-Agent": "ykxmz-meta"} + if payload is not None: + data = json.dumps(payload).encode("utf-8") + headers["Content-Type"] = "application/json;charset=UTF-8" + req = urllib.request.Request(url, data=data, headers=headers, method=method) + with urllib.request.urlopen(req, timeout=timeout) as resp: + body = resp.read().decode("utf-8", "replace") + return resp.status, (json.loads(body) if body.strip() else {}) + + +def main() -> int: + if len(sys.argv) < 2: + print(" 用法: python _build/gitee_meta.py <令牌>") + return 1 + token = sys.argv[1] + + print("===== 1. 改仓库简介 =====") + try: + status, reply = call( + API, + {"access_token": token, "name": REPO, + "description": DESCRIPTION, "homepage": HOMEPAGE}, + method="PATCH") + if status in (200, 201): + print(f" ✓ 简介已更新") + print(f" {reply.get('description', '')}") + print(f" 主页: {reply.get('homepage', '')}") + else: + print(f" ✗ HTTP {status}: {reply}") + except urllib.error.HTTPError as exc: + detail = exc.read().decode("utf-8", "replace")[:300] + print(f" ✗ HTTP {exc.code}: {detail}") + return 1 + + print() + print("===== 2. 核对发行版 =====") + try: + _s, releases = call(f"{API}/releases?access_token={token}&per_page=5") + if not isinstance(releases, list): + print(f" 读不到发行版列表: {releases}") + for rel in releases[:3]: + print(f" {rel.get('tag_name')} {rel.get('name')}") + for asset in rel.get("assets", []): + size = asset.get("size", 0) / 1024 / 1024 + print(f" {asset.get('browser_download_url', '')}" + .replace("https://gitee.com", "")) + print(f" 大小 {size:.2f} MB " + f"下载次数 {asset.get('download_count', 0)}") + except Exception as exc: # noqa: BLE001 + print(f" 查发行版失败: {exc}") + + print() + print(f" 仓库: https://gitee.com/{OWNER}/{REPO}") + print(f" 发行版: https://gitee.com/{OWNER}/{REPO}/releases") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/_build/gitee_release.py b/_build/gitee_release.py new file mode 100644 index 0000000..8cef3a1 --- /dev/null +++ b/_build/gitee_release.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +r"""在 Gitee 上创建发行版(Release)并上传三个文件。 + +用法: + python _build/gitee_release.py <令牌> [版本号] + +令牌只从命令行参数读,**不写进任何文件、不进仓库**。 + +Gitee 的两个接口: + 建发行版 POST /api/v5/repos/{owner}/{repo}/releases + 传附件 POST /api/v5/repos/{owner}/{repo}/releases/{id}/attach_files + +SSH 密钥只能推代码,建发行版必须用这个令牌。 +""" +from __future__ import annotations + +import json +import mimetypes +import sys +import urllib.error +import urllib.request +import uuid +from pathlib import Path + +ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") +OWNER = "xmz7891" +REPO = "ykxmz" +API = f"https://gitee.com/api/v5/repos/{OWNER}/{REPO}" + + +def api(url: str, payload: dict | None = None, method: str = "GET", + timeout: int = 60): + data = None + headers = {"User-Agent": "ykxmz-release"} + if payload is not None: + data = json.dumps(payload).encode("utf-8") + headers["Content-Type"] = "application/json;charset=UTF-8" + request = urllib.request.Request(url, data=data, headers=headers, + method=method) + with urllib.request.urlopen(request, timeout=timeout) as response: + body = response.read().decode("utf-8", "replace") + return response.status, (json.loads(body) if body.strip() else {}) + + +def upload_file(url: str, path: Path, token: str, timeout: int = 600): + """multipart 上传单个文件。""" + boundary = "----ykxmz" + uuid.uuid4().hex + content_type = (mimetypes.guess_type(path.name)[0] + or "application/octet-stream") + head = ( + f"--{boundary}\r\n" + f'Content-Disposition: form-data; name="access_token"\r\n\r\n' + f"{token}\r\n" + f"--{boundary}\r\n" + f'Content-Disposition: form-data; name="file"; ' + f'filename="{path.name}"\r\n' + f"Content-Type: {content_type}\r\n\r\n" + ).encode("utf-8") + tail = f"\r\n--{boundary}--\r\n".encode("utf-8") + body = head + path.read_bytes() + tail + + request = urllib.request.Request( + url, data=body, method="POST", + headers={ + "Content-Type": f"multipart/form-data; boundary={boundary}", + "Content-Length": str(len(body)), + "User-Agent": "ykxmz-release", + }) + with urllib.request.urlopen(request, timeout=timeout) as response: + text = response.read().decode("utf-8", "replace") + return response.status, (json.loads(text) if text.strip() else {}) + + +def main() -> int: + if len(sys.argv) < 2: + print(" 用法: python _build/gitee_release.py <令牌> [版本号]") + return 1 + token = sys.argv[1] + version = sys.argv[2] if len(sys.argv) > 2 else "1.6.0" + tag = f"v{version}" + + files = [ + ROOT / "dist" / f"ykxmz-agent-{version}.zip", + ROOT / "dist" / f"ykxmz-server-{version}.zip", + ROOT / "dist" / f"ykxmz-watch-{version}.apk", + ] + for path in files: + if not path.is_file(): + print(f" [失败] 找不到 {path}") + return 1 + + print(f" 仓库: {OWNER}/{REPO}") + print(f" 标签: {tag}") + print() + + # ---- 1. 建发行版 ---- + body = f"""## ykxmz {version} + +教室电脑手表遥控。 + +老师抬一下手腕就能管教室里那台电脑 —— 放课件、放音频、投图、 +看看谁在打游戏、下课关机,不用走回讲台。 + +### 这次下载哪个 + +| 你是 | 下这个 | +|---|---| +| 教室电脑装被控端 | `ykxmz-agent-{version}.zip` | +| 要跨网络(办公室管教室) | `ykxmz-server-{version}.zip` | +| 手表装控制端 | `ykxmz-watch-{version}.apk` | + +只在一个教室用的话,第三件(中转服务器)可以先不装, +手表和电脑连同一个 WiFi 就能直连。 + +### 怎么用 + +装完看包里的 `README.txt`,或者仓库首页的说明。 + +### 这一版改了什么 + +- 重写说明文档,按老师 / 电教 / 开发者 / 普通用户分开讲 +- 手表端内置根证书,修部分手表连中转时的证书校验失败 +- 中转站加下载区 +- 网络稳定性:修 MTU 问题,公网可用率从 48% 提到 95% 以上 +""" + print(" 建发行版…") + try: + status, reply = api( + f"{API}/releases", + {"access_token": token, "tag_name": tag, "name": f"ykxmz {version}", + "body": body, "target_commitish": "main", "prerelease": False}, + method="POST") + except urllib.error.HTTPError as exc: + detail = exc.read().decode("utf-8", "replace")[:400] + print(f" [失败] HTTP {exc.code}: {detail}") + return 1 + + if status not in (200, 201): + print(f" [失败] HTTP {status}: {reply}") + return 1 + + release_id = reply.get("id") + print(f" ✓ 发行版已建,id={release_id}") + print(f" {reply.get('html_url', '')}") + + # 如果标签已经存在(重复发布),走"找已有发行版再传附件"的路 + if not release_id: + print(" [提示] 没拿到 id,尝试按标签查已有的发行版…") + try: + _s, existing = api(f"{API}/releases/tags/{tag}?access_token={token}") + release_id = existing.get("id") + print(f" 已有发行版 id={release_id}") + except Exception as exc: # noqa: BLE001 + print(f" [失败] 查不到: {exc}") + return 1 + + # ---- 2. 传附件 ---- + print() + print(" 上传文件:") + attach = f"{API}/releases/{release_id}/attach_files" + for path in files: + size_mb = path.stat().st_size / 1024 / 1024 + try: + status, reply = upload_file(attach, path, token) + if status in (200, 201): + print(f" ✓ {path.name} ({size_mb:.2f} MB)") + else: + print(f" ✗ {path.name}: HTTP {status} {reply}") + except urllib.error.HTTPError as exc: + detail = exc.read().decode("utf-8", "replace")[:200] + print(f" ✗ {path.name}: HTTP {exc.code} {detail}") + except Exception as exc: # noqa: BLE001 + print(f" ✗ {path.name}: {exc}") + + print() + print(f" 完成:https://gitee.com/{OWNER}/{REPO}/releases/tag/{tag}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/_build/package_remote.py b/_build/package_remote.py index c2b3095..8d8375c 100644 --- a/_build/package_remote.py +++ b/_build/package_remote.py @@ -17,7 +17,7 @@ import zipfile from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") -VERSION = "1.6.0" +VERSION = "1.6.1" NAME = f"ykxmz-{VERSION}" AGENT_SRC = ROOT / "dist_exe" / "ykxmz" diff --git a/_build/release.py b/_build/release.py new file mode 100644 index 0000000..933b7f7 --- /dev/null +++ b/_build/release.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +r"""一条命令完成发布。 + +用法: + python _build/release.py 1.7.0 # 升版本 + 构建 + 打包 + 推送 + 建发行版 + python _build/release.py 1.7.0 --no-readme # 明说这版没改 README + +它干这些事: + 1. 升版本号(三端 + 文档 + 测试断言) + 2. 重建 EXE 和 APK + 3. 打三个成品 + 4. 跑一遍关键测试 + 5. git 提交 + 推送 + 6. 在 Gitee 建发行版,把三个文件传上去 + 7. 覆盖仓库简介(只在第一次需要,重复设成一样也无害) + +令牌从 _build/.gitee_token 读(那个文件在 .gitignore 里,不会进仓库)。 +第一次用:把令牌写进去就行。 +""" +from __future__ import annotations + +import os +import subprocess +import sys +from pathlib import Path + +ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") +TOKEN_FILE = ROOT / "_build" / ".gitee_token" +GIT = r"C:\Program Files\Git\bin\git.exe" +GIT_SSH = r"C:\Program Files\Git\usr\bin\ssh.exe" + + +def sh(args, cwd=ROOT, check=False, timeout=1800, env=None): + merged = dict(os.environ) + if env: + merged.update(env) + proc = subprocess.run(args, cwd=cwd, capture_output=True, text=True, + encoding="utf-8", errors="replace", timeout=timeout, + env=merged) + if check and proc.returncode != 0: + raise RuntimeError(f"{args[0]} 失败:{proc.stdout}\n{proc.stderr}") + return proc + + +def step(n, title): + print() + print(f" {'=' * 56}") + print(f" {n}. {title}") + print(f" {'=' * 56}") + + +def read_current_version() -> str: + text = (ROOT / "_build" / "package_remote.py").read_text(encoding="utf-8") + for line in text.splitlines(): + if line.startswith("VERSION = "): + return line.split('"')[1] + return "0.0.0" + + +def main() -> int: + if len(sys.argv) < 2: + print(" 用法: python _build/release.py <新版本号>") + print(f" 当前版本: {read_current_version()}") + return 1 + + new_version = sys.argv[1] + old_version = read_current_version() + note_readme = "--no-readme" in sys.argv + + if not TOKEN_FILE.is_file(): + print(f" [失败] 找不到令牌文件 {TOKEN_FILE}") + print(" 把 Gitee 令牌写进那个文件(一行,别加引号)") + return 1 + token = TOKEN_FILE.read_text(encoding="utf-8").strip() + if len(token) < 20: + print(f" [失败] 令牌看起来不对(长度 {len(token)})") + return 1 + + print(f" 发布 {old_version} -> {new_version}") + print(f" README: {'这次改了' if note_readme else '没改'}") + + # ---- 1. 升版本 ---- + step(1, "升版本号") + proc = sh([sys.executable, "_build/bump_version_generic.py", + old_version, new_version]) + print(proc.stdout[-1200:]) + if proc.returncode != 0: + print(proc.stderr[-500:]) + return 1 + + # ---- 2. 重建 ---- + step(2, "重建 EXE 和 APK") + sh([GIT, "--version"]) # 探活,无关紧要 + for args in (["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", + "-File", "android\\build_apk.ps1"], + ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", + "-File", "windows\\build_exe.ps1"]): + proc = sh(args, timeout=2400) + tail = (proc.stdout or "").strip().splitlines()[-2:] + for line in tail: + print(f" {line}") + if proc.returncode != 0: + print(f" [失败] {args[-1]}") + print((proc.stderr or "")[-600:]) + return 1 + + # ---- 3. 打包 ---- + step(3, "打三个成品") + proc = sh([sys.executable, "_build/package_remote.py"]) + print(proc.stdout[-1400:]) + if proc.returncode != 0: + return 1 + + # ---- 4. 关键测试 ---- + step(4, "跑关键测试") + for test in ("audit_encoding.py", "test_net_tune.py", "test_chunked_body.py", + "test_admin_js.py"): + proc = sh([sys.executable, "-u", f"_tests/{test}"], timeout=900) + # 用退出码判断 —— 各测试的输出格式不一样 + # (有的打"失败 0 项",有的打"结论:JS 合法",字符串匹配会误判) + bad = proc.returncode != 0 + print(f" {test:28} {'✗' if bad else '✓'}") + if bad: + print((proc.stdout or "")[-800:]) + print((proc.stderr or "")[-400:]) + return 1 + proc = sh([sys.executable, "-u", "_tests/test_package_remote.py"], + timeout=1800) + out = proc.stdout or "" + last = [ln for ln in out.splitlines() if "通过" in ln or "失败" in ln] + print(f" {'test_package_remote.py':28} " + f"{'✓' if proc.returncode == 0 else '✗'} {last[-1] if last else ''}") + if proc.returncode != 0: + return 1 + + # ---- 5. 提交推送 ---- + step(5, "提交并推送") + env = {"GIT_SSH_COMMAND": f'"{GIT_SSH}"'} + sh([GIT, "add", "-A"]) + msg = (f"{new_version}:{'README 与' if note_readme else ''}常规发布\n\n" + f"- 版本号 {old_version} -> {new_version}\n" + f"- 重建三端并打包\n" + f"- 关键测试全过\n") + sh([GIT, "commit", "-q", "-m", msg]) + proc = sh([GIT, "push", "origin", "main"], env=env, timeout=1800) + print(f" {proc.stdout.strip()[-300:]}") + if proc.returncode != 0: + print(proc.stderr[-600:]) + return 1 + + # ---- 6. 发行版 ---- + step(6, "建 Gitee 发行版") + proc = sh([sys.executable, "_build/gitee_release.py", token, new_version], + timeout=2400) + print(proc.stdout[-1200:]) + if proc.returncode != 0: + print(proc.stderr[-600:]) + return 1 + + print() + print(f" ✓ {new_version} 发布完成") + print(f" https://gitee.com/xmz7891/ykxmz/releases/tag/v{new_version}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$100.class b/_tests/out_app/com/lanremote/watch/MainActivity$100.class index 3582d65..60db030 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$100.class and b/_tests/out_app/com/lanremote/watch/MainActivity$100.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$101$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$101$1.class index d21c84d..bb7a906 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$101$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$101$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$101.class b/_tests/out_app/com/lanremote/watch/MainActivity$101.class index 087f4c3..56e58a2 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$101.class and b/_tests/out_app/com/lanremote/watch/MainActivity$101.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$102$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$102$1.class index fe0ef33..5b45781 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$102$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$102$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$102.class b/_tests/out_app/com/lanremote/watch/MainActivity$102.class index 5287123..64ce1f1 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$102.class and b/_tests/out_app/com/lanremote/watch/MainActivity$102.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$103.class b/_tests/out_app/com/lanremote/watch/MainActivity$103.class index 44e458a..b27ab2f 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$103.class and b/_tests/out_app/com/lanremote/watch/MainActivity$103.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$104.class b/_tests/out_app/com/lanremote/watch/MainActivity$104.class index 1574cf2..7405faf 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$104.class and b/_tests/out_app/com/lanremote/watch/MainActivity$104.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$105$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$105$1.class index 45ab0a0..cfb4155 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$105$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$105$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$105.class b/_tests/out_app/com/lanremote/watch/MainActivity$105.class index f3a1c65..3a4ba01 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$105.class and b/_tests/out_app/com/lanremote/watch/MainActivity$105.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$106$1$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$106$1$1.class index 4ead215..66a53fe 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$106$1$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$106$1$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$106$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$106$1.class index 3d686b8..fb6171a 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$106$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$106$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$106.class b/_tests/out_app/com/lanremote/watch/MainActivity$106.class index b4f0b26..1b3e494 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$106.class and b/_tests/out_app/com/lanremote/watch/MainActivity$106.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$107$1$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$107$1$1.class index f9f115b..7adb207 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$107$1$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$107$1$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$107$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$107$1.class index 901ae22..c775468 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$107$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$107$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$107.class b/_tests/out_app/com/lanremote/watch/MainActivity$107.class index 9ded135..53957d4 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$107.class and b/_tests/out_app/com/lanremote/watch/MainActivity$107.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$108.class b/_tests/out_app/com/lanremote/watch/MainActivity$108.class index a4249f6..69b7509 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$108.class and b/_tests/out_app/com/lanremote/watch/MainActivity$108.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$109.class b/_tests/out_app/com/lanremote/watch/MainActivity$109.class index 5cd2e2d..ead6ce3 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$109.class and b/_tests/out_app/com/lanremote/watch/MainActivity$109.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$110.class b/_tests/out_app/com/lanremote/watch/MainActivity$110.class index 15acc66..f660365 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$110.class and b/_tests/out_app/com/lanremote/watch/MainActivity$110.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$111$1$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$111$1$1.class index 36344a2..4abf3a2 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$111$1$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$111$1$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$111$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$111$1.class index af4f74d..b3e7896 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$111$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$111$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$111.class b/_tests/out_app/com/lanremote/watch/MainActivity$111.class index 1a62945..0642478 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$111.class and b/_tests/out_app/com/lanremote/watch/MainActivity$111.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$112$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$112$1.class index 4a2b84d..80f8493 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$112$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$112$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$112.class b/_tests/out_app/com/lanremote/watch/MainActivity$112.class index 496426e..59e762d 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$112.class and b/_tests/out_app/com/lanremote/watch/MainActivity$112.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$113.class b/_tests/out_app/com/lanremote/watch/MainActivity$113.class index 26a485b..e9dc012 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$113.class and b/_tests/out_app/com/lanremote/watch/MainActivity$113.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$114.class b/_tests/out_app/com/lanremote/watch/MainActivity$114.class index eb123ff..7a8ac30 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$114.class and b/_tests/out_app/com/lanremote/watch/MainActivity$114.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$115$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$115$1.class index a91ce52..037d1be 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$115$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$115$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$115.class b/_tests/out_app/com/lanremote/watch/MainActivity$115.class index 568e608..ab30005 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$115.class and b/_tests/out_app/com/lanremote/watch/MainActivity$115.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$116$1$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$116$1$1.class index 74b7329..c3b922e 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$116$1$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$116$1$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$116$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$116$1.class index 8604af9..a43daf6 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$116$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$116$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$116.class b/_tests/out_app/com/lanremote/watch/MainActivity$116.class index 871ce45..d6f110f 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$116.class and b/_tests/out_app/com/lanremote/watch/MainActivity$116.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$117$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$117$1.class index 75eb07f..00d1e3d 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$117$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$117$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$117.class b/_tests/out_app/com/lanremote/watch/MainActivity$117.class index 75c14fc..f55b7f8 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$117.class and b/_tests/out_app/com/lanremote/watch/MainActivity$117.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$118.class b/_tests/out_app/com/lanremote/watch/MainActivity$118.class index fa609cf..758b1cd 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$118.class and b/_tests/out_app/com/lanremote/watch/MainActivity$118.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$119.class b/_tests/out_app/com/lanremote/watch/MainActivity$119.class index 2419e12..6f9e70f 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$119.class and b/_tests/out_app/com/lanremote/watch/MainActivity$119.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$120.class b/_tests/out_app/com/lanremote/watch/MainActivity$120.class index 1a5e052..59ee059 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$120.class and b/_tests/out_app/com/lanremote/watch/MainActivity$120.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$121.class b/_tests/out_app/com/lanremote/watch/MainActivity$121.class index 0fffed3..f46ff38 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$121.class and b/_tests/out_app/com/lanremote/watch/MainActivity$121.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$122$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$122$1.class index da1f060..18223b2 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$122$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$122$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$122.class b/_tests/out_app/com/lanremote/watch/MainActivity$122.class index c192d0d..6e816cf 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$122.class and b/_tests/out_app/com/lanremote/watch/MainActivity$122.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$123.class b/_tests/out_app/com/lanremote/watch/MainActivity$123.class index 1b028e0..1e9c6d9 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$123.class and b/_tests/out_app/com/lanremote/watch/MainActivity$123.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$124.class b/_tests/out_app/com/lanremote/watch/MainActivity$124.class index 639752f..bb262d0 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$124.class and b/_tests/out_app/com/lanremote/watch/MainActivity$124.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$125.class b/_tests/out_app/com/lanremote/watch/MainActivity$125.class index 86ca6d7..5a13c92 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$125.class and b/_tests/out_app/com/lanremote/watch/MainActivity$125.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$126.class b/_tests/out_app/com/lanremote/watch/MainActivity$126.class index 1cce4a1..9f91a8a 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$126.class and b/_tests/out_app/com/lanremote/watch/MainActivity$126.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$127$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$127$1.class index e8f6007..6605170 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$127$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$127$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$127$2.class b/_tests/out_app/com/lanremote/watch/MainActivity$127$2.class index 53a7a10..8f780c8 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$127$2.class and b/_tests/out_app/com/lanremote/watch/MainActivity$127$2.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$127.class b/_tests/out_app/com/lanremote/watch/MainActivity$127.class index 8542138..3509908 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$127.class and b/_tests/out_app/com/lanremote/watch/MainActivity$127.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$128.class b/_tests/out_app/com/lanremote/watch/MainActivity$128.class index 2882877..ce46ad7 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$128.class and b/_tests/out_app/com/lanremote/watch/MainActivity$128.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$129.class b/_tests/out_app/com/lanremote/watch/MainActivity$129.class index 4cfa763..32f1076 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$129.class and b/_tests/out_app/com/lanremote/watch/MainActivity$129.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$94$1.class b/_tests/out_app/com/lanremote/watch/MainActivity$94$1.class index 47b0348..aa2ab99 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$94$1.class and b/_tests/out_app/com/lanremote/watch/MainActivity$94$1.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$94.class b/_tests/out_app/com/lanremote/watch/MainActivity$94.class index cc19837..d0924d2 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$94.class and b/_tests/out_app/com/lanremote/watch/MainActivity$94.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$95.class b/_tests/out_app/com/lanremote/watch/MainActivity$95.class index 2144d12..0a5149a 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$95.class and b/_tests/out_app/com/lanremote/watch/MainActivity$95.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$96.class b/_tests/out_app/com/lanremote/watch/MainActivity$96.class index 8d27ce1..6b6c229 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$96.class and b/_tests/out_app/com/lanremote/watch/MainActivity$96.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$97.class b/_tests/out_app/com/lanremote/watch/MainActivity$97.class index 60be8d3..8a384df 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$97.class and b/_tests/out_app/com/lanremote/watch/MainActivity$97.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$98.class b/_tests/out_app/com/lanremote/watch/MainActivity$98.class index 74c917f..b71711c 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$98.class and b/_tests/out_app/com/lanremote/watch/MainActivity$98.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity$99.class b/_tests/out_app/com/lanremote/watch/MainActivity$99.class index 98eaa34..98a0034 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity$99.class and b/_tests/out_app/com/lanremote/watch/MainActivity$99.class differ diff --git a/_tests/out_app/com/lanremote/watch/MainActivity.class b/_tests/out_app/com/lanremote/watch/MainActivity.class index 20a486a..8c2e8a4 100644 Binary files a/_tests/out_app/com/lanremote/watch/MainActivity.class and b/_tests/out_app/com/lanremote/watch/MainActivity.class differ diff --git a/_tests/out_app/com/lanremote/watch/RelayTransport.class b/_tests/out_app/com/lanremote/watch/RelayTransport.class index ae033e7..5de8d1e 100644 Binary files a/_tests/out_app/com/lanremote/watch/RelayTransport.class and b/_tests/out_app/com/lanremote/watch/RelayTransport.class differ diff --git a/_tests/shots/1-屏幕中间.png b/_tests/shots/1-屏幕中间.png index 683dd74..1960c17 100644 Binary files a/_tests/shots/1-屏幕中间.png and b/_tests/shots/1-屏幕中间.png differ diff --git a/_tests/shots/3-自定义640x400.png b/_tests/shots/3-自定义640x400.png index 4e38939..d0daadc 100644 Binary files a/_tests/shots/3-自定义640x400.png and b/_tests/shots/3-自定义640x400.png differ diff --git a/_tests/test_apk_contents.py b/_tests/test_apk_contents.py index 9b5d679..de889e7 100644 --- a/_tests/test_apk_contents.py +++ b/_tests/test_apk_contents.py @@ -23,7 +23,7 @@ def _latest_apk() -> Path: (ROOT / "dist").glob("*watch*.apk"), key=lambda p: p.stat().st_mtime, reverse=True) return candidates[0] if candidates else \ - ROOT / "dist" / "ykxmz-watch-1.6.0.apk" + ROOT / "dist" / "ykxmz-watch-1.6.1.apk" APK = _latest_apk() diff --git a/_tests/test_package_remote.py b/_tests/test_package_remote.py index 457932c..c976a10 100644 --- a/_tests/test_package_remote.py +++ b/_tests/test_package_remote.py @@ -26,9 +26,9 @@ ROOT = Path(__file__).resolve().parent.parent # 被控端 -> 一个 zip # 服务器端 -> 一个 zip # 控制端 -> 直接给 APK(不打 zip) -AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-1.6.0.zip" -SERVER_ZIP = ROOT / "dist" / "ykxmz-server-1.6.0.zip" -WATCH_APK = ROOT / "dist" / "ykxmz-watch-1.6.0.apk" +AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-1.6.1.zip" +SERVER_ZIP = ROOT / "dist" / "ykxmz-server-1.6.1.zip" +WATCH_APK = ROOT / "dist" / "ykxmz-watch-1.6.1.apk" TOOLCHAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\starklink\toolchain") JAVAC = TOOLCHAIN / "jdk17" / "bin" / "javac.exe" JAVA = TOOLCHAIN / "jdk17" / "bin" / "java.exe" @@ -89,7 +89,7 @@ def main() -> int: for label, path in (("被控端", agent_dir / "README-agent.txt"), ("服务器端", relay_dir / "README-server.txt"), ("控制端(旁边那份)", - ROOT / "dist" / "ykxmz-watch-1.6.0-说明.txt")): + ROOT / "dist" / "ykxmz-watch-1.6.1-说明.txt")): raw = path.read_bytes() if path.is_file() else b"" check(f"{label}说明有 UTF-8 BOM", raw[:3] == b"\xef\xbb\xbf", raw[:3]) diff --git a/_tests/verify_all.ps1 b/_tests/verify_all.ps1 index 30119c6..f4ea2dd 100644 --- a/_tests/verify_all.ps1 +++ b/_tests/verify_all.ps1 @@ -402,7 +402,6 @@ New-Item -ItemType Directory -Force -Path $out | Out-Null (Join-Path $root "android\src\com\lanremote\watch\DiscoveryCore.java") ` (Join-Path $root "android\src\com\lanremote\watch\Transport.java") ` (Join-Path $root "android\src\com\lanremote\watch\RelayTransport.java") ` - # TlsCompat:内置根证书,修老手表连中转时的 SSLHandshakeException (Join-Path $root "android\src\com\lanremote\watch\TlsCompat.java") ` (Join-Path $root "android\src\com\lanremote\watch\RemoteClient.java") ` (Join-Path $root "_tests\java\JavaClientTest.java") 2>&1 | Out-Null diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 680c7ec..9ab4896 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:versionName="1.6.1"> diff --git a/android/build_apk.ps1 b/android/build_apk.ps1 index ec5c855..b315086 100644 --- a/android/build_apk.ps1 +++ b/android/build_apk.ps1 @@ -27,7 +27,7 @@ $d8 = Join-Path $bt "d8.bat" $work = Join-Path $android "build" $outDir = Join-Path $root "dist" -$apkName = "ykxmz-watch-1.6.0.apk" +$apkName = "ykxmz-watch-1.6.1.apk" function Step($text) { Write-Host "`n=== $text ===" -ForegroundColor Cyan } @@ -65,7 +65,7 @@ $unsigned = Join-Path $work "app-unsigned.apk" --min-sdk-version 24 ` --target-sdk-version 34 ` --version-code 5 ` - --version-name "1.6.0" ` + --version-name "1.6.1" ` --auto-add-overlay if ($LASTEXITCODE -ne 0) { throw "aapt2 link 失败" } diff --git a/docs/AFTER-INSTALL.txt b/docs/AFTER-INSTALL.txt index f8ac74a..c38173a 100644 --- a/docs/AFTER-INSTALL.txt +++ b/docs/AFTER-INSTALL.txt @@ -3,7 +3,7 @@ ======================================================== 软件名称:ykxmz -版本:1.6.0 +版本:1.6.1 作者:小麦子 装好之后看这一页:怎么确认它在跑、怎么改设置、 @@ -197,7 +197,7 @@ 八、版本记录 -------------------------------------------------------- - 1.6.0 + 1.6.1 * 跨网络支持:Cloudflare 具名隧道,固定域名 * 中转服务器:单设备单配对码、管理页可删设备 * 手表端:自动判断局域网/中转并无缝切换 @@ -209,6 +209,6 @@ -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 1.6.0 + 软件:ykxmz 1.6.1 许可条款见《许可协议》(LICENSE.txt) -------------------------------------------------------- diff --git a/docs/BEFORE-INSTALL.txt b/docs/BEFORE-INSTALL.txt index dc970dd..567ce8c 100644 --- a/docs/BEFORE-INSTALL.txt +++ b/docs/BEFORE-INSTALL.txt @@ -3,7 +3,7 @@ ======================================================== 软件名称:ykxmz -版本:1.6.0 +版本:1.6.1 作者:小麦子 请你**在安装之前**花三分钟读完这一页。里面有几条很要紧的 @@ -152,6 +152,6 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成: -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 1.6.0 + 软件:ykxmz 1.6.1 继续安装,即表示你已阅读并同意《许可协议》。 -------------------------------------------------------- diff --git a/docs/LICENSE.txt b/docs/LICENSE.txt index 121ad7e..cd195c7 100644 --- a/docs/LICENSE.txt +++ b/docs/LICENSE.txt @@ -3,7 +3,7 @@ ======================================================== 软件名称:ykxmz(远程管理工具) -版本:1.6.0 +版本:1.6.1 作者:小麦子 生效日期:2026 年 10 月 5 日 @@ -150,7 +150,7 @@ -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 1.6.0 + 软件:ykxmz 1.6.1 如果你不同意本协议的任何一条,请不要安装或使用本软件。 -------------------------------------------------------- diff --git a/relay/relay.py b/relay/relay.py index c6c4eed..19602c1 100644 --- a/relay/relay.py +++ b/relay/relay.py @@ -58,7 +58,7 @@ from collections import deque from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path -VERSION = "1.6.0" +VERSION = "1.6.1" # ---------------- 参数(都能用环境变量覆盖)---------------- diff --git a/windows/lanremote/__init__.py b/windows/lanremote/__init__.py index 61d38e9..e1cea88 100644 --- a/windows/lanremote/__init__.py +++ b/windows/lanremote/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- """局域网遥控 · Windows 被控端。""" -__version__ = "1.6.0" +__version__ = "1.6.1" APP_NAME = "局域网遥控 被控端" diff --git a/windows/lanremote/server.py b/windows/lanremote/server.py index 3387807..9b11f6e 100644 --- a/windows/lanremote/server.py +++ b/windows/lanremote/server.py @@ -149,12 +149,23 @@ class RemoteServer: self._sock = sock self._running = True - # 配了中转地址就同时启用跨网络通道(和局域网监听并存,不冲突) - try: - self.enable_relay() - except Exception as exc: # noqa: BLE001 - self._log(f"启用中转失败:{exc}") + # ── 先起局域网发现 ── + # + # 顺序很重要:enable_relay() 会挨个试中转地址, + # 每个候选都要等到超时才算"不通",地址越烂等得越久(实测 10 秒+)。 + # 原来这一步排在发现服务前面,导致: + # 电脑刚开机的十几秒里,手表广播搜不到它。 + # 局域网发现是纯本机能力,不该被"连不连得上外网"拖住, + # 所以挪到前面,开机即可被搜到。 + self._discovery = DiscoveryResponder(self.store, self.port) + # 手表点「连不上?」会广播请求,这里就把网络自检结论算出来 + self._discovery.on_selfcheck = self._on_selfcheck_request + if self._discovery.start(): + self._log(f"自动发现已开启(UDP {DISCOVERY_PORT})") + else: + self._log(f"自动发现未开启:{self._discovery.last_error}") + # ── 再起收发线程 ── self._accept_thread = threading.Thread(target=self._accept_loop, name="accept", daemon=True) self._accept_thread.start() @@ -162,14 +173,12 @@ class RemoteServer: name="clip", daemon=True) self._clip_thread.start() - # 启动局域网自动发现,让手表不用输 IP - self._discovery = DiscoveryResponder(self.store, self.port) - # 手表点「连不上?」会广播请求,这里就把网络自检窗口弹出来 - self._discovery.on_selfcheck = self._on_selfcheck_request - if self._discovery.start(): - self._log(f"自动发现已开启(UDP {DISCOVERY_PORT})") - else: - self._log(f"自动发现未开启:{self._discovery.last_error}") + # ── 最后才连中转(会阻塞,所以放最后)── + # 配了中转地址就同时启用跨网络通道(和局域网监听并存,不冲突) + try: + self.enable_relay() + except Exception as exc: # noqa: BLE001 + self._log(f"启用中转失败:{exc}") self._log(f"服务已启动,监听 0.0.0.0:{self.port}") diff --git a/windows/version_info.txt b/windows/version_info.txt index e1560a3..5b45442 100644 --- a/windows/version_info.txt +++ b/windows/version_info.txt @@ -27,12 +27,12 @@ VSVersionInfo( [ StringStruct("CompanyName", "ykxmz"), StringStruct("FileDescription", "ykxmz"), - StringStruct("FileVersion", "1.6.0.0"), + StringStruct("FileVersion", "1.6.1.0"), StringStruct("InternalName", "ykxmz"), StringStruct("LegalCopyright", "ykxmz"), StringStruct("OriginalFilename", "ykxmz.exe"), StringStruct("ProductName", "ykxmz"), - StringStruct("ProductVersion", "1.6.0.0"), + StringStruct("ProductVersion", "1.6.1.0"), ], ) ]