diff --git a/.gitea/workflows/vps-deploy.yml b/.gitea/workflows/vps-deploy.yml index 0fdd5a0..3fa8ba3 100644 --- a/.gitea/workflows/vps-deploy.yml +++ b/.gitea/workflows/vps-deploy.yml @@ -40,6 +40,40 @@ jobs: run: bash scripts/nas_sync/promote.sh --target vps - name: VPS 冒烟 (LocalUnifiedProvider 真数据) run: ssh 49.232.102.198 'cd C:\sanguo_vnpy_v2 && C:\Python310\python.exe -X utf8 scripts/data_platform/verify_unified_e2e.py' + - name: 前端构建 + 推 dist 到 VPS (公网前端无管线, 此处补齐) + run: | + set -e + cd frontend + npm ci + npm run build + cd .. + tar czf /tmp/dist_latest.tgz -C frontend/dist . + scp -o ConnectTimeout=20 /tmp/dist_latest.tgz 49.232.102.198:C:/sanguo_vnpy_v2/dist_latest.tgz + - name: VPS 替换 dist + 重启 sanguo-api (等端口释放防 10048 竞态, 再等起服) + run: | + set -e + ssh 49.232.102.198 'C:\Python310\python.exe -X utf8 C:\sanguo_vnpy_v2\scripts\nas_sync\vps_update_dist.py' | tee /tmp/dist_swap.log + grep -q DIST_UPDATE_DONE /tmp/dist_swap.log + # 停 API → 等端口彻底释放(旧实例被杀后端口有滞留, 立即重启会 10048 静默崩) + ssh 49.232.102.198 'schtasks /end /tn sanguo-api' || true + for i in $(seq 1 30); do + ssh 49.232.102.198 'netstat -ano -p tcp' | tr -d '\r' | grep -q ':8000.*LISTEN' || { echo "port freed after $((i*2))s"; break; } + sleep 2 + done + ssh 49.232.102.198 'schtasks /run /tn sanguo-api' + # 等新实例监听 + /docs 可用(VPS 启动需数分钟, 上限 10 分钟) + for i in $(seq 1 60); do + if ssh 49.232.102.198 'netstat -ano -p tcp' | tr -d '\r' | grep -q ':8000.*LISTEN'; then + echo "API listening after ~$((i*10))s"; break + fi + sleep 10 + if [ "$i" = "60" ]; then echo "API 10 分钟未监听 8000"; exit 1; fi + done + for i in $(seq 1 12); do + ssh 49.232.102.198 'powershell -NoProfile -Command "(Invoke-WebRequest -UseBasicParsing http://127.0.0.1:8000/docs).StatusCode"' 2>/dev/null | grep -q 200 && { echo "API /docs 200"; exit 0; } + sleep 10 + done + echo "API 监听但 /docs 2 分钟未返回 200"; exit 1 - name: mark vps-deployed tag (VPS 版本真相, session 用 git log vps-deployed..HEAD 查未部署) env: TOKEN: ${{ github.token }} diff --git a/scripts/nas_sync/vps_update_dist.py b/scripts/nas_sync/vps_update_dist.py new file mode 100644 index 0000000..8d972fa --- /dev/null +++ b/scripts/nas_sync/vps_update_dist.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +"""VPS: 替换 frontend/dist 为最新构建(先备份旧版)。 + +用法(VPS 上): C:\\Python310\\python.exe -X utf8 C:\\sanguo_vnpy_v2\\scripts\\nas_sync\\vps_update_dist.py +输入: C:\\sanguo_vnpy_v2\\dist_latest.tgz (Mac 构建后 scp 上来的 tar 包, 内容为 dist 根) +输出: 尾行 DIST_UPDATE_DONE(成功标记, CI 用) +""" +import os +import re +import shutil +import tarfile + +ROOT = r"C:\sanguo_vnpy_v2" +TGZ = os.path.join(ROOT, "dist_latest.tgz") +DIST = os.path.join(ROOT, "frontend", "dist") +BAK = os.path.join(ROOT, "frontend", "dist_bak") + +if not os.path.exists(TGZ): + raise SystemExit(f"tgz not found: {TGZ}") + +if os.path.exists(BAK): + shutil.rmtree(BAK) +if os.path.exists(DIST): + shutil.move(DIST, BAK) + print("old dist ->", BAK, flush=True) +os.makedirs(DIST, exist_ok=True) +with tarfile.open(TGZ) as t: + t.extractall(DIST) +idx = os.path.join(DIST, "index.html") +with open(idx, encoding="utf-8") as f: + head = f.read(400) +m = re.search(r"assets/index-[^\"']*", head) +print("new index:", m.group(0) if m else "?", flush=True) +print("DIST_UPDATE_DONE", flush=True)