File size: 4,573 Bytes
3d325be
04a3a48
 
 
 
 
 
 
 
 
 
24f9049
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
04a3a48
 
 
 
 
 
 
 
 
 
 
 
 
24f9049
 
 
04a3a48
24f9049
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3d325be
24f9049
3d325be
24f9049
04a3a48
 
 
 
24f9049
04a3a48
 
 
 
 
 
 
3d325be
04a3a48
 
 
 
 
 
 
 
 
 
 
 
24f9049
04a3a48
 
 
 
 
 
24f9049
04a3a48
 
24f9049
 
 
 
 
 
 
 
 
 
 
 
04a3a48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3d325be
24f9049
3d325be
04a3a48
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import os
import sys
import tarfile
from huggingface_hub import HfApi, hf_hub_download

api = HfApi()
repo_id = os.getenv("HF_DATASET")
token = os.getenv("HF_TOKEN")
FILENAME = "latest_backup.tar.gz"
STATE_DIR = "/root/.openclaw"

# 只备份/恢复这些数据目录(不含 openclaw.json,让 config-generator 重新生成)
DATA_DIRS = [
    "agents",
    "workspace",
    "sessions",
    "credentials",
    "backups",
    "skills",
    "logs",
    "openclaw-weixin",
    "identity",
    "media",
    "plugins",
    "plugin-skills",
    "tasks",
    "npm",
    ".cc-switch",
]

# 单独文件也需要保留
DATA_FILES = [
    "agent_bindings.json",
    "update-check.json",
]


def restore():
    try:
        if not repo_id or not token:
            print("[Sync] Skip Restore: HF_DATASET or HF_TOKEN not set")
            return

        print(f"[Sync] Downloading {FILENAME} from {repo_id}...")
        path = hf_hub_download(
            repo_id=repo_id, filename=FILENAME,
            repo_type="dataset", token=token,
            force_download=True
        )

        print(f"[Sync] Selective restore: only data dirs, skip openclaw.json")
        extracted = 0
        skipped = 0
        with tarfile.open(path, "r:gz") as tar:
            for member in tar.getmembers():
                name = member.name
                # 跳过根级别的 openclaw.json(让 config-generator 重新生成)
                if name == "openclaw.json":
                    skipped += 1
                    continue
                # 检查是否属于数据目录或数据文件
                allowed = False
                for d in DATA_DIRS:
                    if name == d or name.startswith(d + "/"):
                        allowed = True
                        break
                if not allowed:
                    for f in DATA_FILES:
                        if name == f:
                            allowed = True
                            break
                if allowed:
                    tar.extract(member, path=STATE_DIR)
                    extracted += 1
                else:
                    skipped += 1

        print(f"[Sync] Restore done: extracted {extracted}, skipped {skipped}")

        # 验证关键文件
        for check_dir, label in [
            ("agents/agent_1/sessions", "agent_1 sessions"),
            ("sessions", "root sessions"),
            ("workspace", "workspace"),
            ("openclaw-weixin", "weixin data"),
        ]:
            full = os.path.join(STATE_DIR, check_dir)
            if os.path.exists(full):
                count = len([f for f in os.listdir(full) if os.path.isfile(os.path.join(full, f))])
                print(f"[Sync]   {label}: {count} files")
            else:
                print(f"[Sync]   {label}: NOT FOUND")

        memory_file = os.path.join(STATE_DIR, "workspace", "MEMORY.md")
        if os.path.exists(memory_file):
            size = os.path.getsize(memory_file)
            print(f"[Sync]   MEMORY.md: {size} bytes")
        else:
            print(f"[Sync]   MEMORY.md: NOT FOUND")

        return True
    except Exception as e:
        print(f"[Sync] Restore note: No existing backup or error: {e}")
        return False


def backup():
    try:
        if not repo_id or not token:
            print("[Sync] Skip Backup: HF_DATASET or HF_TOKEN not set")
            return

        print(f"[Sync] Backing up data from {STATE_DIR}...")
        file_count = 0
        with tarfile.open(FILENAME, "w:gz") as tar:
            # 备份数据目录
            for d in DATA_DIRS:
                full = os.path.join(STATE_DIR, d)
                if os.path.exists(full):
                    tar.add(full, arcname=d)
                    file_count += 1

            # 备份数据文件
            for f in DATA_FILES:
                full = os.path.join(STATE_DIR, f)
                if os.path.exists(full):
                    tar.add(full, arcname=f)
                    file_count += 1

        size = os.path.getsize(FILENAME)
        print(f"[Sync] Archive: {file_count} items, {size // 1024} KB")

        api.upload_file(
            path_or_fileobj=FILENAME,
            path_in_repo=FILENAME,
            repo_id=repo_id,
            repo_type="dataset",
            token=token
        )
        print(f"[Sync] Backup uploaded to {repo_id}/{FILENAME}")
    except Exception as e:
        print(f"[Sync] Backup error: {e}")


if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "backup":
        backup()
    else:
        restore()