feat: 升级流程增强 + 网关化配置 + 重连循环化

- 配置化:gateway.url/socket.path/download.prefix(网关基础地址统一推导 ws 与下载地址)、
  main.home 主目录(jar/pid 相对它推导)、order.basic;properties 中文 \uXXXX 转义自动还原
- 升级流程:下载 PK 魔数检查与诊断日志;SHA 校验;替换改「改名腾位」绕开 Windows 文件锁延迟;
  nssm stop/start 驱动停止与拉起(pid 强杀回退);升级中标志暂停看门狗拉起避免抢占 jar 锁
- ws_client:重连改循环实现修复递归栈溢出(长时间断线后 maximum recursion depth);
  退避封顶延长至 5 分钟;心跳线程独立修复「暂无心跳数据」
- 新增命令:GET_APIS/HTTP_PROXY(接口测试代理,纯透传鉴权)、GET_LOG_DOWNLOAD(日志下载备用)
- 诊断增强:taskkill/进程退出/替换重试逐次日志

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-03 16:52:34 +08:00
co-authored by Claude
parent b572697e17
commit 0b13de14eb
7 changed files with 366 additions and 152 deletions
+9 -14
View File
@@ -57,6 +57,10 @@ class MainAppClient:
"""日志文件列表(原始 JSON 文本)。"""
return self._get_text(self._url("/api/admin/log/files"))
def log_download(self, file: str) -> str | None:
"""日志全量下载(文本,自带 X-Admin-Token 鉴权)。"""
return self._get_text(self._url(f"/api/admin/log/download?file={quote(file)}"))
def restart(self, delay_ms: int) -> tuple[bool, str]:
"""触发主程序优雅重启。返回 (是否成功, 失败原因)。"""
body, reason = self._post_text_with_reason(self._url(f"/api/admin/restart?delayMs={delay_ms}"), "")
@@ -86,9 +90,8 @@ class MainAppClient:
"""
代理调用前置机任意接口(本机环回,穿透白名单)。
自动按 path 加鉴权头:
- /order/** → Authorization: Basic(读 config.order_basic
- /api/admin/** → X-Admin-Token(读 config.main_admin_token
纯透传:鉴权头由调用方(B 端测试页面)通过 headers 传入,
Agent 不自动加认证,便于测试不同账号。
:return {"ok":bool, "statusCode":int, "body":str, "headers":dict, "error":str}
"""
@@ -100,18 +103,10 @@ class MainAppClient:
if qs:
url += ("&" if "?" in url else "?") + qs
# 纯透传 headers(鉴权由 B 端填写,不自动加)
headers = {}
# 按路径自动加鉴权
if path.startswith("/order"):
if self.config.order_basic:
b64 = __import__("base64").b64encode(
self.config.order_basic.encode("utf-8")
).decode("ascii")
headers["Authorization"] = f"Basic {b64}"
elif path.startswith("/api/admin"):
if self.config.main_admin_token:
headers["X-Admin-Token"] = self.config.main_admin_token
# 合并外部传入的 headers(覆盖默认)
if extra_headers:
headers.update(extra_headers)
if extra_headers:
headers.update(extra_headers)