Files
BackupX/server/internal/backup/temp_files.go
Wu Qing 00151e466c feat: 解决 CDC 去重、集中备份与首次初始化问题 (#105)
实现 CDC 内容寻址仓库、远程 Agent 中央中转备份与首次初始化体验,并补充安全校验、测试及双语文档。

Closes #94
Closes #101
Closes #104
2026-08-07 23:01:29 +08:00

76 lines
2.3 KiB
Go

package backup
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"time"
)
var fileNameCleaner = regexp.MustCompile(`[^a-zA-Z0-9._-]+`)
func EnsureTempRoot() (string, error) {
root := filepath.Join(os.TempDir(), "backupx")
if err := os.MkdirAll(root, 0o755); err != nil {
return "", fmt.Errorf("create backup temp root: %w", err)
}
return root, nil
}
func CreateTaskTempDir(taskName string, startedAt time.Time) (string, error) {
root, err := EnsureTempRoot()
if err != nil {
return "", err
}
name := sanitizeTaskName(taskName)
if name == "" {
name = "backup"
}
path := filepath.Join(root, fmt.Sprintf("%s_%s", name, startedAt.UTC().Format("20060102_150405")))
if err := os.MkdirAll(path, 0o755); err != nil {
return "", fmt.Errorf("create task temp dir: %w", err)
}
return path, nil
}
func BuildArtifactName(taskName string, startedAt time.Time, extension string) string {
name := sanitizeTaskName(taskName)
if name == "" {
name = "backup"
}
ext := strings.TrimSpace(extension)
if ext != "" && !strings.HasPrefix(ext, ".") {
ext = "." + ext
}
return fmt.Sprintf("%s_%s%s", name, startedAt.UTC().Format("20060102_150405"), ext)
}
func BuildStorageKey(backupType string, startedAt time.Time, fileName string) string {
typeName := strings.TrimSpace(strings.ToLower(backupType))
if typeName == "" {
typeName = "file"
}
return filepath.ToSlash(filepath.Join("BackupX", typeName, startedAt.UTC().Format("060102"), fileName))
}
// BuildRecordStorageKey gives remote-Agent artifacts a record-owned namespace.
// The Master validates this namespace before accepting a relayed upload, so one
// Agent cannot overwrite another record's object on centrally mounted storage.
func BuildRecordStorageKey(backupType string, startedAt time.Time, recordID uint, fileName string) string {
typeName := strings.TrimSpace(strings.ToLower(backupType))
if typeName == "" {
typeName = "file"
}
return filepath.ToSlash(filepath.Join("BackupX", typeName, startedAt.UTC().Format("060102"), "records", fmt.Sprintf("%d", recordID), fileName))
}
func sanitizeTaskName(value string) string {
trimmed := strings.TrimSpace(strings.ToLower(value))
trimmed = strings.ReplaceAll(trimmed, " ", "-")
trimmed = fileNameCleaner.ReplaceAllString(trimmed, "-")
trimmed = strings.Trim(trimmed, "-._")
return trimmed
}