| |
| |
| |
| |
|
|
| import os |
| import sys |
| import tarfile |
| import time |
| from datetime import datetime |
| from huggingface_hub import HfApi, hf_hub_download |
|
|
| api = HfApi() |
| repo_id = os.getenv("HF_DATASET") |
| token = os.getenv("HF_TOKEN") |
|
|
| |
| MAIN_BACKUP = "openclaw_backup.tar.gz" |
| BROWSER_BACKUP = "browser_backup.tar.gz" |
|
|
| |
| SKIP_ITEMS = { |
| "openclaw.json", |
| "browsers", |
| "wechat-data", |
| "cache", |
| ".cache", |
| } |
|
|
| |
| CORE_ITEMS = { |
| "sessions", |
| "workspace", |
| "agents", |
| "memory", |
| "credentials", |
| } |
|
|
|
|
| def should_skip(item_name: str) -> bool: |
| """Check if an item should be skipped from backup""" |
| return item_name in SKIP_ITEMS or item_name.startswith('.') or item_name.endswith('.tmp') |
|
|
|
|
| def restore(): |
| """Restore from latest backup on startup""" |
| if not repo_id or not token: |
| print("β οΈ Skip Restore: HF_DATASET or HF_TOKEN not configured") |
| print(" β Fresh installation (normal for first deploy)") |
| return |
|
|
| |
| try: |
| print(f"π₯ Downloading {MAIN_BACKUP} from {repo_id}...") |
| path = hf_hub_download( |
| repo_id=repo_id, |
| filename=MAIN_BACKUP, |
| repo_type="dataset", |
| token=token |
| ) |
| with tarfile.open(path, "r:gz") as tar: |
| tar.extractall(path="/root/.openclaw/") |
| print(f"β
Restored from {MAIN_BACKUP}") |
|
|
| except Exception as e: |
| print(f"βΉοΈ No previous backup found: {e}") |
| print(" β This is normal for first deployment") |
|
|
| |
| try: |
| print(f"π₯ Checking for browser backup...") |
| browser_path = hf_hub_download( |
| repo_id=repo_id, |
| filename=BROWSER_BACKUP, |
| repo_type="dataset", |
| token=token |
| ) |
| with tarfile.open(browser_path, "r:gz") as tar: |
| tar.extractall(path="/root/.openclaw/") |
| print(f"β
Browser binaries restored") |
|
|
| except Exception: |
| print(f"βΉοΈ No browser backup found - will install fresh if needed") |
|
|
|
|
| def backup(): |
| """Backup current state (runs every hour)""" |
| if not repo_id or not token: |
| print("β οΈ Skip Backup: HF_DATASET or HF_TOKEN not configured") |
| return |
|
|
| base_dir = "/root/.openclaw" |
|
|
| |
| if not os.path.exists(base_dir): |
| print(f"β οΈ {base_dir} does not exist - nothing to backup") |
| return |
|
|
| try: |
| print(f"π¦ Creating backup archive...") |
| items_backed_up = [] |
| items_skipped = [] |
|
|
| with tarfile.open(MAIN_BACKUP, "w:gz") as tar: |
| for item in os.listdir(base_dir): |
| if should_skip(item): |
| items_skipped.append(item) |
| continue |
|
|
| full_path = os.path.join(base_dir, item) |
| if os.path.exists(full_path): |
| tar.add(full_path, arcname=item) |
| items_backed_up.append(item) |
|
|
| print(f" β
Backed up: {', '.join(items_backed_up)}") |
| if items_skipped: |
| print(f" βοΈ Skipped: {', '.join(items_skipped)}") |
|
|
| |
| print(f"π€ Uploading {MAIN_BACKUP} to {repo_id}...") |
| api.upload_file( |
| path_or_fileobj=MAIN_BACKUP, |
| path_in_repo=MAIN_BACKUP, |
| repo_id=repo_id, |
| repo_type="dataset", |
| token=token |
| ) |
| print(f"β
Backup complete - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") |
|
|
| except Exception as e: |
| print(f"β Backup error: {e}") |
|
|
| |
| try: |
| browsers_dir = "/root/.openclaw/browsers" |
| if not os.path.exists(browsers_dir): |
| return |
|
|
| |
| try: |
| hf_hub_download( |
| repo_id=repo_id, |
| filename=BROWSER_BACKUP, |
| repo_type="dataset", |
| token=token |
| ) |
| print(f" Browser backup already exists - skipping upload") |
|
|
| except Exception: |
| |
| print(f"π¦ First time: uploading browser binaries (~150MB)...") |
| with tarfile.open(BROWSER_BACKUP, "w:gz") as tar: |
| tar.add(browsers_dir, arcname="browsers") |
|
|
| api.upload_file( |
| path_or_fileobj=BROWSER_BACKUP, |
| path_in_repo=BROWSER_BACKUP, |
| repo_id=repo_id, |
| repo_type="dataset", |
| token=token |
| ) |
| print(f"β
Browser backup uploaded (will not upload again)") |
|
|
| except Exception as e: |
| print(f"β οΈ Browser backup skipped: {e}") |
|
|
|
|
| def list_backups(): |
| """List available backups in dataset""" |
| if not repo_id or not token: |
| print("β οΈ HF_DATASET or HF_TOKEN not configured") |
| return |
|
|
| try: |
| files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token) |
| backup_files = [f for f in files if f.endswith('.tar.gz')] |
|
|
| if backup_files: |
| print(f"\nπ Available backups in {repo_id}:") |
| for f in sorted(backup_files, reverse=True): |
| print(f" - {f}") |
| else: |
| print(f"π No backups found in {repo_id}") |
|
|
| except Exception as e: |
| print(f"β Error listing backups: {e}") |
|
|
|
|
| if __name__ == "__main__": |
| if len(sys.argv) > 1: |
| if sys.argv[1] == "backup": |
| backup() |
| elif sys.argv[1] == "list": |
| list_backups() |
| elif sys.argv[1] == "restore": |
| restore() |
| else: |
| restore() |