172 lines
3.4 KiB
Go
172 lines
3.4 KiB
Go
package transfer
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type CleanupService struct {
|
|
config CleanupConfig
|
|
pendingFiles []string
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func NewCleanupService(config CleanupConfig) *CleanupService {
|
|
return &CleanupService{
|
|
config: config,
|
|
pendingFiles: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
func (cs *CleanupService) ScheduleCleanup(filePath string) error {
|
|
if !cs.config.Enabled {
|
|
return nil
|
|
}
|
|
|
|
cs.mu.Lock()
|
|
defer cs.mu.Unlock()
|
|
cs.pendingFiles = append(cs.pendingFiles, filePath)
|
|
log.Printf("Scheduled file for cleanup: %s", filePath)
|
|
return nil
|
|
}
|
|
|
|
func (cs *CleanupService) Start(ctx context.Context) error {
|
|
if !cs.config.Enabled {
|
|
log.Println("Cleanup service disabled")
|
|
return nil
|
|
}
|
|
|
|
log.Printf("Cleanup service started (retention: %v, batch: %d)", cs.config.RetentionPeriod, cs.config.BatchSize)
|
|
|
|
ticker := time.NewTicker(cs.config.CheckInterval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
log.Println("Cleanup service shutting down...")
|
|
return ctx.Err()
|
|
case <-ticker.C:
|
|
if err := cs.ExecuteCleanup(ctx); err != nil {
|
|
log.Printf("Cleanup error: %v", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (cs *CleanupService) ExecuteCleanup(ctx context.Context) error {
|
|
cs.mu.Lock()
|
|
if len(cs.pendingFiles) == 0 {
|
|
cs.mu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
batchSize := cs.config.BatchSize
|
|
if batchSize > len(cs.pendingFiles) {
|
|
batchSize = len(cs.pendingFiles)
|
|
}
|
|
cs.mu.Unlock()
|
|
|
|
log.Printf("Executing cleanup batch (size: %d)", batchSize)
|
|
|
|
batch := make([]string, batchSize)
|
|
copy(batch, cs.pendingFiles[:batchSize])
|
|
cs.pendingFiles = cs.pendingFiles[batchSize:]
|
|
cs.mu.Unlock()
|
|
|
|
log.Printf("Processing %d files for cleanup", len(batch))
|
|
|
|
var cleanedCount int
|
|
var errors []error
|
|
|
|
for _, filePath := range batch {
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
default:
|
|
}
|
|
|
|
if err := cs.cleanupFile(filePath); err != nil {
|
|
errors = append(errors, fmt.Errorf("Failed to cleanup file %s: %w", filePath, err))
|
|
} else {
|
|
cleanedCount++
|
|
}
|
|
}
|
|
|
|
log.Printf("Cleanup batch completed (cleaned: %d, errors: %d)", cleanedCount, len(errors))
|
|
|
|
if len(errors) > 0 {
|
|
for i, err := range errors {
|
|
if i >= 3 {
|
|
log.Printf("... and %d more errors", len(errors)-3)
|
|
break
|
|
}
|
|
log.Printf("Error: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (cs *CleanupService) cleanupFile(filePath string) error {
|
|
info, err := os.Stat(filePath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("Failed to get file info: %w", err)
|
|
}
|
|
|
|
if cs.config.RetentionPeriod > 0 {
|
|
if time.Since(info.ModTime()) < cs.config.RetentionPeriod {
|
|
log.Printf("File too new to cleanup: %s", filePath)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if err := os.Remove(filePath); err != nil {
|
|
return fmt.Errorf("Failed to remove file: %w", err)
|
|
}
|
|
|
|
log.Printf("File cleaned up: %s", filePath)
|
|
return nil
|
|
}
|
|
|
|
func (cs *CleanupService) GetPendingCount() int {
|
|
cs.mu.Lock()
|
|
defer cs.mu.Unlock()
|
|
return len(cs.pendingFiles)
|
|
}
|
|
|
|
func (cs *CleanupService) ForceCleanupAll(ctx context.Context) error {
|
|
log.Println("Force cleanup requested")
|
|
|
|
for {
|
|
cs.mu.Lock()
|
|
pendingCount := len(cs.pendingFiles)
|
|
cs.mu.Unlock()
|
|
|
|
if pendingCount == 0 {
|
|
break
|
|
}
|
|
|
|
if err := cs.ExecuteCleanup(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(100 * time.Millisecond):
|
|
}
|
|
}
|
|
|
|
log.Println("Force cleanup complete")
|
|
return nil
|
|
}
|