b
File size: 3,872 Bytes
3894c0f
 
0318d4c
 
d558b55
3894c0f
0318d4c
 
3894c0f
 
0318d4c
42dc41b
 
 
884ad4a
0318d4c
 
 
 
d558b55
0318d4c
 
42dc41b
3894c0f
 
 
0318d4c
 
 
3894c0f
 
42dc41b
3894c0f
0318d4c
 
 
42dc41b
d558b55
0318d4c
d558b55
0318d4c
 
 
 
 
 
 
d558b55
 
0318d4c
 
 
42dc41b
d558b55
0318d4c
 
 
d558b55
0318d4c
3894c0f
0318d4c
 
d558b55
8c2c76a
0318d4c
 
 
 
 
3894c0f
0318d4c
 
 
d558b55
0318d4c
 
 
d558b55
0318d4c
d558b55
0318d4c
9b31860
0318d4c
 
 
 
 
 
 
3894c0f
0318d4c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42dc41b
0318d4c
 
 
3894c0f
 
 
0318d4c
d558b55
0318d4c
 
 
 
 
 
 
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
#!/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