mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 16:00: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
|
import paramiko
|
||||||
|
|
||||||
HOST = "192.168.10.105"
|
HOST = "192.168.2.156"
|
||||||
USER = "root"
|
USER = "root"
|
||||||
PASSWORD = "1313144"
|
PASSWORD = "1313144"
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import zipfile
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||||||
VERSION = "1.6.1"
|
VERSION = "1.6.2"
|
||||||
NAME = f"ykxmz-{VERSION}"
|
NAME = f"ykxmz-{VERSION}"
|
||||||
|
|
||||||
AGENT_SRC = ROOT / "dist_exe" / "ykxmz"
|
AGENT_SRC = ROOT / "dist_exe" / "ykxmz"
|
||||||
|
|||||||
+21
-3
@@ -21,6 +21,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import time
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -124,13 +125,30 @@ def main() -> int:
|
|||||||
print((proc.stdout or "")[-800:])
|
print((proc.stdout or "")[-800:])
|
||||||
print((proc.stderr or "")[-400:])
|
print((proc.stderr or "")[-400:])
|
||||||
return 1
|
return 1
|
||||||
|
# 打包测试要起真的中转 + agent,前面刚跑过几个测试,
|
||||||
|
# 偶尔会撞上端口/隧道还没恢复 —— 重试一次就好
|
||||||
|
ok_pkg = False
|
||||||
|
for attempt in range(2):
|
||||||
proc = sh([sys.executable, "-u", "_tests/test_package_remote.py"],
|
proc = sh([sys.executable, "-u", "_tests/test_package_remote.py"],
|
||||||
timeout=1800)
|
timeout=1800)
|
||||||
out = proc.stdout or ""
|
out = proc.stdout or ""
|
||||||
last = [ln for ln in out.splitlines() if "通过" in ln or "失败" in ln]
|
last = [ln for ln in out.splitlines() if "通过" in ln or "失败" in ln]
|
||||||
print(f" {'test_package_remote.py':28} "
|
ok_pkg = proc.returncode == 0
|
||||||
f"{'✓' if proc.returncode == 0 else '✗'} {last[-1] if last else ''}")
|
tag = "✓" if ok_pkg else ("重试" if attempt == 0 else "✗")
|
||||||
if proc.returncode != 0:
|
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
|
return 1
|
||||||
|
|
||||||
# ---- 5. 提交推送 ----
|
# ---- 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())
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 608 KiB After Width: | Height: | Size: 3.1 KiB |
@@ -23,7 +23,7 @@ def _latest_apk() -> Path:
|
|||||||
(ROOT / "dist").glob("*watch*.apk"),
|
(ROOT / "dist").glob("*watch*.apk"),
|
||||||
key=lambda p: p.stat().st_mtime, reverse=True)
|
key=lambda p: p.stat().st_mtime, reverse=True)
|
||||||
return candidates[0] if candidates else \
|
return candidates[0] if candidates else \
|
||||||
ROOT / "dist" / "ykxmz-watch-1.6.1.apk"
|
ROOT / "dist" / "ykxmz-watch-1.6.2.apk"
|
||||||
|
|
||||||
|
|
||||||
APK = _latest_apk()
|
APK = _latest_apk()
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ ROOT = Path(__file__).resolve().parent.parent
|
|||||||
# 被控端 -> 一个 zip
|
# 被控端 -> 一个 zip
|
||||||
# 服务器端 -> 一个 zip
|
# 服务器端 -> 一个 zip
|
||||||
# 控制端 -> 直接给 APK(不打 zip)
|
# 控制端 -> 直接给 APK(不打 zip)
|
||||||
AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-1.6.1.zip"
|
AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-1.6.2.zip"
|
||||||
SERVER_ZIP = ROOT / "dist" / "ykxmz-server-1.6.1.zip"
|
SERVER_ZIP = ROOT / "dist" / "ykxmz-server-1.6.2.zip"
|
||||||
WATCH_APK = ROOT / "dist" / "ykxmz-watch-1.6.1.apk"
|
WATCH_APK = ROOT / "dist" / "ykxmz-watch-1.6.2.apk"
|
||||||
TOOLCHAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\starklink\toolchain")
|
TOOLCHAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\starklink\toolchain")
|
||||||
JAVAC = TOOLCHAIN / "jdk17" / "bin" / "javac.exe"
|
JAVAC = TOOLCHAIN / "jdk17" / "bin" / "javac.exe"
|
||||||
JAVA = TOOLCHAIN / "jdk17" / "bin" / "java.exe"
|
JAVA = TOOLCHAIN / "jdk17" / "bin" / "java.exe"
|
||||||
@@ -89,7 +89,7 @@ def main() -> int:
|
|||||||
for label, path in (("被控端", agent_dir / "README-agent.txt"),
|
for label, path in (("被控端", agent_dir / "README-agent.txt"),
|
||||||
("服务器端", relay_dir / "README-server.txt"),
|
("服务器端", relay_dir / "README-server.txt"),
|
||||||
("控制端(旁边那份)",
|
("控制端(旁边那份)",
|
||||||
ROOT / "dist" / "ykxmz-watch-1.6.1-说明.txt")):
|
ROOT / "dist" / "ykxmz-watch-1.6.2-说明.txt")):
|
||||||
raw = path.read_bytes() if path.is_file() else b""
|
raw = path.read_bytes() if path.is_file() else b""
|
||||||
check(f"{label}说明有 UTF-8 BOM",
|
check(f"{label}说明有 UTF-8 BOM",
|
||||||
raw[:3] == b"\xef\xbb\xbf", raw[:3])
|
raw[:3] == b"\xef\xbb\xbf", raw[:3])
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.lanremote.watch"
|
package="com.lanremote.watch"
|
||||||
android:versionCode="5"
|
android:versionCode="5"
|
||||||
android:versionName="1.6.1">
|
android:versionName="1.6.2">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ $d8 = Join-Path $bt "d8.bat"
|
|||||||
|
|
||||||
$work = Join-Path $android "build"
|
$work = Join-Path $android "build"
|
||||||
$outDir = Join-Path $root "dist"
|
$outDir = Join-Path $root "dist"
|
||||||
$apkName = "ykxmz-watch-1.6.1.apk"
|
$apkName = "ykxmz-watch-1.6.2.apk"
|
||||||
|
|
||||||
function Step($text) { Write-Host "`n=== $text ===" -ForegroundColor Cyan }
|
function Step($text) { Write-Host "`n=== $text ===" -ForegroundColor Cyan }
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ $unsigned = Join-Path $work "app-unsigned.apk"
|
|||||||
--min-sdk-version 24 `
|
--min-sdk-version 24 `
|
||||||
--target-sdk-version 34 `
|
--target-sdk-version 34 `
|
||||||
--version-code 5 `
|
--version-code 5 `
|
||||||
--version-name "1.6.1" `
|
--version-name "1.6.2" `
|
||||||
--auto-add-overlay
|
--auto-add-overlay
|
||||||
if ($LASTEXITCODE -ne 0) { throw "aapt2 link 失败" }
|
if ($LASTEXITCODE -ne 0) { throw "aapt2 link 失败" }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
========================================================
|
========================================================
|
||||||
|
|
||||||
软件名称:ykxmz
|
软件名称:ykxmz
|
||||||
版本:1.6.1
|
版本:1.6.2
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
|
|
||||||
装好之后看这一页:怎么确认它在跑、怎么改设置、
|
装好之后看这一页:怎么确认它在跑、怎么改设置、
|
||||||
@@ -197,7 +197,7 @@
|
|||||||
八、版本记录
|
八、版本记录
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
1.6.1
|
1.6.2
|
||||||
* 跨网络支持:Cloudflare 具名隧道,固定域名
|
* 跨网络支持:Cloudflare 具名隧道,固定域名
|
||||||
* 中转服务器:单设备单配对码、管理页可删设备
|
* 中转服务器:单设备单配对码、管理页可删设备
|
||||||
* 手表端:自动判断局域网/中转并无缝切换
|
* 手表端:自动判断局域网/中转并无缝切换
|
||||||
@@ -209,6 +209,6 @@
|
|||||||
|
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
软件:ykxmz 1.6.1
|
软件:ykxmz 1.6.2
|
||||||
许可条款见《许可协议》(LICENSE.txt)
|
许可条款见《许可协议》(LICENSE.txt)
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
========================================================
|
========================================================
|
||||||
|
|
||||||
软件名称:ykxmz
|
软件名称:ykxmz
|
||||||
版本:1.6.1
|
版本:1.6.2
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
|
|
||||||
请你**在安装之前**花三分钟读完这一页。里面有几条很要紧的
|
请你**在安装之前**花三分钟读完这一页。里面有几条很要紧的
|
||||||
@@ -152,6 +152,6 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
|
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
软件:ykxmz 1.6.1
|
软件:ykxmz 1.6.2
|
||||||
继续安装,即表示你已阅读并同意《许可协议》。
|
继续安装,即表示你已阅读并同意《许可协议》。
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@
|
|||||||
========================================================
|
========================================================
|
||||||
|
|
||||||
软件名称:ykxmz(远程管理工具)
|
软件名称:ykxmz(远程管理工具)
|
||||||
版本:1.6.1
|
版本:1.6.2
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
生效日期:2026 年 10 月 5 日
|
生效日期:2026 年 10 月 5 日
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
|
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
软件:ykxmz 1.6.1
|
软件:ykxmz 1.6.2
|
||||||
|
|
||||||
如果你不同意本协议的任何一条,请不要安装或使用本软件。
|
如果你不同意本协议的任何一条,请不要安装或使用本软件。
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ from collections import deque
|
|||||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
VERSION = "1.6.1"
|
VERSION = "1.6.2"
|
||||||
|
|
||||||
# ---------------- 参数(都能用环境变量覆盖)----------------
|
# ---------------- 参数(都能用环境变量覆盖)----------------
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""局域网遥控 · Windows 被控端。"""
|
"""局域网遥控 · Windows 被控端。"""
|
||||||
|
|
||||||
__version__ = "1.6.1"
|
__version__ = "1.6.2"
|
||||||
APP_NAME = "局域网遥控 被控端"
|
APP_NAME = "局域网遥控 被控端"
|
||||||
|
|||||||
@@ -253,6 +253,20 @@ class RelayLink:
|
|||||||
self._log("没配置中转地址,跳过")
|
self._log("没配置中转地址,跳过")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# 上次连通的地址排到最前面。
|
||||||
|
# 设备 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
|
self.candidates = candidates
|
||||||
# 先探一遍,挑第一个通的
|
# 先探一遍,挑第一个通的
|
||||||
chosen = self._pick_candidate(candidates)
|
chosen = self._pick_candidate(candidates)
|
||||||
@@ -260,6 +274,14 @@ class RelayLink:
|
|||||||
if len(candidates) > 1:
|
if len(candidates) > 1:
|
||||||
self._log(f"中转地址候选 {len(candidates)} 个,选用 {chosen}")
|
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
|
||||||
|
|
||||||
self.device_id = self._ensure_device_id()
|
self.device_id = self._ensure_device_id()
|
||||||
self.code = str(self.store.pairing_code() or "")
|
self.code = str(self.store.pairing_code() or "")
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,10 @@ class Session:
|
|||||||
# 几十毫秒,而且地址永远不变)
|
# 几十毫秒,而且地址永远不变)
|
||||||
# 电脑在外面 -> 第一个连不上,自动切第二个(Cloudflare 隧道,
|
# 电脑在外面 -> 第一个连不上,自动切第二个(Cloudflare 隧道,
|
||||||
# 600 毫秒左右,地址固定 relay.xxmxxs.top)
|
# 600 毫秒左右,地址固定 relay.xxmxxs.top)
|
||||||
DEFAULT_RELAY_URL = "192.168.10.105:8080;https://relay.xxmxxs.top"
|
# 内置的中转地址:局域网优先,连不上自动切公网隧道。
|
||||||
|
# 第一个是随身 WiFi 的固定地址(写死是因为它常在同一网段、直连最快);
|
||||||
|
# 它变了也没关系 —— 连上过的地址会被记住并排到最前面。
|
||||||
|
DEFAULT_RELAY_URL = "192.168.2.156:8080;https://relay.xxmxxs.top"
|
||||||
|
|
||||||
|
|
||||||
class RemoteServer:
|
class RemoteServer:
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ VSVersionInfo(
|
|||||||
[
|
[
|
||||||
StringStruct("CompanyName", "ykxmz"),
|
StringStruct("CompanyName", "ykxmz"),
|
||||||
StringStruct("FileDescription", "ykxmz"),
|
StringStruct("FileDescription", "ykxmz"),
|
||||||
StringStruct("FileVersion", "1.6.1.0"),
|
StringStruct("FileVersion", "1.6.2.0"),
|
||||||
StringStruct("InternalName", "ykxmz"),
|
StringStruct("InternalName", "ykxmz"),
|
||||||
StringStruct("LegalCopyright", "ykxmz"),
|
StringStruct("LegalCopyright", "ykxmz"),
|
||||||
StringStruct("OriginalFilename", "ykxmz.exe"),
|
StringStruct("OriginalFilename", "ykxmz.exe"),
|
||||||
StringStruct("ProductName", "ykxmz"),
|
StringStruct("ProductName", "ykxmz"),
|
||||||
StringStruct("ProductVersion", "1.6.1.0"),
|
StringStruct("ProductVersion", "1.6.2.0"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user