diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e30a378..900ae07 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -13,6 +13,7 @@ V2.1.1 是一次以稳定性、浏览器兼容性和 VPS 实际使用体验为 - 修复登录和管理密码被意外删除首尾空格的问题;前端和 `ml password` 现在保持一致。 - 修复 SOCKS5 客户端未提供“无需认证”方法时,服务端仍错误接受连接的问题。 - 修复 `ml status` 一直显示旧版 `v2.0`,以及首次安装提示 5-30 秒但实际最多等待 90 秒的问题。 +- 修复 `ml update` 重启服务后可能读取上一次连接留下的节点 ID、过早提示“已就绪”的竞态;现在会清理旧状态,并确认 OpenVPN 进程和 `tun0` 均已建立后才报告成功。 - 修复正式版 GitHub Actions 发布脚本的 Shell 块问题。 ## 性能与体验优化 @@ -36,7 +37,7 @@ V2.1.1 是一次以稳定性、浏览器兼容性和 VPS 实际使用体验为 - Ubuntu 22.04 x86_64 VPS 一键安装成功,服务保持运行且无异常重启。 - HTTP 与 SOCKS5 代理出口验证通过。 - 节点测试、切换、断开和恢复原节点的完整流程通过。 -- 本地 34 项单元测试、Python 编译、前端 JavaScript 语法、`install.sh` 语法和 Docker Compose 配置检查通过。 +- 本地 35 项单元测试、Python 编译、前端 JavaScript 语法、`install.sh` 语法和 Docker Compose 配置检查通过。 - 99 个节点分页为 50/49,国家多选、空状态、收藏、设置、网关、日志和 Web 更新检测均通过浏览器交互测试。 - 11.5 秒空闲轮询观测期间,相同节点快照产生 0 次 DOM 变更。 - 390x844 手机视口和 1440x900 桌面视口没有页面级横向溢出或控件重叠。 diff --git a/install.sh b/install.sh index 1d5c0fc..f6383a8 100644 --- a/install.sh +++ b/install.sh @@ -1098,6 +1098,22 @@ if [ -d "/proc/sys/net/ipv4/conf" ]; then fi echo -e "\n正在启动 AimiliVPN 服务并初始化网络..." +# Avoid treating the previous process' persisted node ID as a successful new +# connection during upgrades. The service will replace this startup state. +if [ -f "${INSTALL_DIR}/vpngate_data/state.json" ]; then + python3 - "${INSTALL_DIR}/vpngate_data/state.json" <<'PY' 2>/dev/null || true +import json +import sys +from pathlib import Path + +state_path = Path(sys.argv[1]) +state = json.loads(state_path.read_text(encoding="utf-8")) +state["active_openvpn_node_id"] = "" +state["is_connecting"] = True +state["last_check_message"] = "服务正在重启并重新建立加密通道..." +state_path.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8") +PY +fi if command -v systemctl >/dev/null 2>&1; then systemctl restart aimilivpn.service || true elif command -v rc-service >/dev/null 2>&1; then @@ -1115,7 +1131,7 @@ for i in {1..90}; do CUR_MSG=$(python3 -c "import json; print(json.load(open('${INSTALL_DIR}/vpngate_data/state.json')).get('last_check_message', ''))" 2>/dev/null || echo "") if [ "$IS_CONN" = "False" ] || [ "$IS_CONN" = "false" ]; then - if [ -n "$ACTIVE_ID" ]; then + if [ -n "$ACTIVE_ID" ] && ip link show dev tun0 >/dev/null 2>&1 && pidof openvpn >/dev/null 2>&1; then echo -e " -> ${GREEN}[已就绪]${PLAIN} 首次节点连接成功,活动节点: ${GREEN}$ACTIVE_ID${PLAIN}" break else diff --git a/tests/test_manager_logic.py b/tests/test_manager_logic.py index 4a0a9c3..3e8ec4d 100644 --- a/tests/test_manager_logic.py +++ b/tests/test_manager_logic.py @@ -489,6 +489,9 @@ class ManagerLogicTests(unittest.TestCase): self.assertNotIn("管理终端 v2.0", install_text) self.assertIn("5-90 秒", install_text) self.assertIn('new_pwd = input("请输入新管理密码 (不能为空): ")', install_text) + self.assertIn('state["active_openvpn_node_id"] = ""', install_text) + self.assertIn("ip link show dev tun0", install_text) + self.assertIn("pidof openvpn", install_text) def test_release_workflow_uses_full_patch_version(self) -> None: workflow_text = (manager.ROOT_DIR / ".github" / "workflows" / "release.yml").read_text(encoding="utf-8")