b / sync_data.sh
aappeekk's picture
Update sync_data.sh
0318d4c verified
#!/bin/bash
# --- 1. 参数与环境检查 ---
LOG_PREFIX="[Koishi-Cloud-Sync]"
if [ -z "$WEBDAV_URL" ] || [ -z "$WEBDAV_USERNAME" ] || [ -z "$WEBDAV_PASSWORD" ]; then
echo "$LOG_PREFIX [WARN] WebDAV 未配置,直接启动 Koishi。"
exec yarn start
fi
# 确保路径不以斜杠结尾
CLEAN_URL=$(echo "${WEBDAV_URL}" | sed 's:/*$::')
WEBDAV_BACKUP_PATH=${WEBDAV_BACKUP_PATH:-""}
FULL_WEBDAV_URL="${CLEAN_URL}${WEBDAV_BACKUP_PATH:+/$WEBDAV_BACKUP_PATH}"
# 统一前缀名 (确保恢复和备份用的是同一个)
FILE_PREFIX="koishi_backup_"
# --- 2. 启动前恢复备份 ---
restore_backup() {
echo "$LOG_PREFIX [Restore] 正在从 WebDAV 恢复数据..."
python3 <<EOF
import sys, os, tarfile, requests
from webdav3.client import Client
options = {
"webdav_hostname": "${FULL_WEBDAV_URL}",
"webdav_login": "${WEBDAV_USERNAME}",
"webdav_password": "${WEBDAV_PASSWORD}",
}
client = Client(options)
try:
# 这里的 list() 会受 hostname 里的子路径影响,处理文件名过滤
files = client.list()
backups = sorted([f for f in files if f.startswith("${FILE_PREFIX}") and f.endswith(".tar.gz")])
if not backups:
print("$LOG_PREFIX [Restore] WebDAV 上没有发现备份文件,跳过恢复。")
sys.exit(0)
latest = backups[-1]
print(f"$LOG_PREFIX [Restore] 发现最新备份: {latest}")
# 构造下载链接
download_url = f"${FULL_WEBDAV_URL}/{latest}"
r = requests.get(download_url, auth=("${WEBDAV_USERNAME}", "${WEBDAV_PASSWORD}"), stream=True)
if r.status_code == 200:
tmp_path = f"/tmp/{latest}"
with open(tmp_path, "wb") as f:
for chunk in r.iter_content(8192):
f.write(chunk)
with tarfile.open(tmp_path, "r:gz") as tar:
tar.extractall("/app")
print("$LOG_PREFIX [Restore] 数据恢复成功!")
else:
print(f"$LOG_PREFIX [Restore] 下载失败,状态码: {r.status_code}")
except Exception as e:
print(f"$LOG_PREFIX [Restore] 发生错误: {e}")
EOF
}
# --- 3. 周期性备份任务 ---
sync_loop() {
# 给系统留出启动时间
sleep 60
while true; do
ts=$(date +%Y%m%d_%H%M%S)
file_name="${FILE_PREFIX}${ts}.tar.gz"
local_tmp="/tmp/${file_name}"
echo "$LOG_PREFIX [Sync] 正在打包数据 (包含 node_modules)..."
# 使用 /app 目录进行打包
tar -czf "$local_tmp" -C /app .
echo "$LOG_PREFIX [Sync] 打包完成 ($(du -h $local_tmp | cut -f1)),准备上传..."
python3 <<EOF
from webdav3.client import Client
import os
options = {
"webdav_hostname": "${FULL_WEBDAV_URL}",
"webdav_login": "${WEBDAV_USERNAME}",
"webdav_password": "${WEBDAV_PASSWORD}",
}
client = Client(options)
try:
# webdav3 的 upload_file 第一个参数是远程文件名,第二个是本地路径
# 注意:如果 options 已经包含完整路径,此处只需传文件名
client.upload_file("$file_name", "$local_tmp")
print(f"$LOG_PREFIX [Sync] 上传成功: $file_name")
# 清理旧备份
files = sorted([f for f in client.list() if f.startswith("${FILE_PREFIX}") and f.endswith(".tar.gz")])
if len(files) > 5:
for old_file in files[:-5]:
client.clean(old_file)
print(f"$LOG_PREFIX [Clean] 已删除旧备份: {old_file}")
except Exception as e:
print(f"$LOG_PREFIX [Error] 上传过程中出错: {e}")
EOF
rm -f "$local_tmp"
# 默认 2 小时同步一次
echo "$LOG_PREFIX [Sync] 本次任务结束,等待下一次循环..."
sleep ${SYNC_INTERVAL:-7200}
done
}
# --- 执行流 ---
restore_backup
# 启动备份进程 (后台)
sync_loop &
# 启动 Koishi (前台)
echo "$LOG_PREFIX 正在启动 Koishi 服务..."
exec yarn start