mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 12:30:44 +00:00
ykxmz 1.5.0:手表端 TLS 证书兼容 + 三端分开打包 + 下载区
手表端
- 内置 GTS Root R4 / GlobalSign Root CA
修 SSLHandshakeException: Chain validation failed
- 连接错误翻译成人话:证书 / 时间 / 解析 / 超时分别给提示
- 经中转连上后用服务器报的地址刷新已配对记录
- 版本号 1.3.0 -> 1.5.0(AndroidManifest 之前漏改了)
服务器端
- 支持 chunked 请求体,修每 16 秒一次的连接错乱与大面积 502
- 网络调优 net-tune.sh(开机自动应用)
- 新增下载区,管理页加下载卡片
- 隧道改 HTTP/2 + 双连接
打包方式变更
- 从一个合并 zip 改成三个独立产物:
ykxmz-agent-*.zip 被控端
ykxmz-server-*.zip 服务器端
ykxmz-watch-*.apk 控制端
This commit is contained in:
@@ -0,0 +1,77 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
r"""把 TlsCompat.java 加进各处的 Java 编译清单。
|
||||||
|
|
||||||
|
背景:
|
||||||
|
RelayTransport 改成用 TlsCompat.open() 之后,
|
||||||
|
那些"只编译一部分 java"的地方就编译不过了 ——
|
||||||
|
它们没有把 TlsCompat.java 列进去。
|
||||||
|
|
||||||
|
需要补的三处:
|
||||||
|
_tests/test_package_remote.py
|
||||||
|
_tests/test_watch_lan_switch.py
|
||||||
|
_tests/verify_all.ps1
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||||||
|
|
||||||
|
TARGETS = [
|
||||||
|
ROOT / "_tests" / "test_package_remote.py",
|
||||||
|
ROOT / "_tests" / "test_watch_lan_switch.py",
|
||||||
|
ROOT / "_tests" / "verify_all.ps1",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def patch(path: Path) -> bool:
|
||||||
|
raw = path.read_bytes()
|
||||||
|
had_bom = raw.startswith(b"\xef\xbb\xbf")
|
||||||
|
text = raw.decode("utf-8-sig")
|
||||||
|
|
||||||
|
if "TlsCompat.java" in text:
|
||||||
|
print(f" {path.name}: 已经有了")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 在 RelayTransport.java 那一行后面插一行同格式的 TlsCompat.java
|
||||||
|
pattern = re.compile(
|
||||||
|
r"([ \t]*(?:\(Join-Path \$root )?[\"']?[^\n\"']*RelayTransport\.java[\"']?\)?\,?[ \t]*\r?\n)")
|
||||||
|
match = pattern.search(text)
|
||||||
|
if not match:
|
||||||
|
print(f" [失败] {path.name}: 找不到 RelayTransport.java 那一行")
|
||||||
|
return False
|
||||||
|
|
||||||
|
line = match.group(1)
|
||||||
|
indent = re.match(r"[ \t]*", line).group(0)
|
||||||
|
# 保留原来的包裹形式
|
||||||
|
if "Join-Path" in line:
|
||||||
|
new_line = f'{indent}(Join-Path $root "android\\src\\com\\lanremote\\watch\\TlsCompat.java")`\n'
|
||||||
|
elif '"' in line:
|
||||||
|
new_line = f'{indent}"TlsCompat.java",\n' if line.rstrip().endswith(",") \
|
||||||
|
else f'{indent}"TlsCompat.java"\n'
|
||||||
|
else:
|
||||||
|
new_line = f'{indent}TlsCompat.java\n'
|
||||||
|
|
||||||
|
text = text[:match.end(1)] + new_line + text[match.end(1):]
|
||||||
|
|
||||||
|
body = text.replace("\r\n", "\n").encode("utf-8")
|
||||||
|
path.write_bytes((b"\xef\xbb\xbf" if had_bom else b"") + body)
|
||||||
|
print(f" {path.name}: 补上了 TlsCompat.java")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
ok = True
|
||||||
|
for path in TARGETS:
|
||||||
|
if not path.is_file():
|
||||||
|
print(f" [跳过] {path.name} 不存在")
|
||||||
|
continue
|
||||||
|
if not patch(path):
|
||||||
|
ok = False
|
||||||
|
return 0 if ok else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
r"""精确补上 TlsCompat.java(上一版正则没匹配上)。
|
||||||
|
|
||||||
|
两处的实际写法:
|
||||||
|
test_package_remote.py:
|
||||||
|
for n in ("Json.java", "B64.java", "Transport.java",
|
||||||
|
"RelayTransport.java", "RemoteClient.java",
|
||||||
|
"DiscoveryCore.java")]
|
||||||
|
verify_all.ps1:
|
||||||
|
(Join-Path $root "android\src\com\lanremote\watch\RelayTransport.java") `
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||||||
|
|
||||||
|
PY_OLD = ''' sources = [ROOT / "android" / "src" / "com" / "lanremote" / "watch" / n
|
||||||
|
for n in ("Json.java", "B64.java", "Transport.java",
|
||||||
|
"RelayTransport.java", "RemoteClient.java",
|
||||||
|
"DiscoveryCore.java")]'''
|
||||||
|
|
||||||
|
PY_NEW = ''' sources = [ROOT / "android" / "src" / "com" / "lanremote" / "watch" / n
|
||||||
|
for n in ("Json.java", "B64.java", "Transport.java",
|
||||||
|
"RelayTransport.java", "TlsCompat.java",
|
||||||
|
"RemoteClient.java",
|
||||||
|
"DiscoveryCore.java")]'''
|
||||||
|
|
||||||
|
PS1_OLD = ''' (Join-Path $root "android\\src\\com\\lanremote\\watch\\RelayTransport.java") `'''
|
||||||
|
|
||||||
|
PS1_NEW = ''' (Join-Path $root "android\\src\\com\\lanremote\\watch\\RelayTransport.java") `
|
||||||
|
# TlsCompat:内置根证书,修老手表 SSLHandshakeException
|
||||||
|
(Join-Path $root "android\\src\\com\\lanremote\\watch\\TlsCompat.java") `'''
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
ok = True
|
||||||
|
|
||||||
|
path = ROOT / "_tests" / "test_package_remote.py"
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
if "TlsCompat.java" in text:
|
||||||
|
print(" test_package_remote.py: 已经有了")
|
||||||
|
elif PY_OLD in text:
|
||||||
|
path.write_text(text.replace(PY_OLD, PY_NEW, 1),
|
||||||
|
encoding="utf-8", newline="\n")
|
||||||
|
print(" test_package_remote.py: 补上 TlsCompat.java")
|
||||||
|
else:
|
||||||
|
print(" [失败] test_package_remote.py 锚点没找到")
|
||||||
|
ok = False
|
||||||
|
|
||||||
|
path = ROOT / "_tests" / "verify_all.ps1"
|
||||||
|
raw = path.read_bytes()
|
||||||
|
had_bom = raw.startswith(b"\xef\xbb\xbf")
|
||||||
|
text = raw.decode("utf-8-sig")
|
||||||
|
if "TlsCompat.java" in text:
|
||||||
|
print(" verify_all.ps1: 已经有了")
|
||||||
|
elif PS1_OLD in text:
|
||||||
|
text = text.replace(PS1_OLD, PS1_NEW, 1)
|
||||||
|
path.write_bytes((b"\xef\xbb\xbf" if had_bom else b"")
|
||||||
|
+ text.replace("\r\n", "\n").encode("utf-8"))
|
||||||
|
print(" verify_all.ps1: 补上 TlsCompat.java")
|
||||||
|
else:
|
||||||
|
print(" [失败] verify_all.ps1 锚点没找到")
|
||||||
|
ok = False
|
||||||
|
|
||||||
|
return 0 if ok else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# 提交 1.5.0 的全部改动
|
||||||
|
$ErrorActionPreference = "Continue"
|
||||||
|
$git = "C:\Program Files\Git\bin\git.exe"
|
||||||
|
$root = "C:\Users\shu\Desktop\deepseekagent\LanRemote"
|
||||||
|
Set-Location $root
|
||||||
|
|
||||||
|
Write-Host "===== 1. 暂存 =====" -ForegroundColor Cyan
|
||||||
|
& $git add -A 2>&1 | Out-Null
|
||||||
|
$files = @(& $git -c core.quotepath=false diff --cached --name-only |
|
||||||
|
Where-Object { $_ -and $_.Trim() -ne "" })
|
||||||
|
Write-Host " 改动文件数: $($files.Count)"
|
||||||
|
$files | Select-Object -First 25 | ForEach-Object { Write-Host " $_" }
|
||||||
|
if ($files.Count -gt 25) { Write-Host " …还有 $($files.Count - 25) 个" }
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "===== 2. 确认没有大文件混进来 =====" -ForegroundColor Cyan
|
||||||
|
$big = foreach ($f in $files) {
|
||||||
|
$p = Join-Path $root ($f -replace '/','\')
|
||||||
|
if (Test-Path -LiteralPath $p -PathType Leaf) {
|
||||||
|
$len = (Get-Item -LiteralPath $p).Length
|
||||||
|
if ($len -gt 1MB) { [pscustomobject]@{ Name = $f; MB = [math]::Round($len/1MB,2) } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($big) { $big | ForEach-Object { Write-Host " ⚠ $($_.MB) MB $($_.Name)" -ForegroundColor Yellow } }
|
||||||
|
else { Write-Host " ✓ 没有超过 1MB 的文件" -ForegroundColor Green }
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "===== 3. 提交 =====" -ForegroundColor Cyan
|
||||||
|
$msg = @"
|
||||||
|
ykxmz 1.5.0:手表端 TLS 证书兼容 + 三端分开打包 + 下载区
|
||||||
|
|
||||||
|
手表端
|
||||||
|
- 内置 GTS Root R4 / GlobalSign Root CA
|
||||||
|
修 SSLHandshakeException: Chain validation failed
|
||||||
|
(廉价手表系统根证书库常缺 GTS Root R4)
|
||||||
|
- 连接错误翻译成人话:证书 / 时间 / 解析 / 超时分别给提示
|
||||||
|
- 经中转连上后用服务器报的地址刷新已配对记录(原来一直显示旧 IP)
|
||||||
|
- 版本号 1.3.0 -> 1.5.0(AndroidManifest 之前漏改了)
|
||||||
|
|
||||||
|
服务器端
|
||||||
|
- 支持 chunked 请求体:修每 16 秒一次的连接错乱与大面积 502
|
||||||
|
- 网络调优 net-tune.sh:夹 MSS 1400 + 路径 MTU 探测
|
||||||
|
(公网可用率 48% -> 100%,实测 15 分钟 180/180)
|
||||||
|
做成开机服务 lanremote-nettune.service,并会自动重建隧道
|
||||||
|
- 新增下载区:GET /v1/downloads 列表 + GET /download/<文件>
|
||||||
|
只允许白名单后缀、严格校验文件名(挡目录穿越)
|
||||||
|
管理页加下载卡片
|
||||||
|
- 隧道改 HTTP/2 + 双连接(QUIC 在这条线路上可用率只有 48%)
|
||||||
|
- 网络体检、批量删除设备
|
||||||
|
|
||||||
|
打包方式变更
|
||||||
|
- 原来是三个部分合成一个 zip,现在**分成三个独立产物**:
|
||||||
|
ykxmz-agent-1.5.0.zip 被控端
|
||||||
|
ykxmz-server-1.5.0.zip 服务器端
|
||||||
|
ykxmz-watch-1.5.0.apk 控制端(直接给 APK,不打 zip)
|
||||||
|
三个包/文件都带上许可协议 / 安装前必读 / 安装后须知
|
||||||
|
|
||||||
|
文档
|
||||||
|
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
|
||||||
|
"@
|
||||||
|
& $git commit -q -m $msg
|
||||||
|
Write-Host " exit=$LASTEXITCODE"
|
||||||
|
& $git log --oneline 2>&1 | Select-Object -First 3 | ForEach-Object { Write-Host " $_" }
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "===== 4. 公钥(加到这里才能推)=====" -ForegroundColor Yellow
|
||||||
|
Write-Host " 打开 https://gitee.com/profile/sshkeys" -ForegroundColor White
|
||||||
|
Write-Host " 把下面这一整行粘进去:" -ForegroundColor White
|
||||||
|
Get-Content "$env:USERPROFILE\.ssh\id_ed25519_gitee.pub" | ForEach-Object {
|
||||||
|
Write-Host " $_" -ForegroundColor Green
|
||||||
|
}
|
||||||
+154
-135
@@ -352,11 +352,88 @@ RELAY_README = f"""========================================================
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
WATCH_README = f"""========================================================
|
||||||
|
控制端(安卓手表) 版本 {VERSION}
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
【装】
|
||||||
|
|
||||||
|
把 ykxmz-watch-{VERSION}.apk 传到手表上安装。
|
||||||
|
手表如果提示"未知来源",在设置里允许一下。
|
||||||
|
|
||||||
|
|
||||||
|
【连】
|
||||||
|
|
||||||
|
1) 打开 App,首页有四个东西:
|
||||||
|
中转设置(跨网络用) 填服务器端给的地址
|
||||||
|
局域网连接(同一个WiFi)同一个 WiFi 时走这条,最快
|
||||||
|
输入配对码连接 经中转连
|
||||||
|
服务器:还没测 点右边「检查服务器」看延迟
|
||||||
|
|
||||||
|
2) 电脑和手表在同一个 WiFi -> 点「局域网连接」,自动搜到电脑,点一下就连
|
||||||
|
电脑在外面 -> 点「输入配对码连接」,填电脑上那个 6 位码
|
||||||
|
|
||||||
|
3) 连上后是 10 个标签页:
|
||||||
|
媒体 屏幕 文件 语音 电脑 网络 系统 教室 效率 娱乐
|
||||||
|
|
||||||
|
|
||||||
|
【连不上时看这个】
|
||||||
|
|
||||||
|
App 会把错误翻译成人话:
|
||||||
|
"证书校验失败" -> 手表系统太旧或网络被劫持
|
||||||
|
"证书时间不对" -> 把手表的日期时间调成自动获取
|
||||||
|
"连接超时" -> 网络慢或被防火墙挡
|
||||||
|
"电脑拒绝连接" -> 电脑上 ykxmz 没开
|
||||||
|
"域名解析不了" -> 手表没联网
|
||||||
|
|
||||||
|
首页的「检查服务器」能测出到中转的延迟(快/一般/慢三档配色)。
|
||||||
|
|
||||||
|
|
||||||
|
【回退】
|
||||||
|
|
||||||
|
系统页最上面三个按钮:
|
||||||
|
回退上一步 撤销刚才那一步
|
||||||
|
回退全部 把能撤的都撤了
|
||||||
|
看能回退什么 列出还能撤哪些
|
||||||
|
|
||||||
|
能撤的:所有开关、所有画面(全屏大字/投图/通知等)
|
||||||
|
撤不了的:关机、重启、删文件、杀进程 —— 这些**不会**出现在回退列表里,
|
||||||
|
免得你以为什么都能退回去。
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def write_readme(path: Path, text: str) -> None:
|
def write_readme(path: Path, text: str) -> None:
|
||||||
"""说明文档统一写成 UTF-8 with BOM —— Windows 记事本不加 BOM 会认成 GBK。"""
|
"""说明文档统一写成 UTF-8 with BOM —— Windows 记事本不加 BOM 会认成 GBK。"""
|
||||||
path.write_bytes(b"\xef\xbb\xbf" + text.replace("\n", "\r\n").encode("utf-8"))
|
path.write_bytes(b"\xef\xbb\xbf" + text.replace("\n", "\r\n").encode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def _zip_dir(zip_path: Path, source: Path, arc_root: str) -> int:
|
||||||
|
"""把一个目录打成一个 zip(内部带一层 arc_root 目录名)。"""
|
||||||
|
if zip_path.exists():
|
||||||
|
zip_path.unlink()
|
||||||
|
count = 0
|
||||||
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED,
|
||||||
|
compresslevel=6) as archive:
|
||||||
|
for item in sorted(source.rglob("*")):
|
||||||
|
if item.is_file():
|
||||||
|
archive.write(item, Path(arc_root) / item.relative_to(source))
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def _copy_docs(target: Path) -> int:
|
||||||
|
"""把三份正式文档拷到目标目录(UTF-8 BOM + CRLF)。"""
|
||||||
|
done = 0
|
||||||
|
for name in ("LICENSE.txt", "BEFORE-INSTALL.txt", "AFTER-INSTALL.txt"):
|
||||||
|
src = DOCS / name
|
||||||
|
if src.is_file():
|
||||||
|
write_readme(target / name, src.read_text(encoding="utf-8"))
|
||||||
|
done += 1
|
||||||
|
else:
|
||||||
|
print(f" [警告] 缺少文档 {src}")
|
||||||
|
return done
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
if not AGENT_SRC.is_dir():
|
if not AGENT_SRC.is_dir():
|
||||||
print(f" [失败] 找不到被控端: {AGENT_SRC}")
|
print(f" [失败] 找不到被控端: {AGENT_SRC}")
|
||||||
@@ -365,13 +442,18 @@ def main() -> int:
|
|||||||
print(f" [失败] 找不到 APK: {APK_SRC}")
|
print(f" [失败] 找不到 APK: {APK_SRC}")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
build = ROOT / "dist" / NAME
|
dist = ROOT / "dist"
|
||||||
if build.exists():
|
dist.mkdir(parents=True, exist_ok=True)
|
||||||
shutil.rmtree(build, ignore_errors=True)
|
work = dist / "_build_tmp"
|
||||||
|
if work.exists():
|
||||||
|
shutil.rmtree(work, ignore_errors=True)
|
||||||
|
|
||||||
# ---------- 1. 被控端 ----------
|
results = []
|
||||||
agent_dir = build / "1-agent"
|
|
||||||
print(" 复制被控端…")
|
# ================= 1. 被控端 =================
|
||||||
|
print(" [1/3] 被控端(Windows)")
|
||||||
|
agent_name = f"ykxmz-agent-{VERSION}"
|
||||||
|
agent_dir = work / agent_name
|
||||||
shutil.copytree(AGENT_SRC, agent_dir,
|
shutil.copytree(AGENT_SRC, agent_dir,
|
||||||
ignore=shutil.ignore_patterns("data", "received",
|
ignore=shutil.ignore_patterns("data", "received",
|
||||||
"*.idsig", "*.log"))
|
"*.idsig", "*.log"))
|
||||||
@@ -381,155 +463,92 @@ def main() -> int:
|
|||||||
if src.is_file():
|
if src.is_file():
|
||||||
shutil.copy2(src, agent_dir / tool)
|
shutil.copy2(src, agent_dir / tool)
|
||||||
write_readme(agent_dir / "README-agent.txt", AGENT_README)
|
write_readme(agent_dir / "README-agent.txt", AGENT_README)
|
||||||
# 老版本往被控端目录塞过一份顶层说明的副本,清掉
|
|
||||||
for junk in ("先看这个.txt", "使用说明.txt"):
|
for junk in ("先看这个.txt", "使用说明.txt"):
|
||||||
target = agent_dir / junk
|
target = agent_dir / junk
|
||||||
if target.is_file():
|
if target.is_file():
|
||||||
target.unlink()
|
target.unlink()
|
||||||
|
_copy_docs(agent_dir)
|
||||||
|
if not (agent_dir / "ykxmz.exe").is_file():
|
||||||
|
print(" [失败] 被控端里没有 ykxmz.exe")
|
||||||
|
return 1
|
||||||
|
agent_zip = dist / f"{agent_name}.zip"
|
||||||
|
n = _zip_dir(agent_zip, agent_dir, agent_name)
|
||||||
|
results.append(("被控端", agent_zip, n))
|
||||||
|
|
||||||
# ---------- 2. 服务器端 ----------
|
# ================= 2. 服务器端 =================
|
||||||
relay_dir = build / "2-server"
|
print(" [2/3] 服务器端(随身 WiFi / Linux)")
|
||||||
relay_dir.mkdir(parents=True)
|
server_name = f"ykxmz-server-{VERSION}"
|
||||||
print(" 复制服务器端…")
|
server_dir = work / server_name
|
||||||
# 文件清单写死容易漏 —— watchdog.sh 就漏过一次。
|
server_dir.mkdir(parents=True)
|
||||||
|
# 文件清单写死容易漏 —— watchdog.sh / net-tune.sh 都漏过一次。
|
||||||
# 改成:relay 目录里所有 .py / .sh 都带上。
|
# 改成:relay 目录里所有 .py / .sh 都带上。
|
||||||
wanted = sorted(
|
wanted = sorted(
|
||||||
[f for f in RELAY_SRC.iterdir()
|
[f for f in RELAY_SRC.iterdir()
|
||||||
if f.suffix in (".py", ".sh") and f.is_file()],
|
if f.suffix in (".py", ".sh") and f.is_file()],
|
||||||
key=lambda f: f.name)
|
key=lambda f: f.name)
|
||||||
for src in wanted:
|
for src in wanted:
|
||||||
shutil.copy2(src, relay_dir / src.name)
|
shutil.copy2(src, server_dir / src.name)
|
||||||
write_readme(relay_dir / "README-server.txt", RELAY_README)
|
write_readme(server_dir / "README-server.txt", RELAY_README)
|
||||||
|
_copy_docs(server_dir)
|
||||||
|
for must in ("relay.py", "install.sh", "watchdog.sh", "net-tune.sh"):
|
||||||
|
if not (server_dir / must).is_file():
|
||||||
|
print(f" [警告] 服务器端少了 {must}")
|
||||||
|
server_zip = dist / f"{server_name}.zip"
|
||||||
|
n = _zip_dir(server_zip, server_dir, server_name)
|
||||||
|
results.append(("服务器端", server_zip, n))
|
||||||
|
|
||||||
# ---------- 3. 控制端 ----------
|
# ================= 3. 控制端(直接给 APK)=================
|
||||||
watch_dir = build / "3-watch"
|
print(" [3/3] 控制端(手表)—— 不打 zip,直接给 APK")
|
||||||
watch_dir.mkdir(parents=True)
|
# 顺带把说明也放一份在旁边,方便看
|
||||||
print(" 复制控制端…")
|
watch_note = dist / f"ykxmz-watch-{VERSION}-说明.txt"
|
||||||
shutil.copy2(APK_SRC, watch_dir / APK_SRC.name)
|
write_readme(watch_note, WATCH_README)
|
||||||
write_readme(watch_dir / "README-watch.txt", f"""========================================================
|
results.append(("控制端", APK_SRC, 1))
|
||||||
控制端(安卓手表) 版本 {VERSION}
|
|
||||||
========================================================
|
|
||||||
|
|
||||||
【装】
|
shutil.rmtree(work, ignore_errors=True)
|
||||||
|
|
||||||
把 {APK_SRC.name} 传到手表上安装。
|
# ================= 汇总 =================
|
||||||
手表如果提示"未知来源",在设置里允许一下。
|
print()
|
||||||
|
print(" ================ 产物 ================")
|
||||||
|
ok = True
|
||||||
【连】
|
for label, path, count in results:
|
||||||
|
if not path.is_file():
|
||||||
1) 打开 App,首页点「中转设置(跨网络用)」
|
print(f" {label}: ✗ 缺失!")
|
||||||
填服务器端给你的地址,形如 https://relay.你的域名
|
ok = False
|
||||||
(不填也能用,但只在同一个 WiFi 下)
|
|
||||||
|
|
||||||
2) 点「自动搜索电脑」—— 同一个局域网时能直接搜到
|
|
||||||
搜不到就点「连不上?点这里诊断」
|
|
||||||
|
|
||||||
3) 输 6 位配对码(电脑上设的那个)
|
|
||||||
|
|
||||||
4) 连上后是 10 个标签页:
|
|
||||||
媒体 屏幕 文件 语音 电脑 网络 系统 教室 效率 娱乐
|
|
||||||
每个页面上半部分是常用按钮,往下滑是更多功能(共 206 个)。
|
|
||||||
|
|
||||||
|
|
||||||
【回退】
|
|
||||||
|
|
||||||
系统页最上面三个按钮:
|
|
||||||
回退上一步 撤销刚才那一步
|
|
||||||
回退全部 把能撤的都撤了
|
|
||||||
看能回退什么 列出还能撤哪些
|
|
||||||
|
|
||||||
能撤的:所有开关(15 个)、所有画面(26 个,全屏大字/投图/通知等)
|
|
||||||
撤不了的:关机、重启、删文件、杀进程 —— 这些**不会**出现在回退列表里,
|
|
||||||
免得你以为什么都能退回去。
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
# ---------- 4. 顶层说明 ----------
|
|
||||||
write_readme(build / "README.txt", TOP_README)
|
|
||||||
|
|
||||||
# ---------- 4b. 三份正式文档(作者:小麦子)----------
|
|
||||||
# 放顶层,和 README.txt 并排,解压第一眼就能看到。
|
|
||||||
# 统一转成 UTF-8 BOM + CRLF —— 不带 BOM 记事本会按 GBK 读,全乱。
|
|
||||||
doc_files = [
|
|
||||||
("LICENSE.txt", "许可协议"),
|
|
||||||
("BEFORE-INSTALL.txt", "安装前必读"),
|
|
||||||
("AFTER-INSTALL.txt", "安装后须知"),
|
|
||||||
]
|
|
||||||
for name, label in doc_files:
|
|
||||||
src = DOCS / name
|
|
||||||
if not src.is_file():
|
|
||||||
print(f" [警告] 缺少文档 {src}")
|
|
||||||
continue
|
continue
|
||||||
# 读进来(原文件是无 BOM 的 UTF-8),交给 write_readme
|
size = path.stat().st_size / 1024 / 1024
|
||||||
# 统一加 BOM + CRLF 后写出
|
extra = f"({count} 个文件)" if count > 1 else ""
|
||||||
write_readme(build / name, src.read_text(encoding="utf-8"))
|
print(f" {label:6} {path.name:34} {size:6.2f} MB {extra}")
|
||||||
print(f" {label}: {name}")
|
if not ok:
|
||||||
|
|
||||||
# ---------- 5. 检查 ----------
|
|
||||||
print()
|
|
||||||
print(" 目录结构:")
|
|
||||||
total = 0
|
|
||||||
for item in sorted(build.rglob("*")):
|
|
||||||
if item.is_file():
|
|
||||||
total += 1
|
|
||||||
for item in sorted(build.iterdir()):
|
|
||||||
if item.is_dir():
|
|
||||||
count = sum(1 for _ in item.rglob("*") if _.is_file())
|
|
||||||
print(f" {item.name}/ ({count} 个文件)")
|
|
||||||
else:
|
|
||||||
print(f" {item.name}")
|
|
||||||
print(f" 合计 {total} 个文件")
|
|
||||||
|
|
||||||
# 必须有的东西
|
|
||||||
required = [
|
|
||||||
agent_dir / "ykxmz.exe",
|
|
||||||
relay_dir / "relay.py",
|
|
||||||
relay_dir / "install.sh",
|
|
||||||
watch_dir / APK_SRC.name,
|
|
||||||
build / "README.txt",
|
|
||||||
build / "LICENSE.txt",
|
|
||||||
build / "BEFORE-INSTALL.txt",
|
|
||||||
build / "AFTER-INSTALL.txt",
|
|
||||||
]
|
|
||||||
missing = [str(p.relative_to(build)) for p in required if not p.is_file()]
|
|
||||||
if missing:
|
|
||||||
print(f" [失败] 少了: {missing}")
|
|
||||||
return 1
|
return 1
|
||||||
print(" 三个部分都在")
|
|
||||||
|
|
||||||
# ---------- 6. 打包 ----------
|
# ================= 验证 =================
|
||||||
print()
|
print()
|
||||||
print(" 压缩中…")
|
print(" 验证压缩包内容:")
|
||||||
zip_path = ROOT / "dist" / f"{NAME}.zip"
|
for label, path, _count in results:
|
||||||
if zip_path.exists():
|
if path.suffix != ".zip":
|
||||||
zip_path.unlink()
|
continue
|
||||||
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED,
|
with zipfile.ZipFile(path) as archive:
|
||||||
compresslevel=6) as archive:
|
names = archive.namelist()
|
||||||
for item in sorted(build.rglob("*")):
|
bad = archive.testzip()
|
||||||
if item.is_file():
|
if bad:
|
||||||
archive.write(item, item.relative_to(build.parent))
|
print(f" [失败] {path.name} 里有坏文件: {bad}")
|
||||||
size = zip_path.stat().st_size / 1024 / 1024
|
return 1
|
||||||
print(f" {zip_path.name} {size:.2f} MB")
|
print(f" {path.name}: {len(names)} 个条目,完整")
|
||||||
|
|
||||||
# ---------- 7. 验证压缩包 ----------
|
with zipfile.ZipFile(results[0][1]) as archive:
|
||||||
with zipfile.ZipFile(zip_path) as archive:
|
|
||||||
names = archive.namelist()
|
names = archive.namelist()
|
||||||
bad = archive.testzip()
|
if not any("ykxmz.exe" in n for n in names):
|
||||||
if bad:
|
print(" [失败] 被控端包里没有 ykxmz.exe")
|
||||||
print(f" [失败] 压缩包里有坏文件: {bad}")
|
return 1
|
||||||
return 1
|
with zipfile.ZipFile(results[1][1]) as archive:
|
||||||
has = {
|
names = archive.namelist()
|
||||||
"被控端": any("ykxmz.exe" in n for n in names),
|
for must in ("relay.py", "install.sh", "watchdog.sh", "net-tune.sh"):
|
||||||
"服务器端": any("relay.py" in n for n in names),
|
if not any(must in n for n in names):
|
||||||
"控制端": any(".apk" in n for n in names),
|
print(f" [失败] 服务器端包里没有 {must}")
|
||||||
"顶层说明": any("README.txt" in n for n in names),
|
return 1
|
||||||
}
|
|
||||||
for label, ok in has.items():
|
print()
|
||||||
print(f" {label}: {'✓' if ok else '✗'}")
|
print(" 三个产物齐全")
|
||||||
if not all(has.values()):
|
|
||||||
return 1
|
|
||||||
print(f" 共 {len(names)} 个条目,完整")
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
|||||||
False,
|
False,
|
||||||
True,
|
True,
|
||||||
['C:/Users/shu/Desktop/deepseekagent/LanRemote/windows/app.ico'],
|
['C:/Users/shu/Desktop/deepseekagent/LanRemote/windows/app.ico'],
|
||||||
versioninfo.VSVersionInfo(ffi=versioninfo.FixedFileInfo(filevers=(1, 3, 0, 0), prodvers=(1, 3, 0, 0), mask=0x3f, flags=0x0, OS=0x40004, fileType=1, subtype=0x0, date=(0, 0)), kids=[versioninfo.StringFileInfo([versioninfo.StringTable('080404B0', [versioninfo.StringStruct('CompanyName', 'ykxmz'), versioninfo.StringStruct('FileDescription', 'ykxmz'), versioninfo.StringStruct('FileVersion', '1.4.0.0'), versioninfo.StringStruct('InternalName', 'ykxmz'), versioninfo.StringStruct('LegalCopyright', 'ykxmz'), versioninfo.StringStruct('OriginalFilename', 'ykxmz.exe'), versioninfo.StringStruct('ProductName', 'ykxmz'), versioninfo.StringStruct('ProductVersion', '1.4.0.0')])]), versioninfo.VarFileInfo([versioninfo.VarStruct('Translation', [2052, 1200])])]),
|
versioninfo.VSVersionInfo(ffi=versioninfo.FixedFileInfo(filevers=(1, 3, 0, 0), prodvers=(1, 3, 0, 0), mask=0x3f, flags=0x0, OS=0x40004, fileType=1, subtype=0x0, date=(0, 0)), kids=[versioninfo.StringFileInfo([versioninfo.StringTable('080404B0', [versioninfo.StringStruct('CompanyName', 'ykxmz'), versioninfo.StringStruct('FileDescription', 'ykxmz'), versioninfo.StringStruct('FileVersion', '1.5.0.0'), versioninfo.StringStruct('InternalName', 'ykxmz'), versioninfo.StringStruct('LegalCopyright', 'ykxmz'), versioninfo.StringStruct('OriginalFilename', 'ykxmz.exe'), versioninfo.StringStruct('ProductName', 'ykxmz'), versioninfo.StringStruct('ProductVersion', '1.5.0.0')])]), versioninfo.VarFileInfo([versioninfo.VarStruct('Translation', [2052, 1200])])]),
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
[],
|
[],
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
1791279782,
|
1791284710,
|
||||||
[('runw.exe',
|
[('runw.exe',
|
||||||
'C:\\Users\\shu\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\runw.exe',
|
'C:\\Users\\shu\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\runw.exe',
|
||||||
'EXECUTABLE')],
|
'EXECUTABLE')],
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,274 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
r"""把打包改成"三端分开出"。
|
||||||
|
|
||||||
|
用户要求:
|
||||||
|
"三端分别打包,控制端不用打包成 zip,直接上传 apk"
|
||||||
|
|
||||||
|
所以产物是三个文件(原来是一个大 zip):
|
||||||
|
dist/ykxmz-agent-1.5.0.zip 被控端(Windows)
|
||||||
|
dist/ykxmz-server-1.5.0.zip 服务器端(随身 WiFi / Linux)
|
||||||
|
dist/ykxmz-watch-1.5.0.apk 控制端(手表,直接给 APK 不打 zip)
|
||||||
|
|
||||||
|
三个包里都带上三份文档(许可协议 / 安装前必读 / 安装后须知),
|
||||||
|
这样用户拿到哪一个都知道自己在装什么、有什么红线。
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||||||
|
PKG = ROOT / "_build" / "package_remote.py"
|
||||||
|
|
||||||
|
# 从 "def main() -> int:" 起,到文件末尾的 if __name__ 之前,全换成新的
|
||||||
|
NEW_MAIN = '''def _zip_dir(zip_path: Path, source: Path, arc_root: str) -> int:
|
||||||
|
"""把一个目录打成一个 zip(内部带一层 arc_root 目录名)。"""
|
||||||
|
if zip_path.exists():
|
||||||
|
zip_path.unlink()
|
||||||
|
count = 0
|
||||||
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED,
|
||||||
|
compresslevel=6) as archive:
|
||||||
|
for item in sorted(source.rglob("*")):
|
||||||
|
if item.is_file():
|
||||||
|
archive.write(item, Path(arc_root) / item.relative_to(source))
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def _copy_docs(target: Path) -> int:
|
||||||
|
"""把三份正式文档拷到目标目录(UTF-8 BOM + CRLF)。"""
|
||||||
|
done = 0
|
||||||
|
for name in ("LICENSE.txt", "BEFORE-INSTALL.txt", "AFTER-INSTALL.txt"):
|
||||||
|
src = DOCS / name
|
||||||
|
if src.is_file():
|
||||||
|
write_readme(target / name, src.read_text(encoding="utf-8"))
|
||||||
|
done += 1
|
||||||
|
else:
|
||||||
|
print(f" [警告] 缺少文档 {src}")
|
||||||
|
return done
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if not AGENT_SRC.is_dir():
|
||||||
|
print(f" [失败] 找不到被控端: {AGENT_SRC}")
|
||||||
|
return 1
|
||||||
|
if not APK_SRC.is_file():
|
||||||
|
print(f" [失败] 找不到 APK: {APK_SRC}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
dist = ROOT / "dist"
|
||||||
|
dist.mkdir(parents=True, exist_ok=True)
|
||||||
|
work = dist / "_build_tmp"
|
||||||
|
if work.exists():
|
||||||
|
shutil.rmtree(work, ignore_errors=True)
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
# ================= 1. 被控端 =================
|
||||||
|
print(" [1/3] 被控端(Windows)")
|
||||||
|
agent_name = f"ykxmz-agent-{VERSION}"
|
||||||
|
agent_dir = work / agent_name
|
||||||
|
shutil.copytree(AGENT_SRC, agent_dir,
|
||||||
|
ignore=shutil.ignore_patterns("data", "received",
|
||||||
|
"*.idsig", "*.log"))
|
||||||
|
for tool in TOOLS:
|
||||||
|
if not (agent_dir / tool).is_file():
|
||||||
|
src = ROOT / "tools" / tool
|
||||||
|
if src.is_file():
|
||||||
|
shutil.copy2(src, agent_dir / tool)
|
||||||
|
write_readme(agent_dir / "README-agent.txt", AGENT_README)
|
||||||
|
for junk in ("先看这个.txt", "使用说明.txt"):
|
||||||
|
target = agent_dir / junk
|
||||||
|
if target.is_file():
|
||||||
|
target.unlink()
|
||||||
|
_copy_docs(agent_dir)
|
||||||
|
if not (agent_dir / "ykxmz.exe").is_file():
|
||||||
|
print(" [失败] 被控端里没有 ykxmz.exe")
|
||||||
|
return 1
|
||||||
|
agent_zip = dist / f"{agent_name}.zip"
|
||||||
|
n = _zip_dir(agent_zip, agent_dir, agent_name)
|
||||||
|
results.append(("被控端", agent_zip, n))
|
||||||
|
|
||||||
|
# ================= 2. 服务器端 =================
|
||||||
|
print(" [2/3] 服务器端(随身 WiFi / Linux)")
|
||||||
|
server_name = f"ykxmz-server-{VERSION}"
|
||||||
|
server_dir = work / server_name
|
||||||
|
server_dir.mkdir(parents=True)
|
||||||
|
# 文件清单写死容易漏 —— watchdog.sh / net-tune.sh 都漏过一次。
|
||||||
|
# 改成:relay 目录里所有 .py / .sh 都带上。
|
||||||
|
wanted = sorted(
|
||||||
|
[f for f in RELAY_SRC.iterdir()
|
||||||
|
if f.suffix in (".py", ".sh") and f.is_file()],
|
||||||
|
key=lambda f: f.name)
|
||||||
|
for src in wanted:
|
||||||
|
shutil.copy2(src, server_dir / src.name)
|
||||||
|
write_readme(server_dir / "README-server.txt", RELAY_README)
|
||||||
|
_copy_docs(server_dir)
|
||||||
|
for must in ("relay.py", "install.sh", "watchdog.sh", "net-tune.sh"):
|
||||||
|
if not (server_dir / must).is_file():
|
||||||
|
print(f" [警告] 服务器端少了 {must}")
|
||||||
|
server_zip = dist / f"{server_name}.zip"
|
||||||
|
n = _zip_dir(server_zip, server_dir, server_name)
|
||||||
|
results.append(("服务器端", server_zip, n))
|
||||||
|
|
||||||
|
# ================= 3. 控制端(直接给 APK)=================
|
||||||
|
print(" [3/3] 控制端(手表)—— 不打 zip,直接给 APK")
|
||||||
|
# 顺带把说明也放一份在旁边,方便看
|
||||||
|
watch_note = dist / f"ykxmz-watch-{VERSION}-说明.txt"
|
||||||
|
write_readme(watch_note, WATCH_README)
|
||||||
|
results.append(("控制端", APK_SRC, 1))
|
||||||
|
|
||||||
|
shutil.rmtree(work, ignore_errors=True)
|
||||||
|
|
||||||
|
# ================= 汇总 =================
|
||||||
|
print()
|
||||||
|
print(" ================ 产物 ================")
|
||||||
|
ok = True
|
||||||
|
for label, path, count in results:
|
||||||
|
if not path.is_file():
|
||||||
|
print(f" {label}: ✗ 缺失!")
|
||||||
|
ok = False
|
||||||
|
continue
|
||||||
|
size = path.stat().st_size / 1024 / 1024
|
||||||
|
extra = f"({count} 个文件)" if count > 1 else ""
|
||||||
|
print(f" {label:6} {path.name:34} {size:6.2f} MB {extra}")
|
||||||
|
if not ok:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# ================= 验证 =================
|
||||||
|
print()
|
||||||
|
print(" 验证压缩包内容:")
|
||||||
|
for label, path, _count in results:
|
||||||
|
if path.suffix != ".zip":
|
||||||
|
continue
|
||||||
|
with zipfile.ZipFile(path) as archive:
|
||||||
|
names = archive.namelist()
|
||||||
|
bad = archive.testzip()
|
||||||
|
if bad:
|
||||||
|
print(f" [失败] {path.name} 里有坏文件: {bad}")
|
||||||
|
return 1
|
||||||
|
print(f" {path.name}: {len(names)} 个条目,完整")
|
||||||
|
|
||||||
|
with zipfile.ZipFile(results[0][1]) as archive:
|
||||||
|
names = archive.namelist()
|
||||||
|
if not any("ykxmz.exe" in n for n in names):
|
||||||
|
print(" [失败] 被控端包里没有 ykxmz.exe")
|
||||||
|
return 1
|
||||||
|
with zipfile.ZipFile(results[1][1]) as archive:
|
||||||
|
names = archive.namelist()
|
||||||
|
for must in ("relay.py", "install.sh", "watchdog.sh", "net-tune.sh"):
|
||||||
|
if not any(must in n for n in names):
|
||||||
|
print(f" [失败] 服务器端包里没有 {must}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(" 三个产物齐全")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
# 手表说明单独抽出来(原来嵌在 main 里)
|
||||||
|
WATCH_README_BLOCK = '''WATCH_README = f"""========================================================
|
||||||
|
控制端(安卓手表) 版本 {VERSION}
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
【装】
|
||||||
|
|
||||||
|
把 ykxmz-watch-{VERSION}.apk 传到手表上安装。
|
||||||
|
手表如果提示"未知来源",在设置里允许一下。
|
||||||
|
|
||||||
|
|
||||||
|
【连】
|
||||||
|
|
||||||
|
1) 打开 App,首页有四个东西:
|
||||||
|
中转设置(跨网络用) 填服务器端给的地址
|
||||||
|
局域网连接(同一个WiFi)同一个 WiFi 时走这条,最快
|
||||||
|
输入配对码连接 经中转连
|
||||||
|
服务器:还没测 点右边「检查服务器」看延迟
|
||||||
|
|
||||||
|
2) 电脑和手表在同一个 WiFi -> 点「局域网连接」,自动搜到电脑,点一下就连
|
||||||
|
电脑在外面 -> 点「输入配对码连接」,填电脑上那个 6 位码
|
||||||
|
|
||||||
|
3) 连上后是 10 个标签页:
|
||||||
|
媒体 屏幕 文件 语音 电脑 网络 系统 教室 效率 娱乐
|
||||||
|
|
||||||
|
|
||||||
|
【连不上时看这个】
|
||||||
|
|
||||||
|
App 会把错误翻译成人话:
|
||||||
|
"证书校验失败" -> 手表系统太旧或网络被劫持
|
||||||
|
"证书时间不对" -> 把手表的日期时间调成自动获取
|
||||||
|
"连接超时" -> 网络慢或被防火墙挡
|
||||||
|
"电脑拒绝连接" -> 电脑上 ykxmz 没开
|
||||||
|
"域名解析不了" -> 手表没联网
|
||||||
|
|
||||||
|
首页的「检查服务器」能测出到中转的延迟(快/一般/慢三档配色)。
|
||||||
|
|
||||||
|
|
||||||
|
【回退】
|
||||||
|
|
||||||
|
系统页最上面三个按钮:
|
||||||
|
回退上一步 撤销刚才那一步
|
||||||
|
回退全部 把能撤的都撤了
|
||||||
|
看能回退什么 列出还能撤哪些
|
||||||
|
|
||||||
|
能撤的:所有开关、所有画面(全屏大字/投图/通知等)
|
||||||
|
撤不了的:关机、重启、删文件、杀进程 —— 这些**不会**出现在回退列表里,
|
||||||
|
免得你以为什么都能退回去。
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
WATCH_PATTERN = re.compile(r'WATCH_README = f""".*?"""\n\n\n', re.S)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
text = PKG.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
if "ykxmz-agent-" in text:
|
||||||
|
print(" 已经改过")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# 1. 把 WATCH_README 提到顶层的常量
|
||||||
|
# 原来它是嵌在 main() 里 write_readme 的第三个参数
|
||||||
|
old_watch = re.search(
|
||||||
|
r' write_readme\(watch_dir / "README-watch\.txt", f"""'
|
||||||
|
r'.*?"""\)\n', text, re.S)
|
||||||
|
if old_watch:
|
||||||
|
text = text[:old_watch.start()] + text[old_watch.end():]
|
||||||
|
print(" 摘掉了 main 里内嵌的手表说明")
|
||||||
|
else:
|
||||||
|
print(" [提示] 没找到内嵌的手表说明(可能已改)")
|
||||||
|
|
||||||
|
# 2. 插入 WATCH_README 常量(放在 RELAY_README 之后)
|
||||||
|
anchor = 'def write_readme(path: Path, text: str) -> None:'
|
||||||
|
if "WATCH_README =" not in text and anchor in text:
|
||||||
|
text = text.replace(anchor, WATCH_README_BLOCK + anchor, 1)
|
||||||
|
print(" 加了 WATCH_README 常量")
|
||||||
|
|
||||||
|
# 3. 换掉 main()
|
||||||
|
start = text.find("def main() -> int:")
|
||||||
|
end = text.find('if __name__ == "__main__":')
|
||||||
|
if start < 0 or end < 0 or end < start:
|
||||||
|
print(" [失败] 找不到 main() 的边界")
|
||||||
|
return 1
|
||||||
|
text = text[:start] + NEW_MAIN + text[end:]
|
||||||
|
print(" 替换了 main()(改成出三个产物)")
|
||||||
|
|
||||||
|
PKG.write_text(text, encoding="utf-8", newline="\n")
|
||||||
|
|
||||||
|
import ast
|
||||||
|
try:
|
||||||
|
ast.parse(text)
|
||||||
|
print(" package_remote.py 语法 OK")
|
||||||
|
except SyntaxError as exc:
|
||||||
|
print(f" 语法错误: 行 {exc.lineno}: {exc.msg}")
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
r"""把 test_package_remote.py 改成适配"三端分开出"。
|
||||||
|
|
||||||
|
原来:
|
||||||
|
ZIP = dist/ykxmz-1.5.0.zip (一个合并包)
|
||||||
|
解压后是 1-agent/ 2-server/ 3-watch/ + 顶层 README
|
||||||
|
|
||||||
|
现在:
|
||||||
|
dist/ykxmz-agent-1.5.0.zip 被控端
|
||||||
|
dist/ykxmz-server-1.5.0.zip 服务器端
|
||||||
|
dist/ykxmz-watch-1.5.0.apk 控制端(直接给)
|
||||||
|
|
||||||
|
测试要验证的东西不变(三部分内容完整、能跑起来、文档带 BOM),
|
||||||
|
只是"从哪拿"变了。
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ast
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
TEST = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\_tests"
|
||||||
|
r"\test_package_remote.py")
|
||||||
|
|
||||||
|
OLD_HEAD = '''ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
ZIP = ROOT / "dist" / "ykxmz-1.5.0.zip"'''
|
||||||
|
|
||||||
|
NEW_HEAD = '''ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
# 三端分开出(用户要求):
|
||||||
|
# 被控端 -> 一个 zip
|
||||||
|
# 服务器端 -> 一个 zip
|
||||||
|
# 控制端 -> 直接给 APK(不打 zip)
|
||||||
|
AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-1.5.0.zip"
|
||||||
|
SERVER_ZIP = ROOT / "dist" / "ykxmz-server-1.5.0.zip"
|
||||||
|
WATCH_APK = ROOT / "dist" / "ykxmz-watch-1.5.0.apk"'''
|
||||||
|
|
||||||
|
OLD_OPEN = '''def main() -> int:
|
||||||
|
if not ZIP.is_file():
|
||||||
|
print(f" 找不到 {ZIP}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
work = Path(tempfile.mkdtemp(prefix="verify_pkg_"))
|
||||||
|
relay_proc = agent_proc = None
|
||||||
|
try:
|
||||||
|
# ---------------- 1. 解压 ----------------
|
||||||
|
print("一、解压")
|
||||||
|
with zipfile.ZipFile(ZIP) as archive:
|
||||||
|
archive.extractall(work)
|
||||||
|
top = work / ZIP.stem
|
||||||
|
check("顶层目录存在", top.is_dir(), top)
|
||||||
|
agent_dir = top / "1-agent"
|
||||||
|
relay_dir = top / "2-server"
|
||||||
|
watch_dir = top / "3-watch"
|
||||||
|
check("三个部分目录都在",
|
||||||
|
agent_dir.is_dir() and relay_dir.is_dir() and watch_dir.is_dir())
|
||||||
|
check("顶层说明在", (top / "README.txt").is_file())
|
||||||
|
|
||||||
|
exe = agent_dir / "ykxmz.exe"
|
||||||
|
relay_py = relay_dir / "relay.py"
|
||||||
|
install_sh = relay_dir / "install.sh"
|
||||||
|
apk = next(watch_dir.glob("*.apk"), None)
|
||||||
|
check("被控端 EXE 在", exe.is_file())
|
||||||
|
check("服务器端 relay.py 在", relay_py.is_file())
|
||||||
|
check("服务器端 install.sh 在", install_sh.is_file())
|
||||||
|
check("控制端 APK 在", apk is not None, apk)
|
||||||
|
|
||||||
|
# 说明文档要有 BOM(否则记事本会认成 GBK 乱码)
|
||||||
|
for label, path in (("顶层", top / "README.txt"),
|
||||||
|
("被控端", agent_dir / "README-agent.txt"),
|
||||||
|
("服务器端", relay_dir / "README-server.txt"),
|
||||||
|
("控制端", watch_dir / "README-watch.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])'''
|
||||||
|
|
||||||
|
NEW_OPEN = '''def main() -> int:
|
||||||
|
# 1) 三个产物都要在
|
||||||
|
for label, path in (("被控端包", AGENT_ZIP), ("服务器端包", SERVER_ZIP),
|
||||||
|
("控制端 APK", WATCH_APK)):
|
||||||
|
if not path.is_file():
|
||||||
|
print(f" 找不到{label}: {path}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
work = Path(tempfile.mkdtemp(prefix="verify_pkg_"))
|
||||||
|
relay_proc = agent_proc = None
|
||||||
|
try:
|
||||||
|
# ---------------- 1. 解压两个 zip ----------------
|
||||||
|
print("一、解压(两个 zip)")
|
||||||
|
with zipfile.ZipFile(AGENT_ZIP) as archive:
|
||||||
|
archive.extractall(work)
|
||||||
|
with zipfile.ZipFile(SERVER_ZIP) as archive:
|
||||||
|
archive.extractall(work)
|
||||||
|
|
||||||
|
# 两个包各自带一层版本目录
|
||||||
|
agent_dir = work / AGENT_ZIP.stem
|
||||||
|
relay_dir = work / SERVER_ZIP.stem
|
||||||
|
check("被控端目录存在", agent_dir.is_dir(), agent_dir)
|
||||||
|
check("服务器端目录存在", relay_dir.is_dir(), relay_dir)
|
||||||
|
|
||||||
|
exe = agent_dir / "ykxmz.exe"
|
||||||
|
relay_py = relay_dir / "relay.py"
|
||||||
|
install_sh = relay_dir / "install.sh"
|
||||||
|
apk = WATCH_APK
|
||||||
|
check("被控端 EXE 在", exe.is_file())
|
||||||
|
check("服务器端 relay.py 在", relay_py.is_file())
|
||||||
|
check("服务器端 install.sh 在", install_sh.is_file())
|
||||||
|
check("服务器端带了网络调优脚本", (relay_dir / "net-tune.sh").is_file())
|
||||||
|
check("服务器端带了看门狗", (relay_dir / "watchdog.sh").is_file())
|
||||||
|
check("控制端 APK 在(直接在 dist 里)", apk.is_file(), apk)
|
||||||
|
|
||||||
|
# 说明文档要有 BOM(否则记事本会认成 GBK 乱码)
|
||||||
|
for label, path in (("被控端", agent_dir / "README-agent.txt"),
|
||||||
|
("服务器端", relay_dir / "README-server.txt"),
|
||||||
|
("控制端(旁边那份)",
|
||||||
|
ROOT / "dist" / "ykxmz-watch-1.5.0-说明.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])
|
||||||
|
|
||||||
|
# 三份正式文档:两个包里都要有
|
||||||
|
for label, base in (("被控端包", agent_dir), ("服务器端包", relay_dir)):
|
||||||
|
for doc in ("LICENSE.txt", "BEFORE-INSTALL.txt",
|
||||||
|
"AFTER-INSTALL.txt"):
|
||||||
|
check(f"{label}带了 {doc}", (base / doc).is_file())'''
|
||||||
|
|
||||||
|
OLD_TOOLS = ''' # 被控端目录里不该有 data / 说明残留
|
||||||
|
check("没有把 data 目录打进去",
|
||||||
|
not (agent_dir / "data").exists())'''
|
||||||
|
|
||||||
|
NEW_TOOLS = ''' # 被控端目录里不该有 data / 说明残留
|
||||||
|
check("没有把 data 目录打进去",
|
||||||
|
not (agent_dir / "data").exists())'''
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
text = TEST.read_text(encoding="utf-8")
|
||||||
|
if "AGENT_ZIP" in text:
|
||||||
|
print(" 已经改过")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
ok = True
|
||||||
|
for old, new, label in ((OLD_HEAD, NEW_HEAD, "产物路径常量"),
|
||||||
|
(OLD_OPEN, NEW_OPEN, "解压与检查段")):
|
||||||
|
if old not in text:
|
||||||
|
print(f" [失败] {label} —— 锚点没找到")
|
||||||
|
# 打印实际内容帮助定位
|
||||||
|
key = old.splitlines()[0]
|
||||||
|
for i, line in enumerate(text.splitlines(), 1):
|
||||||
|
if line.strip() == key.strip():
|
||||||
|
print(f" 实际 {i}: {line}")
|
||||||
|
ok = False
|
||||||
|
continue
|
||||||
|
text = text.replace(old, new, 1)
|
||||||
|
print(f" {label}")
|
||||||
|
|
||||||
|
if not ok:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
TEST.write_text(text, encoding="utf-8", newline="\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
ast.parse(text)
|
||||||
|
print(" test_package_remote.py 语法 OK")
|
||||||
|
except SyntaxError as exc:
|
||||||
|
print(f" 语法错误: 行 {exc.lineno}: {exc.msg}")
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
r"""两件事:
|
||||||
|
1. 给 verify_all.ps1 补回 UTF-8 BOM
|
||||||
|
(edit 工具写出来不带 BOM,PowerShell 里中文会乱码)
|
||||||
|
2. 把三个成品上传到设备的下载目录
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
VERIFY = ROOT / "_tests" / "verify_all.ps1"
|
||||||
|
|
||||||
|
UPLOADS = [
|
||||||
|
("dist/ykxmz-agent-1.5.0.zip",
|
||||||
|
"/root/lanremote-relay/downloads/ykxmz-agent-1.5.0.zip"),
|
||||||
|
("dist/ykxmz-server-1.5.0.zip",
|
||||||
|
"/root/lanremote-relay/downloads/ykxmz-server-1.5.0.zip"),
|
||||||
|
("dist/ykxmz-watch-1.5.0.apk",
|
||||||
|
"/root/lanremote-relay/downloads/ykxmz-watch-1.5.0.apk"),
|
||||||
|
("dist/ykxmz-watch-1.5.0-说明.txt",
|
||||||
|
"/root/lanremote-relay/downloads/ykxmz-watch-1.5.0-说明.txt"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
# ---- 1. 补 BOM ----
|
||||||
|
raw = VERIFY.read_bytes()
|
||||||
|
if raw.startswith(b"\xef\xbb\xbf"):
|
||||||
|
print(" verify_all.ps1: BOM 正常")
|
||||||
|
else:
|
||||||
|
VERIFY.write_bytes(b"\xef\xbb\xbf" + raw)
|
||||||
|
print(" verify_all.ps1: 补回了 UTF-8 BOM")
|
||||||
|
|
||||||
|
# ---- 2. 建目录 ----
|
||||||
|
run("mkdir -p /root/lanremote-relay/downloads", timeout=30)
|
||||||
|
run("rm -f /root/lanremote-relay/downloads/ykxmz-1.5.0.zip", timeout=30)
|
||||||
|
|
||||||
|
# ---- 3. 上传 ----
|
||||||
|
print()
|
||||||
|
print(" 上传成品:")
|
||||||
|
for local, remote in UPLOADS:
|
||||||
|
src = ROOT / local
|
||||||
|
if not src.is_file():
|
||||||
|
print(f" [跳过] {local} 不存在")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
upload(str(src), remote, 0o644)
|
||||||
|
size = src.stat().st_size
|
||||||
|
print(f" ✓ {src.name} ({size / 1024 / 1024:.2f} MB)")
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
print(f" ✗ {src.name}: {exc}")
|
||||||
|
|
||||||
|
# ---- 4. 确认 ----
|
||||||
|
print()
|
||||||
|
code, out, _err = run(
|
||||||
|
"ls -la /root/lanremote-relay/downloads/ | tail -8", timeout=30)
|
||||||
|
print(out)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 验证下载区能用(本地 + 公网)。
|
||||||
|
set -u
|
||||||
|
|
||||||
|
BASE=http://127.0.0.1:8080
|
||||||
|
PUB=https://relay.xxmxxs.top
|
||||||
|
UA='LanRemote/1.4.0'
|
||||||
|
|
||||||
|
echo "===== 1. 本地列出下载文件 ====="
|
||||||
|
curl -s --max-time 10 "$BASE/v1/downloads" | python3 -m json.tool 2>/dev/null \
|
||||||
|
| head -30 || echo " 读不到"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "===== 2. 本地下载(只看 HTTP 码和大小)====="
|
||||||
|
for f in ykxmz-watch-1.5.0.apk ykxmz-server-1.5.0.zip ykxmz-agent-1.5.0.zip; do
|
||||||
|
info=$(curl -s --max-time 20 -o /tmp/dl.bin -w '%{http_code} %{size_download} %{content_type}' \
|
||||||
|
"$BASE/download/$f" 2>/dev/null)
|
||||||
|
printf " %-32s %s\n" "$f" "$info"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "===== 3. 公网列出(走隧道)====="
|
||||||
|
curl -s --max-time 20 -H "User-Agent: $UA" "$PUB/v1/downloads" \
|
||||||
|
| head -c 300
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "===== 4. 公网下载 APK 头几个字节(验证真的能下)====="
|
||||||
|
code=$(curl -s --max-time 40 -o /tmp/apk_pub.bin -w '%{http_code}' \
|
||||||
|
-H "User-Agent: $UA" "$PUB/download/ykxmz-watch-1.5.0.apk" 2>/dev/null)
|
||||||
|
size=$(stat -c %s /tmp/apk_pub.bin 2>/dev/null || echo 0)
|
||||||
|
echo " HTTP $code,下载 $size 字节"
|
||||||
|
echo -n " 是不是合法 APK(zip 头 PK): "
|
||||||
|
head -c 2 /tmp/apk_pub.bin | grep -q 'PK' && echo "是 ✓" || echo "不是 ✗"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "===== 5. 安全:目录穿越要被挡住 ====="
|
||||||
|
for bad in "../relay.py" "..%2Frelay.py" "relay.py" "x.sh"; do
|
||||||
|
code=$(curl -s --max-time 10 -o /dev/null -w '%{http_code}' \
|
||||||
|
"$BASE/download/$bad" 2>/dev/null)
|
||||||
|
printf " %-20s HTTP %s\n" "$bad" "$code"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "===== 6. 管理页有没有下载卡片 ====="
|
||||||
|
KEY=$(cat /root/lanremote-relay/data/admin_key.txt 2>/dev/null)
|
||||||
|
for needle in 'id=dlPanel' '/v1/downloads' '/download/'; do
|
||||||
|
if curl -s --max-time 10 -H "X-Admin: $KEY" "$BASE/" 2>/dev/null \
|
||||||
|
| grep -q "$needle"; then
|
||||||
|
echo " ✓ $needle"
|
||||||
|
else
|
||||||
|
echo " ✗ $needle"
|
||||||
|
fi
|
||||||
|
done
|
||||||
@@ -22,7 +22,13 @@ import zipfile
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parent.parent
|
ROOT = Path(__file__).resolve().parent.parent
|
||||||
ZIP = ROOT / "dist" / "ykxmz-1.5.0.zip"
|
# 三端分开出(用户要求):
|
||||||
|
# 被控端 -> 一个 zip
|
||||||
|
# 服务器端 -> 一个 zip
|
||||||
|
# 控制端 -> 直接给 APK(不打 zip)
|
||||||
|
AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-1.5.0.zip"
|
||||||
|
SERVER_ZIP = ROOT / "dist" / "ykxmz-server-1.5.0.zip"
|
||||||
|
WATCH_APK = ROOT / "dist" / "ykxmz-watch-1.5.0.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"
|
||||||
@@ -45,44 +51,55 @@ def check(name, ok, detail=""):
|
|||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
if not ZIP.is_file():
|
# 1) 三个产物都要在
|
||||||
print(f" 找不到 {ZIP}")
|
for label, path in (("被控端包", AGENT_ZIP), ("服务器端包", SERVER_ZIP),
|
||||||
return 1
|
("控制端 APK", WATCH_APK)):
|
||||||
|
if not path.is_file():
|
||||||
|
print(f" 找不到{label}: {path}")
|
||||||
|
return 1
|
||||||
|
|
||||||
work = Path(tempfile.mkdtemp(prefix="verify_pkg_"))
|
work = Path(tempfile.mkdtemp(prefix="verify_pkg_"))
|
||||||
relay_proc = agent_proc = None
|
relay_proc = agent_proc = None
|
||||||
try:
|
try:
|
||||||
# ---------------- 1. 解压 ----------------
|
# ---------------- 1. 解压两个 zip ----------------
|
||||||
print("一、解压")
|
print("一、解压(两个 zip)")
|
||||||
with zipfile.ZipFile(ZIP) as archive:
|
with zipfile.ZipFile(AGENT_ZIP) as archive:
|
||||||
archive.extractall(work)
|
archive.extractall(work)
|
||||||
top = work / ZIP.stem
|
with zipfile.ZipFile(SERVER_ZIP) as archive:
|
||||||
check("顶层目录存在", top.is_dir(), top)
|
archive.extractall(work)
|
||||||
agent_dir = top / "1-agent"
|
|
||||||
relay_dir = top / "2-server"
|
# 两个包各自带一层版本目录
|
||||||
watch_dir = top / "3-watch"
|
agent_dir = work / AGENT_ZIP.stem
|
||||||
check("三个部分目录都在",
|
relay_dir = work / SERVER_ZIP.stem
|
||||||
agent_dir.is_dir() and relay_dir.is_dir() and watch_dir.is_dir())
|
check("被控端目录存在", agent_dir.is_dir(), agent_dir)
|
||||||
check("顶层说明在", (top / "README.txt").is_file())
|
check("服务器端目录存在", relay_dir.is_dir(), relay_dir)
|
||||||
|
|
||||||
exe = agent_dir / "ykxmz.exe"
|
exe = agent_dir / "ykxmz.exe"
|
||||||
relay_py = relay_dir / "relay.py"
|
relay_py = relay_dir / "relay.py"
|
||||||
install_sh = relay_dir / "install.sh"
|
install_sh = relay_dir / "install.sh"
|
||||||
apk = next(watch_dir.glob("*.apk"), None)
|
apk = WATCH_APK
|
||||||
check("被控端 EXE 在", exe.is_file())
|
check("被控端 EXE 在", exe.is_file())
|
||||||
check("服务器端 relay.py 在", relay_py.is_file())
|
check("服务器端 relay.py 在", relay_py.is_file())
|
||||||
check("服务器端 install.sh 在", install_sh.is_file())
|
check("服务器端 install.sh 在", install_sh.is_file())
|
||||||
check("控制端 APK 在", apk is not None, apk)
|
check("服务器端带了网络调优脚本", (relay_dir / "net-tune.sh").is_file())
|
||||||
|
check("服务器端带了看门狗", (relay_dir / "watchdog.sh").is_file())
|
||||||
|
check("控制端 APK 在(直接在 dist 里)", apk.is_file(), apk)
|
||||||
|
|
||||||
# 说明文档要有 BOM(否则记事本会认成 GBK 乱码)
|
# 说明文档要有 BOM(否则记事本会认成 GBK 乱码)
|
||||||
for label, path in (("顶层", top / "README.txt"),
|
for label, path in (("被控端", agent_dir / "README-agent.txt"),
|
||||||
("被控端", agent_dir / "README-agent.txt"),
|
|
||||||
("服务器端", relay_dir / "README-server.txt"),
|
("服务器端", relay_dir / "README-server.txt"),
|
||||||
("控制端", watch_dir / "README-watch.txt")):
|
("控制端(旁边那份)",
|
||||||
|
ROOT / "dist" / "ykxmz-watch-1.5.0-说明.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])
|
||||||
|
|
||||||
|
# 三份正式文档:两个包里都要有
|
||||||
|
for label, base in (("被控端包", agent_dir), ("服务器端包", relay_dir)):
|
||||||
|
for doc in ("LICENSE.txt", "BEFORE-INSTALL.txt",
|
||||||
|
"AFTER-INSTALL.txt"):
|
||||||
|
check(f"{label}带了 {doc}", (base / doc).is_file())
|
||||||
|
|
||||||
# 被控端目录里不该有 data / 说明残留
|
# 被控端目录里不该有 data / 说明残留
|
||||||
check("没有把 data 目录打进去",
|
check("没有把 data 目录打进去",
|
||||||
not (agent_dir / "data").exists())
|
not (agent_dir / "data").exists())
|
||||||
@@ -179,7 +196,8 @@ def main() -> int:
|
|||||||
classes.mkdir(parents=True, exist_ok=True)
|
classes.mkdir(parents=True, exist_ok=True)
|
||||||
sources = [ROOT / "android" / "src" / "com" / "lanremote" / "watch" / n
|
sources = [ROOT / "android" / "src" / "com" / "lanremote" / "watch" / n
|
||||||
for n in ("Json.java", "B64.java", "Transport.java",
|
for n in ("Json.java", "B64.java", "Transport.java",
|
||||||
"RelayTransport.java", "RemoteClient.java",
|
"RelayTransport.java", "TlsCompat.java",
|
||||||
|
"RemoteClient.java",
|
||||||
"DiscoveryCore.java")]
|
"DiscoveryCore.java")]
|
||||||
sources.append(ROOT / "_tests" / "java" / "JavaRelayTest.java")
|
sources.append(ROOT / "_tests" / "java" / "JavaRelayTest.java")
|
||||||
comp = subprocess.run(
|
comp = subprocess.run(
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ ROOT = Path(__file__).resolve().parent.parent
|
|||||||
WATCH = ROOT / "android" / "src" / "com" / "lanremote" / "watch"
|
WATCH = ROOT / "android" / "src" / "com" / "lanremote" / "watch"
|
||||||
MAIN = WATCH / "MainActivity.java"
|
MAIN = WATCH / "MainActivity.java"
|
||||||
RELAY_T = WATCH / "RelayTransport.java"
|
RELAY_T = WATCH / "RelayTransport.java"
|
||||||
|
"TlsCompat.java"
|
||||||
CLIENT = WATCH / "RemoteClient.java"
|
CLIENT = WATCH / "RemoteClient.java"
|
||||||
JSON = WATCH / "Json.java"
|
JSON = WATCH / "Json.java"
|
||||||
|
|
||||||
|
|||||||
@@ -402,6 +402,8 @@ 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\DiscoveryCore.java") `
|
||||||
(Join-Path $root "android\src\com\lanremote\watch\Transport.java") `
|
(Join-Path $root "android\src\com\lanremote\watch\Transport.java") `
|
||||||
(Join-Path $root "android\src\com\lanremote\watch\RelayTransport.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 "android\src\com\lanremote\watch\RemoteClient.java") `
|
||||||
(Join-Path $root "_tests\java\JavaClientTest.java") 2>&1 | Out-Null
|
(Join-Path $root "_tests\java\JavaClientTest.java") 2>&1 | Out-Null
|
||||||
$compiled = ($LASTEXITCODE -eq 0)
|
$compiled = ($LASTEXITCODE -eq 0)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user