File size: 5,870 Bytes
3f49de3
0ace41e
3f49de3
0ace41e
3f49de3
0ace41e
416d80d
0ace41e
416d80d
 
 
0ace41e
f5d3971
0ace41e
 
 
 
b204b33
0ace41e
b204b33
 
0ace41e
b204b33
 
 
0ace41e
 
b204b33
0ace41e
b204b33
 
 
0ace41e
b204b33
 
 
0ace41e
b204b33
0ace41e
 
b204b33
0ace41e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b204b33
0ace41e
b204b33
0ace41e
 
b204b33
0ace41e
b204b33
a937c7e
 
b204b33
0ace41e
 
b204b33
0ace41e
b204b33
0ace41e
 
b204b33
 
 
 
 
 
0ace41e
 
 
 
 
e52cf6c
0ace41e
 
b204b33
 
 
0ace41e
 
 
 
d1b9593
0ace41e
 
 
 
 
 
cf1882c
0ace41e
 
 
 
 
 
 
13681ab
0ace41e
e6a5980
f444687
 
 
e52cf6c
 
0ace41e
 
8c43c56
0ace41e
b204b33
 
 
0ace41e
8c43c56
0ace41e
3f49de3
 
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
FROM node:22-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
    git openssh-client build-essential python3 python3-pip g++ make ca-certificates sqlite3 \
    && rm -rf /var/lib/apt/lists/*

RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages

RUN update-ca-certificates && \
    git config --global http.sslVerify false && \
    git config --global url."https://github.com/".insteadOf ssh://git@github.com/

RUN npm install -g openclaw@2026.6.9 --unsafe-perm

ENV PORT=7860 OPENCLAW_GATEWAY_MODE=local HOME=/root

# ==================== 同步引擎 - 最终修复版 ====================
RUN cat > /usr/local/bin/sync.py << 'EOF'
import os, sys, tarfile, shutil
from huggingface_hub import HfApi, hf_hub_download
from datetime import datetime, timedelta

api = HfApi()
repo_id = os.getenv("HF_DATASET")
token = os.getenv("HF_TOKEN")
BASE = "/root/.openclaw"

def restore():
    print("🔍 [Restore] Searching latest backup...")
    try:
        files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)
        now = datetime.now()
        for i in range(5):
            day = (now - timedelta(days=i)).strftime("%Y-%m-%d")
            name = f"backup_{day}.tar.gz"
            if name in files:
                print(f"📦 Downloading {name}...")
                path = hf_hub_download(repo_id=repo_id, filename=name, repo_type="dataset", token=token)
                
                print("📂 Tar contents preview:")
                with tarfile.open(path, "r:gz") as tar:
                    for member in tar.getmembers()[:20]:  # 只打印前20print("  ", member.name)
                    
                    for member in tar.getmembers():
                        # 关键修复:统一放到 .openclaw 下
                        if member.name.startswith('agents/') or member.name.startswith('skills/') or \
                           member.name.startswith('workspace/') or member.name.startswith('cron/') or \
                           member.name.startswith('state/'):
                            member.name = os.path.join('.openclaw', member.name)
                        elif member.name == 'openclaw.json' or member.name == 'backup_state.sqlite':
                            member.name = os.path.join('.openclaw', member.name)
                        tar.extract(member, "/root")
                
                print("✅ Extraction completed")
                
                # 处理 DB
                if os.path.exists(f"{BASE}/backup_state.sqlite"):
                    os.makedirs(f"{BASE}/state", exist_ok=True)
                    shutil.move(f"{BASE}/backup_state.sqlite", f"{BASE}/state/openclaw.sqlite")
                    print("✅ SQLite (cron) restored")
                return True
        print("⚠️ No backup found")
    except Exception as e:
        print(f"❌ Restore error: {e}")

def backup():
    print("📦 [Backup] Creating...")
    try:
        day = datetime.now().strftime("%Y-%m-%d")
        name = f"backup_{day}.tar.gz"
        with tarfile.open(name, "w:gz") as tar:
            if os.path.exists(BASE):
                tar.add(BASE, arcname=".openclaw")
        api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token)
        print(f"✅ Backup uploaded: {name}")
    except Exception as e:
        print(f"❌ Backup error: {e}")

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

# 模板
RUN mkdir -p /root/.openclaw
RUN cat > /root/.openclaw/openclaw.json.template << 'EOT'
{"models":{"providers":{"thirdparty":{"baseUrl":"PLACEHOLDER_BASE_URL","apiKey":"PLACEHOLDER_API_KEY","api":"openai-completions","headers":{"User-Agent":"Mozilla/5.0"},"models":[{"id":"PLACEHOLDER_MODEL_ID","name":"GLM-4.7-Flash","contextWindow":131072}]}}},"agents":{"defaults":{"model":{"primary":"thirdparty/PLACEHOLDER_MODEL_ID"}}},"gateway":{"mode":"local","bind":"lan","port":7860,"trustedProxies":["0.0.0.0/0","10.0.0.0/8","10.16.0.0/12","172.16.0.0/12","192.168.0.0/16"],"auth":{"mode":"token","token":"PLACEHOLDER_GATEWAY_PASSWORD"},"controlUi":{"enabled":true,"allowInsecureAuth":true,"dangerouslyAllowHostHeaderOriginFallback":true,"dangerouslyDisableDeviceAuth":true}}}
EOT

# 启动脚本
RUN cat > /usr/local/bin/start-openclaw << 'EOF'
#!/bin/bash
set -e
mkdir -p /root/.openclaw/{sessions,state}

echo "🚀 Starting OpenClaw..."

python3 /usr/local/bin/sync.py restore
sleep 8

if [ ! -d "/root/.openclaw/agents" ]; then
    echo "🔄 Retrying restore..."
    python3 /usr/local/bin/sync.py restore
    sleep 6
fi

echo "=== Final Status ==="
echo "Agents dir: $([ -d "/root/.openclaw/agents" ] && echo Yes || echo No)"
echo "Sessions: $(ls /root/.openclaw/agents/main/sessions 2>/dev/null | wc -l || echo 0)"
echo "Skills: $(ls /root/.openclaw/skills 2>/dev/null | wc -l || echo 0)"
[ -f "/root/.openclaw/state/openclaw.sqlite" ] && echo "Cron jobs: $(sqlite3 /root/.openclaw/state/openclaw.sqlite "SELECT COUNT(*) FROM cron_jobs WHERE enabled=1;" 2>/dev/null || echo 0)"

#python3 /usr/local/bin/sync.py backup

CLEAN_BASE=$(echo "$OPENAI_API_BASE" | sed 's|/chat/completions||g' | sed 's|/v1/|/v1|g' | sed 's|/v1$|/v1|g')
sed -e "s|PLACEHOLDER_BASE_URL|$CLEAN_BASE|g" \
    -e "s|PLACEHOLDER_API_KEY|$OPENAI_API_KEY|g" \
    -e "s|PLACEHOLDER_MODEL_ID|$MODEL|g" \
    -e "s|PLACEHOLDER_GATEWAY_PASSWORD|$OPENCLAW_GATEWAY_PASSWORD|g" \
    /root/.openclaw/openclaw.json.template > /root/.openclaw/openclaw.json

echo "✅ OpenClaw started"
(while true; do sleep 12000; python3 /usr/local/bin/sync.py backup; done) &

openclaw doctor --fix
exec openclaw gateway run --port $PORT
EOF

RUN chmod +x /usr/local/bin/start-openclaw

EXPOSE 7860
CMD ["/usr/local/bin/start-openclaw"]