File size: 7,110 Bytes
3f49de3
687d8aa
3f49de3
 
4bc980d
3f49de3
 
687d8aa
6749611
416d80d
687d8aa
f444687
416d80d
 
 
687d8aa
416d80d
 
687d8aa
416d80d
 
 
 
687d8aa
1b4a82a
b204b33
 
 
 
687d8aa
b204b33
 
 
 
 
 
f33cde5
b204b33
 
d4e00ce
b204b33
 
 
f33cde5
b204b33
 
 
1b4a82a
b204b33
e6a5980
b204b33
e6a5980
b204b33
 
 
 
 
f33cde5
b204b33
1b4a82a
f33cde5
 
 
 
1b4a82a
6749611
 
 
 
1b4a82a
 
 
 
 
 
 
 
 
 
 
 
 
e6a5980
 
b204b33
1b4a82a
b204b33
e6a5980
b204b33
 
 
 
 
 
 
 
1b4a82a
5cb2a86
e52cf6c
 
 
 
f444687
 
 
e52cf6c
 
 
d7433d1
 
f444687
e52cf6c
 
 
 
 
 
 
d4e00ce
e52cf6c
f444687
e52cf6c
 
 
 
 
 
 
6749611
e52cf6c
 
 
 
 
 
 
 
 
 
 
 
 
 
1b4a82a
b204b33
 
 
e52cf6c
b204b33
 
e6a5980
 
f33cde5
b204b33
 
1b4a82a
e6a5980
f33cde5
 
 
 
1b4a82a
f33cde5
1b4a82a
 
 
 
 
e52cf6c
1b4a82a
f33cde5
e6a5980
 
f33cde5
e6a5980
f444687
 
 
e52cf6c
 
b204b33
1b4a82a
e52cf6c
f33cde5
e6a5980
b204b33
 
 
 
e52cf6c
b204b33
687d8aa
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
FROM node:22-slim

# 1. 基础依赖补全
RUN apt-get update && apt-get install -y --no-install-recommends \
    git openssh-client build-essential python3 python3-pip \
    g++ make ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# 2. 安装 HF 数据交互工具
RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages

# 3. 构建环境优化
RUN update-ca-certificates && \
    git config --global http.sslVerify false && \
    git config --global url."https://github.com/".insteadOf ssh://git@github.com/

# 4. OpenClaw 核心安装
RUN npm install -g openclaw@latest --unsafe-perm

# 5. 环境变量预设
ENV PORT=7860 \
    OPENCLAW_GATEWAY_MODE=local \
    HOME=/root

# 6. Python 同步引擎(已新增定时任务完整备份)
RUN cat > /usr/local/bin/sync.py << 'EOF'
import os, sys, tarfile
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")

def restore():
    try:
        print("🔍 [Restore] Searching for latest backup...")
        files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)
        now = datetime.now()
        for i in range(7):
            day = (now - timedelta(days=i)).strftime("%Y-%m-%d")
            name = f"backup_{day}.tar.gz"
            if name in files:
                print(f"📦 [Restore] Found: {name}")
                path = hf_hub_download(repo_id=repo_id, filename=name, repo_type="dataset", token=token)
                with tarfile.open(path, "r:gz") as tar:
                    tar.extractall(path="/root/.openclaw/")
                print(f"✅ [Restore] Success: Restored sessions + skills + scheduled tasks + agents from {name}")
                return True
        print("⚠️ [Restore] No recent backup found.")
    except Exception as e:
        print(f"❌ [Restore] Error: {e}")

def backup():
    try:
        day = datetime.now().strftime("%Y-%m-%d")
        name = f"backup_{day}.tar.gz"
        print(f"📦 [Backup] Starting → {name}")
        with tarfile.open(name, "w:gz") as tar:
            # 会话
            if os.path.exists("/root/.openclaw/agents"):
                tar.add("/root/.openclaw/agents", arcname="agents")
                session_count = len(os.listdir("/root/.openclaw/agents/main/sessions")) if os.path.exists("/root/.openclaw/agents/main/sessions") else 0
                print(f"   → Backed up agents/sessions ({session_count} sessions)")
            # 技能
            if os.path.exists("/root/.openclaw/skills"):
                tar.add("/root/.openclaw/skills", arcname="skills")
            if os.path.exists("/root/.openclaw/workspace"):
                tar.add("/root/.openclaw/workspace", arcname="workspace")
            # 定时任务(新增重点)
            if os.path.exists("/root/.openclaw/cron"):
                tar.add("/root/.openclaw/cron", arcname="cron")
                print("   → Backed up cron/ (scheduled tasks)")
            if os.path.exists("/root/.openclaw/agents/main/cron"):
                tar.add("/root/.openclaw/agents/main/cron", arcname="agents/main/cron")
                print("   → Backed up agents/main/cron")
            if os.path.exists("/root/.openclaw/workspace/cron"):
                tar.add("/root/.openclaw/workspace/cron", arcname="workspace/cron")
                print("   → Backed up workspace/cron")
            # 其他必要目录
            if os.path.exists("/root/.openclaw/openclaw.json"):
                tar.add("/root/.openclaw/openclaw.json", arcname="openclaw.json")
            if os.path.exists("/root/.openclaw/.clawhub"):
                tar.add("/root/.openclaw/.clawhub", arcname=".clawhub")
        api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token)
        print(f"✅ [Backup] Success: {name} uploaded (includes scheduled tasks)")
    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

# 7. openclaw.json 模板(你的第三方 API 配置)
RUN mkdir -p /root/.openclaw && \
    cat > /root/.openclaw/openclaw.json.template << 'EOT'
{
  "models": {
    "providers": {
      "thirdparty": {
        "baseUrl": "PLACEHOLDER_BASE_URL",
        "apiKey": "PLACEHOLDER_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "gemini-3.1-pro-high",
            "name": "Gemini 3.1 Pro (High)",
            "contextWindow": 131072
          }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "timeoutSeconds": 300,           // 整体任务超时,建议 3005分钟)或更高
      "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

# 8. 启动脚本(显示定时任务恢复情况)
RUN cat > /usr/local/bin/start-openclaw << 'EOF'
#!/bin/bash
set -e

mkdir -p /root/.openclaw/sessions

echo "🚀 Starting OpenClaw with full persistence..."

# 恢复所有数据
python3 /usr/local/bin/sync.py restore

# 显示恢复后的会话和定时任务
echo "=== Restored Sessions ==="
if [ -d "/root/.openclaw/agents/main/sessions" ]; then
    count=$(ls -1 "/root/.openclaw/agents/main/sessions" 2>/dev/null | wc -l)
    echo "agents/main/sessions: ${count} sessions"
else
    echo "No agents/main/sessions yet"
fi
echo "=== Restored Scheduled Tasks (cron) ==="
ls -la /root/.openclaw/cron 2>/dev/null || echo "No global cron"
ls -la /root/.openclaw/agents/main/cron 2>/dev/null || echo "No agents/main/cron"
ls -la /root/.openclaw/workspace/cron 2>/dev/null || echo "No workspace/cron"
echo "=================================="

# 立即备份一次
echo "📤 Immediate backup after restore..."
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 fully started (sessions + skills + scheduled tasks restored)"

# 每20分钟自动备份
(while true; do sleep 1200; 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"]