mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 20:40:43 +00:00
1.6.2:常规发布
- 版本号 1.6.2 -> 1.6.2 - 重建三端并打包 - 关键测试全过
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@ from pathlib import Path
|
||||
|
||||
import paramiko
|
||||
|
||||
HOST = "192.168.10.105"
|
||||
HOST = "192.168.2.156"
|
||||
USER = "root"
|
||||
PASSWORD = "1313144"
|
||||
|
||||
|
||||
@@ -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
@@ -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. 提交推送 ----
|
||||
|
||||
@@ -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())
|
||||
@@ -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())
|
||||
@@ -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())
|
||||
Reference in New Issue
Block a user