package useCases import ( "RenewCMS/internal/domain/audit" "context" "time" ) const defaultCleanupBatchSize = 1000 type CleanupActivityUseCase struct { events audit.Repository settings audit.SettingsRepository recorder audit.Recorder batchSize int } func NewCleanupActivityUseCase(events audit.Repository, settings audit.SettingsRepository, recorder audit.Recorder) *CleanupActivityUseCase { return &CleanupActivityUseCase{events, settings, recorder, defaultCleanupBatchSize} } func (c *CleanupActivityUseCase) WithBatchSize(batchSize int) *CleanupActivityUseCase { c.batchSize = batchSize return c } func (c *CleanupActivityUseCase) Tick(now time.Time) (audit.CleanupResult, bool, error) { settings, err := c.settings.Get() if err != nil { return audit.CleanupResult{}, false, err } if !settings.HasRetentionLimit() || !settings.CleanupDue(now) { return audit.CleanupResult{}, false, nil } removed := 0 if settings.RetentionDays != audit.ForeverRetentionDays { removed, err = c.events.DeleteOlderThan(audit.RetentionCutoff(now, settings.RetentionDays)) if err != nil { return audit.CleanupResult{}, false, err } } if settings.RetentionMaxGB != audit.NoSizeLimitGB { trimmed, err := c.trimToSize(now, settings.MaxLogSizeBytes()) if err != nil { return audit.CleanupResult{}, false, err } removed += trimmed } if err := c.settings.SaveLastCleanup(now, removed); err != nil { return audit.CleanupResult{}, false, err } if removed > 0 { c.recordCleanup(removed) } return audit.CleanupResult{Removed: removed}, true, nil } func (c *CleanupActivityUseCase) trimToSize(now time.Time, limitBytes int64) (int, error) { guard := audit.GuardCutoff(now) removed := 0 for { size, err := c.events.SizeBytes() if err != nil { return removed, err } if size <= limitBytes { return removed, nil } batch, err := c.events.DeleteOldest(c.batchSize, guard) if err != nil { return removed, err } if batch == 0 { return removed, nil } removed += batch } } func (c *CleanupActivityUseCase) recordCleanup(removed int) { event := audit.NewEvent(audit.ActionCleanup, audit.CategorySystem) event.Actor = audit.SystemActor() event.Source = audit.SourceSystem event.Params = map[string]any{audit.ParamRemoved: removed} c.recorder.Record(context.Background(), event) }