diff --git a/lib/backup_lib.py b/lib/backup_lib.py index b77c734..00f079e 100644 --- a/lib/backup_lib.py +++ b/lib/backup_lib.py @@ -101,20 +101,35 @@ def prune_backups(*, keep_days: int | None = None) -> int: return removed -def create_backup(*, root_dir: str, env_path: str, db_path: str, label: str = "manual") -> dict[str, Any]: +def create_backup( + *, + root_dir: str, + env_path: str, + db_path: str, + label: str = "manual", + username: str | None = None, + password: str | None = None, +) -> dict[str, Any]: with _LOCK: now = beijing_now() name = f"crypto_okx_hub_backup_{now.strftime('%Y%m%d_%H%M%S')}.tar.gz" out_path = os.path.join(backup_dir(), name) + u = (username if username is not None else os.getenv("HUB_USERNAME") or "admin").strip() or "admin" + p = password if password is not None else (os.getenv("HUB_PASSWORD") or "admin123") + if p is None: + p = "admin123" manifest = { "kind": "crypto_okx_hub", "created_bj": now.strftime("%Y-%m-%d %H:%M:%S"), "label": (label or "manual").strip() or "manual", - "includes": [".env", "database"], + "includes": [".env", "database", "hub_login"], + "hub_username": u, } tmp_fd, tmp_path = tempfile.mkstemp(suffix=".tar.gz", prefix="hub_bak_") os.close(tmp_fd) + env_snap = "" try: + env_snap = _snapshot_env_with_login(env_path, u, str(p)) with tarfile.open(tmp_path, "w:gz") as tar: manifest_path = tmp_path + ".manifest.json" with open(manifest_path, "w", encoding="utf-8") as f: @@ -126,8 +141,8 @@ def create_backup(*, root_dir: str, env_path: str, db_path: str, label: str = "m os.remove(manifest_path) except OSError: pass - if env_path and os.path.isfile(env_path): - tar.add(env_path, arcname=".env") + if env_snap and os.path.isfile(env_snap): + tar.add(env_snap, arcname=".env") if db_path and os.path.isfile(db_path): tar.add(db_path, arcname="database/" + os.path.basename(db_path)) shutil.move(tmp_path, out_path) @@ -137,6 +152,12 @@ def create_backup(*, root_dir: str, env_path: str, db_path: str, label: str = "m except OSError: pass raise + finally: + if env_snap: + try: + os.remove(env_snap) + except OSError: + pass prune_backups() st = os.stat(out_path) return { @@ -149,6 +170,21 @@ def create_backup(*, root_dir: str, env_path: str, db_path: str, label: str = "m } +def _snapshot_env_with_login(env_path: str, username: str, password: str) -> str: + """复制 .env 并写入当前中控登录账号,避免包内缺 HUB_USERNAME/PASSWORD.""" + fd, snap = tempfile.mkstemp(suffix=".env", prefix="hub_env_") + os.close(fd) + if env_path and os.path.isfile(env_path): + shutil.copy2(env_path, snap) + else: + with open(snap, "w", encoding="utf-8") as f: + f.write("") + from lib.env_lib import apply_env_updates + + apply_env_updates(snap, {"HUB_USERNAME": username, "HUB_PASSWORD": password}) + return snap + + def restore_backup(name: str, *, root_dir: str, env_path: str, db_path: str) -> dict[str, Any]: path = backup_path(name) if not path or not os.path.isfile(path): @@ -168,10 +204,23 @@ def restore_backup(name: str, *, root_dir: str, env_path: str, db_path: str) -> os.makedirs(os.path.dirname(os.path.abspath(db_path)) or ".", exist_ok=True) shutil.copy2(src, db_path) break + restored_user = "" + restored_password = "" + if env_path and os.path.isfile(env_path): + from lib.env_lib import env_get + + restored_user = env_get(env_path, "HUB_USERNAME", "") + restored_password = env_get(env_path, "HUB_PASSWORD", "") + if restored_user: + os.environ["HUB_USERNAME"] = restored_user + if restored_password: + os.environ["HUB_PASSWORD"] = restored_password return { "ok": True, - "msg": "已恢复 .env / 数据库,建议重启中控进程使配置完全生效", + "msg": "已恢复 .env / 数据库 / 登录账号,建议重启中控进程使配置完全生效", "name": os.path.basename(path), + "hub_username": restored_user, + "hub_password": restored_password, } @@ -237,6 +286,8 @@ def maybe_run_auto_backup( env_path: str, db_path: str, hour: int = 3, + username: str | None = None, + password: str | None = None, ) -> dict[str, Any] | None: global _LAST_AUTO_DAY now = beijing_now() @@ -255,6 +306,8 @@ def maybe_run_auto_backup( env_path=env_path, db_path=db_path, label="auto", + username=username, + password=password, ) _LAST_AUTO_DAY = day return result @@ -266,15 +319,24 @@ def start_backup_scheduler( env_path: str, db_path_fn: Callable[[], str], hour: int = 3, + get_credentials: Callable[[], tuple[str, str]] | None = None, ) -> None: def loop() -> None: while True: try: + u, p = ("", "") + if get_credentials: + try: + u, p = get_credentials() + except Exception: + u, p = "", "" maybe_run_auto_backup( root_dir=root_dir, env_path=env_path, db_path=db_path_fn(), hour=hour, + username=u or None, + password=p if p != "" else None, ) except Exception: pass diff --git a/templates/settings.html b/templates/settings.html index 0930904..073d34a 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -103,7 +103,7 @@
目录 /root/crypto_okx_hub_backups · 含 .env 与 hub.db。换机时先上传家里下载的包,再点恢复。
目录 /root/crypto_okx_hub_backups · 含 .env、hub.db、当前登录用户名和密码。换机时先上传家里下载的包,再点恢复。