chat / run.sh
Zxen's picture
Update run.sh
04bffbb verified
#!/bin/bash
# --- 1. DNS 优化 ---
echo "⚙️ 正在配置 DNS (优化解析速度)..."
echo "nameserver 1.1.1.1" > /etc/resolv.conf
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
# --- 2. 基础配置 ---
DATA_DIR="/root/.openclaw"
INDEX_FILE="backups.txt"
MAX_BACKUPS="${MAX_BACKUPS:-7}"
CHECK_INTERVAL="${CHECK_INTERVAL:-10}"
export TZ=Asia/Shanghai
[[ -n "${WEBDAV_URL}" && "${WEBDAV_URL}" != */ ]] && WEBDAV_URL="${WEBDAV_URL}/"
INDEX_URL="${WEBDAV_URL}${INDEX_FILE}"
MARKER_FILE="/tmp/last_backup_marker"
CURL_ARGS="-s -L --fail --connect-timeout 20 --retry 3"
if [ -n "$WEBDAV_USER" ]; then
CURL_ARGS="$CURL_ARGS -u $WEBDAV_USER:$WEBDAV_PASSWORD"
fi
# --- 3. 动态生成 openclaw.json ---
generate_config() {
echo "🔧 正在从环境变量生成 openclaw.json..."
mkdir -p "$DATA_DIR"
# 先写入基础配置(无模型)
cat > "$DATA_DIR/openclaw.json" <<'EOFBASE'
{
"models": {},
"agents": {
"defaults": {
"workspace": "/root/.openclaw/workspace"
}
},
"messages": { "ackReactionScope": "group-mentions" },
"commands": { "native": "auto", "nativeSkills": "auto", "restart": true },
"channels": {},
"gateway": {
"port": 7860,
"mode": "local",
"bind": "lan",
"controlUi": { "dangerouslyDisableDeviceAuth": true },
"auth": { "mode": "token" },
"trustedProxies": ["127.0.0.1", "10.0.0.0/8"]
},
"skills": { "install": { "nodeManager": "npm" } },
"plugins": { "entries": {} }
}
EOFBASE
CONFIG="$DATA_DIR/openclaw.json"
# 如果安装了 jq 则用 jq 注入,否则使用基础配置
if command -v jq &>/dev/null; then
# 模型配置(可选)
if [ -n "$API_KEY" ]; then
MID="${MODEL_ID:-claude-opus-4-5-20251101}"
MNAME="${MODEL_NAME:-Claude Opus 4.5}"
MALIAS="${MODEL_ALIAS:-opus}"
jq --arg url "${API_BASE_URL}" \
--arg key "${API_KEY}" \
--arg mid "$MID" --arg mname "$MNAME" --arg malias "$MALIAS" \
--argjson ctx "${MODEL_CONTEXT_WINDOW:-200000}" \
--argjson maxt "${MODEL_MAX_TOKENS:-32000}" \
'.models = {
mode: "merge",
providers: { openai: {
baseUrl: $url, apiKey: $key,
models: [{ id: $mid, name: $mname, api: "openai-chat",
reasoning: true, input: ["text","image"],
contextWindow: $ctx, maxTokens: $maxt }]
}}
}
| .agents.defaults.model = { primary: ("openai/" + $mid) }
| .agents.defaults.models = { ("openai/" + $mid): { alias: $malias } }' \
"$CONFIG" > "$CONFIG.tmp" && mv "$CONFIG.tmp" "$CONFIG"
fi
# HF Space URL(可选)
if [ -n "$HF_SPACE_URL" ]; then
jq --arg url "$HF_SPACE_URL" \
'.gateway.controlUi.allowedOrigins = [$url]' \
"$CONFIG" > "$CONFIG.tmp" && mv "$CONFIG.tmp" "$CONFIG"
fi
# Gateway auth token(可选)
if [ -n "$GATEWAY_AUTH_TOKEN" ]; then
jq --arg tok "$GATEWAY_AUTH_TOKEN" \
'.gateway.auth.token = $tok' \
"$CONFIG" > "$CONFIG.tmp" && mv "$CONFIG.tmp" "$CONFIG"
fi
else
echo "⚠️ 未找到 jq,使用基础配置(可通过控制面板修改)"
fi
echo "✅ openclaw.json 生成完成"
}
# --- 4. 核心备份函数 ---
do_backup_and_rotate() {
[ -z "$WEBDAV_URL" ] && return
[ ! -d "$DATA_DIR" ] && return
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
NEW_BACKUP_NAME="openclaw_${TIMESTAMP}.tar.gz"
TEMP_PATH="/tmp/$NEW_BACKUP_NAME"
echo "📦 [$(date)] 正在执行关键备份 (保存配置或定时监控)..."
# 打包并忽略变动警告
tar --exclude='logs' --exclude='tmp' --ignore-failed-read -czf "$TEMP_PATH" -C "$DATA_DIR" .
if [ $? -le 1 ]; then
if curl $CURL_ARGS -o /dev/null -T "$TEMP_PATH" "${WEBDAV_URL}${NEW_BACKUP_NAME}"; then
echo "✅ 备份上传成功"
# 更新索引
curl $CURL_ARGS "$INDEX_URL" -o /tmp/backups.txt 2>/dev/null || touch /tmp/backups.txt
echo "$NEW_BACKUP_NAME" >> /tmp/backups.txt
sed -i '/^$/d' /tmp/backups.txt
# 清理旧备份
TOTAL_LINES=$(wc -l < /tmp/backups.txt)
if [ "$TOTAL_LINES" -gt "$MAX_BACKUPS" ]; then
DELETE_COUNT=$((TOTAL_LINES - MAX_BACKUPS))
FILES_TO_DELETE=$(head -n "$DELETE_COUNT" /tmp/backups.txt)
for FILE in $FILES_TO_DELETE; do
curl -s $CURL_ARGS -X DELETE "${WEBDAV_URL}${FILE}"
done
tail -n "$MAX_BACKUPS" /tmp/backups.txt > /tmp/new_backups.txt
mv /tmp/new_backups.txt /tmp/backups.txt
fi
curl $CURL_ARGS -o /dev/null -T /tmp/backups.txt "$INDEX_URL"
touch "$MARKER_FILE"
else
echo "❌ 备份上传失败,请检查 WebDAV 配置"
fi
rm -f "$TEMP_PATH"
fi
}
# --- 5. 捕获退出信号 ---
CLEANUP_DONE=0
cleanup() {
[ "$CLEANUP_DONE" -eq 1 ] && return
CLEANUP_DONE=1
echo "⚠️ 接收到退出信号,正在保存最后一份配置到 WebDAV..."
do_backup_and_rotate
echo "👋 备份完成,进程退出。"
exit 0
}
trap cleanup SIGTERM EXIT
# --- 6. 恢复逻辑 ---
restore_latest() {
if [ -z "$WEBDAV_URL" ]; then
echo "ℹ️ 未配置 WEBDAV_URL,跳过备份恢复"
if [ ! -f "$DATA_DIR/openclaw.json" ]; then
generate_config
fi
return
fi
# 先验证 WebDAV 连通性(用 OPTIONS 方法,WebDAV 标准)
echo "🔍 正在验证 WebDAV 连接..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X OPTIONS -L --connect-timeout 10 \
${WEBDAV_USER:+-u "$WEBDAV_USER:$WEBDAV_PASSWORD"} \
"${WEBDAV_URL}")
if [[ "$HTTP_CODE" == "000" ]]; then
echo "❌ WebDAV 连接失败(无法连接),请检查 WEBDAV_URL"
generate_config
return
fi
echo "✅ WebDAV 连接正常 (HTTP $HTTP_CODE)"
echo "🔍 正在从 WebDAV 检查数据..."
if curl $CURL_ARGS "$INDEX_URL" -o /tmp/backups.txt; then
LATEST_FILE=$(tail -n 1 /tmp/backups.txt)
# 验证文件名格式,防止 WebDAV 返回 HTML
if [[ "$LATEST_FILE" =~ ^openclaw_[0-9]+_[0-9]+\.tar\.gz$ ]]; then
echo "⬇️ 正在恢复备份: $LATEST_FILE"
curl $CURL_ARGS "${WEBDAV_URL}${LATEST_FILE}" -o "/tmp/$LATEST_FILE"
mkdir -p "$DATA_DIR"
if tar -xzf "/tmp/$LATEST_FILE" -C "$DATA_DIR" --warning=no-timestamp; then
echo "✅ 备份恢复成功"
else
echo "❌ 备份解压失败,将重新生成配置"
fi
rm -f "/tmp/$LATEST_FILE"
else
echo "⚠️ 索引内容无效(可能是首次部署),跳过恢复"
fi
fi
# 兜底:如果没有配置文件,从环境变量生成
if [ ! -f "$DATA_DIR/openclaw.json" ]; then
echo "⚠️ 未找到已有配置,从环境变量生成"
generate_config
fi
}
# --- 7. 执行流程 ---
restore_latest
touch "$MARKER_FILE"
# 启动后台监控 (仅在配置了 WebDAV 时)
if [ -n "$WEBDAV_URL" ]; then
(
while true; do
sleep "$CHECK_INTERVAL"
CHANGED=$(find "$DATA_DIR" -type f -newer "$MARKER_FILE" -not -path "*/logs/*" -not -path "*/tmp/*" -print -quit)
if [ -n "$CHANGED" ]; then
do_backup_and_rotate
fi
done
) &
fi
# 启动主程序 (不使用 exec,确保 trap 能捕捉到退出)
echo "🚀 OpenClaw 启动成功"
openclaw gateway run