Files
BackupX/server/internal/service/retention_service.go
2026-03-17 13:29:09 +08:00

72 lines
1.9 KiB
Go

package service
import (
"context"
"time"
"backupx/server/internal/model"
"backupx/server/internal/repository"
"backupx/server/internal/storage"
"backupx/server/internal/storage/codec"
)
type RetentionService struct {
records repository.BackupRecordRepository
storageTargets repository.StorageTargetRepository
storageRegistry *storage.Registry
cipher *codec.ConfigCipher
}
func NewRetentionService(records repository.BackupRecordRepository, storageTargets repository.StorageTargetRepository, storageRegistry *storage.Registry, cipher *codec.ConfigCipher) *RetentionService {
return &RetentionService{records: records, storageTargets: storageTargets, storageRegistry: storageRegistry, cipher: cipher}
}
func (s *RetentionService) Apply(ctx context.Context, task *model.BackupTask) error {
if task == nil || (task.RetentionDays <= 0 && task.MaxBackups <= 0) {
return nil
}
items, err := s.records.ListSuccessfulByTask(ctx, task.ID)
if err != nil {
return err
}
removeSet := make(map[uint]model.BackupRecord)
if task.RetentionDays > 0 {
cutoff := time.Now().UTC().AddDate(0, 0, -task.RetentionDays)
for _, item := range items {
if item.CompletedAt != nil && item.CompletedAt.Before(cutoff) {
removeSet[item.ID] = item
}
}
}
if task.MaxBackups > 0 {
kept := 0
for _, item := range items {
if _, marked := removeSet[item.ID]; marked {
continue
}
kept++
if kept > task.MaxBackups {
removeSet[item.ID] = item
}
}
}
if len(removeSet) == 0 {
return nil
}
provider, _, err := buildStorageProviderFromRepos(ctx, task.StorageTargetID, s.storageTargets, s.storageRegistry, s.cipher)
if err != nil {
return err
}
for _, item := range removeSet {
if item.StoragePath != "" {
if err := provider.Delete(ctx, item.StoragePath); err != nil {
return err
}
}
if err := s.records.Delete(ctx, item.ID); err != nil {
return err
}
}
return nil
}