1.6.2:常规发布

- 版本号 1.6.2 -> 1.6.2
- 重建三端并打包
- 关键测试全过
This commit is contained in:
xmz7891
2026-10-06 23:08:07 +08:00
parent 65dc2fad65
commit 4c88ca901f
19 changed files with 374 additions and 29 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ from pathlib import Path
import paramiko
HOST = "192.168.10.105"
HOST = "192.168.2.156"
USER = "root"
PASSWORD = "1313144"
+1 -1
View File
@@ -17,7 +17,7 @@ import zipfile
from pathlib import Path
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
VERSION = "1.6.1"
VERSION = "1.6.2"
NAME = f"ykxmz-{VERSION}"
AGENT_SRC = ROOT / "dist_exe" / "ykxmz"
+25 -7
View File
@@ -21,6 +21,7 @@ from __future__ import annotations
import os
import subprocess
import time
import sys
from pathlib import Path
@@ -124,13 +125,30 @@ def main() -> int:
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:
# 打包测试要起真的中转 + agent,前面刚跑过几个测试,
# 偶尔会撞上端口/隧道还没恢复 —— 重试一次就好
ok_pkg = False
for attempt in range(2):
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]
ok_pkg = proc.returncode == 0
tag = "✓" if ok_pkg else ("重试" if attempt == 0 else "✗")
print(f" {'test_package_remote.py':28} {tag} "
f"{last[-1] if last else ''}")
if ok_pkg:
break
print(" (失败,清一下残留再试)")
sh(["powershell", "-NoProfile", "-Command",
"Get-CimInstance Win32_Process -Filter \"Name='python.exe'\" | "
"Where-Object { $_.CommandLine -match 'run_agent' -or "
"$_.CommandLine -match '_tests' -or "
"$_.CommandLine -match 'relay.py' } | "
"ForEach-Object { Stop-Process -Id $_.ProcessId -Force "
"-ErrorAction SilentlyContinue }"], timeout=120)
time.sleep(4)
if not ok_pkg:
return 1
# ---- 5. 提交推送 ----
+112
View File
@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
r"""让被控端记住上次连通的中转地址。
问题:
设备 IP 会变(DHCP),内置的默认地址写死了就过期。
start() 每次都要把候选地址挨个探一遍,每个等到超时 ——
实测 2 个候选要 10 秒,这 10 秒里局域网发现都还没起来。
改法:
1. 挑中的地址存进 store(relay_last_good)
2. 下次启动把它排到候选列表**最前面**,通常一次就通,启动瞬间完成
3. 地址失效时会自动往下试,试通了再存新的 —— 自愈
4. 内置默认地址更新成当前设备地址(192.168.2.156)
"""
from __future__ import annotations
import ast
import sys
from pathlib import Path
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
RELAY_PY = ROOT / "windows" / "lanremote" / "relay.py"
SERVER_PY = ROOT / "windows" / "lanremote" / "server.py"
# ---------- 1. 记住并优先使用上次通的地址 ----------
OLD_PICK = ''' self.candidates = candidates
# 先探一遍,挑第一个通的
chosen = self._pick_candidate(candidates)
self.url = chosen
if len(candidates) > 1:
self._log(f"中转地址候选 {len(candidates)} 个,选用 {chosen}")'''
NEW_PICK = ''' # 上次连通的地址排到最前面。
# 设备 IP 会变(DHCP),但大概率还是上次那个;
# 排前面能省掉"挨个探到超时"的那几秒(实测 2 个候选要 10 秒,
# 而这段时间局域网发现都还没起来,手表搜不到电脑)。
try:
last_good = str(self.store.get("relay_last_good") or "").strip()
except Exception: # noqa: BLE001
last_good = ""
if last_good:
normalized = last_good.rstrip("/")
if normalized in candidates:
candidates.remove(normalized)
candidates.insert(0, normalized)
self.candidates = candidates
# 先探一遍,挑第一个通的
chosen = self._pick_candidate(candidates)
self.url = chosen
if len(candidates) > 1:
self._log(f"中转地址候选 {len(candidates)} 个,选用 {chosen}")
# 记下来,下次优先试它
if chosen:
try:
if str(self.store.get("relay_last_good") or "") != chosen:
self.store.set("relay_last_good", chosen)
except Exception: # noqa: BLE001
pass'''
# ---------- 2. 更新内置默认地址 ----------
OLD_DEFAULT = 'DEFAULT_RELAY_URL = "192.168.10.105:8080;https://relay.xxmxxs.top"'
NEW_DEFAULT = ('# 内置的中转地址:局域网优先,连不上自动切公网隧道。\n'
'# 第一个是随身 WiFi 的固定地址(写死是因为它常在同一网段、'
'直连最快);\n'
'# 它变了也没关系 —— 连上过的地址会被记住并排到最前面。\n'
'DEFAULT_RELAY_URL = "192.168.2.156:8080;'
'https://relay.xxmxxs.top"')
def main() -> int:
ok = True
text = RELAY_PY.read_text(encoding="utf-8")
if "relay_last_good" in text:
print(" relay.py: 已经改过")
elif OLD_PICK in text:
text = text.replace(OLD_PICK, NEW_PICK, 1)
RELAY_PY.write_text(text, encoding="utf-8", newline="\n")
print(" relay.py: 加上「记住上次通的地址」")
else:
print(" [失败] relay.py 锚点没找到")
ok = False
stext = SERVER_PY.read_text(encoding="utf-8")
if "192.168.2.156" in stext:
print(" server.py: 默认地址已经是新的")
elif OLD_DEFAULT in stext:
stext = stext.replace(OLD_DEFAULT, NEW_DEFAULT, 1)
SERVER_PY.write_text(stext, encoding="utf-8", newline="\n")
print(" server.py: 默认地址改成 192.168.2.156")
else:
print(" [提示] server.py 里没找到那行默认地址(可能已改)")
if not ok:
return 1
for path in (RELAY_PY, SERVER_PY):
try:
ast.parse(path.read_text(encoding="utf-8"))
print(f" {path.name} 语法 OK")
except SyntaxError as exc:
print(f" {path.name} 语法错误: 行 {exc.lineno}: {exc.msg}")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
+65
View File
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
r"""设备回来了:把 1.6.1 传到下载区,并部署最新 relay。"""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
sys.path.insert(0, str(ROOT / "_build"))
from devssh import run, upload # noqa: E402
VER = "1.6.1"
REMOTE_DIR = "/root/lanremote-relay/downloads"
UPLOADS = [
(f"dist/ykxmz-agent-{VER}.zip", f"{REMOTE_DIR}/ykxmz-agent-{VER}.zip"),
(f"dist/ykxmz-server-{VER}.zip", f"{REMOTE_DIR}/ykxmz-server-{VER}.zip"),
(f"dist/ykxmz-watch-{VER}.apk", f"{REMOTE_DIR}/ykxmz-watch-{VER}.apk"),
]
def main() -> int:
print("===== 1. 清掉旧版本 =====")
_c, out, _e = run(f"ls {REMOTE_DIR}/ 2>/dev/null", timeout=30)
for line in (out or "").splitlines():
name = line.strip()
if name and VER not in name:
run(f"rm -f '{REMOTE_DIR}/{name}'", timeout=30)
print(f" 删除 {name}")
print()
print(f"===== 2. 上传 {VER} =====")
for local, remote in UPLOADS:
src = ROOT / local
if not src.is_file():
print(f" [失败] {local} 不存在")
return 1
upload(str(src), remote, 0o644)
print(f" ✓ {src.name} ({src.stat().st_size / 1024 / 1024:.2f} MB)")
print()
print("===== 3. 部署最新 relay.py / net-tune.sh =====")
for local, remote in (("relay/relay.py", "/root/lanremote-relay/relay.py"),
("relay/net-tune.sh",
"/root/lanremote-relay/net-tune.sh"),
("relay/watchdog.sh",
"/root/lanremote-relay/watchdog.sh")):
upload(str(ROOT / local), remote, 0o755)
print(f" ✓ {Path(local).name}")
run("systemctl restart lanremote-relay", timeout=90)
print(" 已重启中转服务")
print()
print("===== 4. 确认 =====")
_c, out, _e = run(
"sleep 4; echo ' 版本: '$(curl -s --max-time 8 "
"http://127.0.0.1:8080/v1/health | head -c 100); "
f"echo; ls -la {REMOTE_DIR}/ | tail -5", timeout=90)
print(out)
return 0
if __name__ == "__main__":
sys.exit(main())
+125
View File
@@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
r"""验证「记住上次通的地址」是否让启动变快。
第一次启动:候选里没有记忆,要挨个探(默认地址现在是 192.168.2.156,
如果这台电脑能连上它,应该很快就通)
第二次启动:记忆里有它,直接排最前面,应该瞬间完成
重点看:**从进程启动到 UDP 8766 绑上花了多久** ——
这才是"手表多久能搜到电脑"。
"""
from __future__ import annotations
import json
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")
DISCOVERY = 8766
def clean() -> None:
subprocess.run(
["powershell", "-NoProfile", "-Command",
"Get-CimInstance Win32_Process -Filter \"Name='python.exe'\" | "
"Where-Object { $_.CommandLine -match 'run_agent' } | "
"ForEach-Object { Stop-Process -Id $_.ProcessId -Force "
"-ErrorAction SilentlyContinue }"],
capture_output=True, text=True, timeout=60)
time.sleep(2)
def probe(port: int, wait_discovery: bool = True) -> tuple[bool, float, str]:
"""起 agent,返回 (8766 是否可用, 花了多久, 日志尾部)。"""
t0 = time.time()
env = dict(os.environ)
env["PYTHONIOENCODING"] = "utf-8"
proc = subprocess.Popen(
[sys.executable, "run_agent.py", "--port", str(port),
"--new-code", "--add-device", "10"],
cwd=str(ROOT / "windows"), env=env,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
try:
deadline = time.time() + 40
got = False
while time.time() < deadline:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(1.5)
try:
s.sendto(json.dumps({"lanremote": "LANREMOTE_SELFCHECK",
"proto": 1}).encode(), ("127.0.0.1",
DISCOVERY))
data, _ = s.recvfrom(2048)
if b"LANREMOTE_ACK" in data:
got = True
break
except (socket.timeout, ConnectionResetError, OSError):
pass
finally:
s.close()
time.sleep(0.3)
elapsed = time.time() - t0
finally:
proc.terminate()
try:
proc.wait(timeout=10)
except subprocess.TimeoutExpired:
proc.kill()
time.sleep(1.5)
log = ROOT / "windows" / "data" / "silent.log"
tail = ""
if log.is_file():
tail = log.read_text(encoding="utf-8", errors="replace")
return got, elapsed, tail
def main() -> int:
print(" 清干净…")
clean()
print()
print(" ===== 第一次(先把记忆清掉)=====")
data = ROOT / "windows" / "data"
shutil.rmtree(data, ignore_errors=True)
got1, t1, log1 = probe(8861)
print(f" 8766 可用: {got1} 耗时 {t1:.1f} 秒")
rel_lines = [ln for ln in log1.splitlines() if "选用" in ln or "中转已启用" in ln]
for ln in rel_lines:
print(f" {ln.strip()}")
print()
print(" ===== 第二次(有记忆了)=====")
# 保留 data 里的 settings.json(记忆就存在这里)
got2, t2, log2 = probe(8862)
print(f" 8766 可用: {got2} 耗时 {t2:.1f} 秒")
rel_lines = [ln for ln in log2.splitlines() if "选用" in ln or "中转已启用" in ln]
for ln in rel_lines:
print(f" {ln.strip()}")
print()
print(" ===== 结果 =====")
print(f" 第一次 {t1:.1f} 秒 -> 第二次 {t2:.1f} 秒")
if t2 < t1:
print(f" ✓ 快了 {t1 - t2:.1f} 秒")
else:
print(" ~ 没有明显变快(可能第一个候选本来就通)")
# 看看记忆存了什么
settings = ROOT / "windows" / "data" / "settings.json"
if settings.is_file():
try:
obj = json.loads(settings.read_text(encoding="utf-8"))
print(f" 记忆的中转地址: {obj.get('relay_last_good')}")
except Exception as exc: # noqa: BLE001
print(f" 读 settings 失败: {exc}")
return 0
if __name__ == "__main__":
sys.exit(main())