系统设置增加备份恢复:中控本机备份,并可下载各客户端备份。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -269,6 +269,69 @@ def pull_all_stats(window: str = "7d") -> list[dict[str, Any]]:
|
||||
return results
|
||||
|
||||
|
||||
def fetch_backup_list(inst: dict[str, Any]) -> dict[str, Any]:
|
||||
base = (inst.get("base_url") or "").rstrip("/")
|
||||
token = (inst.get("bridge_token") or "").strip()
|
||||
if not base or not token:
|
||||
return {"ok": False, "msg": "缺少 URL 或 Token", "items": []}
|
||||
url = f"{base}/api/hub/backup/list"
|
||||
try:
|
||||
r = requests.get(
|
||||
url,
|
||||
headers={"X-Hub-Token": token, "Accept": "application/json"},
|
||||
timeout=_timeout(),
|
||||
)
|
||||
data = r.json() if r.content else {}
|
||||
if isinstance(data, dict):
|
||||
data.setdefault("instance_id", inst.get("id"))
|
||||
data.setdefault("instance_name", inst.get("name"))
|
||||
return data
|
||||
return {"ok": False, "msg": f"HTTP {r.status_code}", "items": []}
|
||||
except Exception as e:
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": str(e) or "拉取失败",
|
||||
"items": [],
|
||||
"instance_id": inst.get("id"),
|
||||
"instance_name": inst.get("name"),
|
||||
}
|
||||
|
||||
|
||||
def fetch_backup_file(inst: dict[str, Any], name: str) -> tuple[bool, bytes | None, str]:
|
||||
"""返回 (ok, content, msg_or_filename)."""
|
||||
base = (inst.get("base_url") or "").rstrip("/")
|
||||
token = (inst.get("bridge_token") or "").strip()
|
||||
safe = (name or "").strip()
|
||||
if not base or not token or not safe:
|
||||
return False, None, "参数不完整"
|
||||
url = f"{base}/api/hub/backup/download/{safe}"
|
||||
try:
|
||||
r = requests.get(
|
||||
url,
|
||||
headers={"X-Hub-Token": token, "Accept": "application/gzip, application/json"},
|
||||
timeout=max(_timeout(), 60.0),
|
||||
stream=True,
|
||||
)
|
||||
ctype = (r.headers.get("content-type") or "").lower()
|
||||
if r.status_code != 200:
|
||||
try:
|
||||
data = r.json()
|
||||
return False, None, (data.get("msg") if isinstance(data, dict) else None) or f"HTTP {r.status_code}"
|
||||
except Exception:
|
||||
return False, None, f"HTTP {r.status_code}"
|
||||
if "json" in ctype:
|
||||
try:
|
||||
data = r.json()
|
||||
return False, None, (data.get("msg") if isinstance(data, dict) else None) or "下载失败"
|
||||
except Exception:
|
||||
return False, None, "下载失败"
|
||||
return True, r.content, os.path.basename(safe)
|
||||
except requests.Timeout:
|
||||
return False, None, "下载超时"
|
||||
except Exception as e:
|
||||
return False, None, str(e) or "下载失败"
|
||||
|
||||
|
||||
def dispatch_cond_order_to_ids(instance_ids: list[int], payload: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
results = []
|
||||
for iid in instance_ids:
|
||||
|
||||
Reference in New Issue
Block a user