td / sync-script.sh
hxger's picture
Upload 3 files
e1ffe54 verified
#!/bin/bash
set -e
WEBDAV_URL="${WEBDAV_URL}"
WEBDAV_USERNAME="${WEBDAV_USERNAME}"
WEBDAV_PASSWORD="${WEBDAV_PASSWORD}"
DB_PATH="${DB_PATH:-/app/db}"
BACKUP_PATH="${BACKUP_PATH:-/app/backup}"
BACKUP_FILENAME="${BACKUP_FILENAME:-tgdrive_db_backup.tar.gz}"
REMOTE_BACKUP_DIR="${REMOTE_BACKUP_DIR:-tgdrive_backup}"
CONFIG_FILE="/app/config/sync_config"
PYTHON_CMD="/app/venv/bin/python3"
mkdir -p ${BACKUP_PATH}
mkdir -p /app/logs
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> /app/logs/sync.log 2>/dev/null || true
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
mkdir -p /app/logs 2>/dev/null || true
touch /app/logs/sync.log 2>/dev/null || true
if [ ! -f "$CONFIG_FILE" ]; then
log "创建初始配置文件"
mkdir -p /app/config 2>/dev/null || true
echo "LAST_SYNC=0" > "$CONFIG_FILE" 2>/dev/null || true
fi
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE" 2>/dev/null || true
fi
if [ -z "$WEBDAV_URL" ] || [ -z "$WEBDAV_USERNAME" ] || [ -z "$WEBDAV_PASSWORD" ]; then
log "错误: WebDAV配置不完整,请设置WEBDAV_URL, WEBDAV_USERNAME, WEBDAV_PASSWORD环境变量"
exit 1
fi
backup_db() {
log "开始备份数据库..."
if [ -d "$DB_PATH" ]; then
if [[ "$DB_PATH" == "/app/db" ]]; then
tar -czf "${BACKUP_PATH}/${BACKUP_FILENAME}" -C /app db
else
tar -czf "${BACKUP_PATH}/${BACKUP_FILENAME}" -C $(dirname "$DB_PATH") $(basename "$DB_PATH")
fi
log "数据库已备份到 ${BACKUP_PATH}/${BACKUP_FILENAME}"
return 0
else
log "警告: 数据库目录不存在"
return 1
fi
}
upload_to_webdav() {
log "开始上传备份到WebDAV (目标目录: ${REMOTE_BACKUP_DIR})..."
$PYTHON_CMD -c "
import webdav3.client as wc
import os
options = {
'webdav_hostname': '$WEBDAV_URL',
'webdav_login': '$WEBDAV_USERNAME',
'webdav_password': '$WEBDAV_PASSWORD',
'webdav_timeout': 30
}
client = wc.Client(options)
# 检查远程目录是否存在
if not client.check('$REMOTE_BACKUP_DIR'):
client.mkdir('$REMOTE_BACKUP_DIR')
# 上传文件
local_path = '${BACKUP_PATH}/${BACKUP_FILENAME}'
remote_path = '$REMOTE_BACKUP_DIR/${BACKUP_FILENAME}'
if os.path.exists(local_path):
try:
client.upload_sync(remote_path=remote_path, local_path=local_path)
print('上传成功')
except Exception as e:
print(f'上传失败: {e}')
else:
print('本地备份文件不存在')
"
if [ $? -eq 0 ]; then
log "备份已成功上传到WebDAV (${REMOTE_BACKUP_DIR}/${BACKUP_FILENAME})"
echo "LAST_SYNC=$(date +%s)" > "$CONFIG_FILE"
return 0
else
log "上传到WebDAV失败"
return 1
fi
}
download_from_webdav() {
log "开始从WebDAV下载备份 (源目录: ${REMOTE_BACKUP_DIR})..."
$PYTHON_CMD -c "
import webdav3.client as wc
import os
options = {
'webdav_hostname': '$WEBDAV_URL',
'webdav_login': '$WEBDAV_USERNAME',
'webdav_password': '$WEBDAV_PASSWORD',
'webdav_timeout': 30
}
client = wc.Client(options)
# 检查远程文件是否存在
remote_path = '$REMOTE_BACKUP_DIR/${BACKUP_FILENAME}'
local_path = '${BACKUP_PATH}/${BACKUP_FILENAME}'
if client.check(remote_path):
try:
client.download_sync(remote_path=remote_path, local_path=local_path)
print('下载成功')
except Exception as e:
print(f'下载失败: {e}')
else:
print('远程备份文件不存在')
"
if [ $? -eq 0 ]; then
log "备份已成功从WebDAV (${REMOTE_BACKUP_DIR}/${BACKUP_FILENAME}) 下载"
return 0
else
log "从WebDAV下载备份失败"
return 1
fi
}
restore_db() {
log "开始恢复数据库到 ${DB_PATH}..."
if [ -f "${BACKUP_PATH}/${BACKUP_FILENAME}" ]; then
if [ -d "$DB_PATH" ] && [ "$(ls -A $DB_PATH 2>/dev/null)" ]; then
local timestamp=$(date +%Y%m%d%H%M%S)
if [[ "$DB_PATH" == "/app/db" ]]; then
tar -czf "${BACKUP_PATH}/db_before_restore_${timestamp}.tar.gz" -C /app db 2>/dev/null || log "无法创建当前数据库备份,继续恢复..."
else
tar -czf "${BACKUP_PATH}/db_before_restore_${timestamp}.tar.gz" -C $(dirname "$DB_PATH") $(basename "$DB_PATH") 2>/dev/null || log "无法创建当前数据库备份,继续恢复..."
fi
log "尝试备份当前数据库到 ${BACKUP_PATH}/db_before_restore_${timestamp}.tar.gz"
fi
# 创建临时恢复目录
mkdir -p /tmp/tgdrive_restore 2>/dev/null || true
# 解压备份文件到临时目录
tar -xzf "${BACKUP_PATH}/${BACKUP_FILENAME}" -C /tmp/tgdrive_restore 2>/dev/null || {
log "解压备份文件失败,可能是格式不正确"
rm -rf /tmp/tgdrive_restore 2>/dev/null || true
return 1
}
# 确保数据库目录存在
mkdir -p "$DB_PATH" 2>/dev/null || true
# 清空数据库目录内容(逐个文件删除而不是删除整个目录)
find "$DB_PATH" -mindepth 1 -delete 2>/dev/null || log "无法清空数据库目录,将尝试直接覆盖..."
# 复制恢复的文件到数据库目录
if [ -d "/tmp/tgdrive_restore/db" ]; then
cp -rf /tmp/tgdrive_restore/db/* "$DB_PATH"/ 2>/dev/null || {
log "复制恢复文件失败,尝试使用rsync..."
which rsync >/dev/null 2>&1 && rsync -a /tmp/tgdrive_restore/db/ "$DB_PATH"/ 2>/dev/null
}
else
log "备份中找不到db目录,尝试直接复制临时目录内容..."
cp -rf /tmp/tgdrive_restore/* "$DB_PATH"/ 2>/dev/null || {
log "复制恢复文件失败,尝试使用rsync..."
which rsync >/dev/null 2>&1 && rsync -a /tmp/tgdrive_restore/ "$DB_PATH"/ 2>/dev/null
}
fi
rm -rf /tmp/tgdrive_restore 2>/dev/null || true
log "数据库已尝试恢复到 ${DB_PATH}"
return 0
else
log "错误: 备份文件不存在,无法恢复数据库"
return 1
fi
}
case "$1" in
backup)
backup_db && upload_to_webdav
;;
restore)
download_from_webdav && restore_db
;;
sync)
current_time=$(date +%s)
download_from_webdav
if { [ ! -d "$DB_PATH" ] || [ ! "$(ls -A $DB_PATH 2>/dev/null)" ]; } && [ -f "${BACKUP_PATH}/${BACKUP_FILENAME}" ]; then
log "检测到本地数据库不存在或为空,开始恢复..."
restore_db
fi
backup_db && upload_to_webdav
;;
*)
echo "用法: $0 {backup|restore|sync}"
echo " backup - 备份数据库并上传到WebDAV"
echo " restore - 从WebDAV下载备份并恢复数据库"
echo " sync - 同步数据库(双向)"
exit 1
;;
esac
exit 0