func (gc GarbageCollector) StartupMessage() string {
	return ""
}
StartupMessage returns an empty string.
package gc
import (
	"context"
	"errors"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"github.com/gotenberg/gotenberg/v7/pkg/gotenberg"
	"go.uber.org/zap"
)
func init() {
	gotenberg.MustRegisterModule(GarbageCollector{})
}
type GarbageCollector struct {
	rootPath      string
	graceDuration time.Duration
	excludeSubstr []string
	ticker *time.Ticker
	done   chan bool
	logger *zap.Logger
}
type GarbageCollectorGraceDurationModifier interface {
	GraceDuration() time.Duration
}
type GarbageCollectorExcludeSubstrModifier interface {
	ExcludeSubstr() []string
}
func (gc GarbageCollector) Descriptor() gotenberg.ModuleDescriptor {
	return gotenberg.ModuleDescriptor{
		ID:  "gc",
		New: func() gotenberg.Module { return new(GarbageCollector) },
	}
}
func (gc *GarbageCollector) Provision(ctx *gotenberg.Context) error {
	gc.rootPath = gotenberg.TmpPath()
	graceDurationModifiers, err := ctx.Modules(new(GarbageCollectorGraceDurationModifier))
	if err != nil {
		return fmt.Errorf("get grace duration modifiers: %w", err)
	}
	for _, graceDurationModifier := range graceDurationModifiers {
		modifier := graceDurationModifier.(GarbageCollectorGraceDurationModifier)
		if gc.graceDuration < modifier.GraceDuration() {
			gc.graceDuration = modifier.GraceDuration()
		}
	}
	excludeSubstrModifiers, err := ctx.Modules(new(GarbageCollectorExcludeSubstrModifier))
	if err != nil {
		return fmt.Errorf("get exclude substr modifiers: %w", err)
	}
	gc.excludeSubstr = strings.Split(os.Getenv("GC_EXCLUDE_SUBSTR"), ",")
	for _, excludeSubstrModifier := range excludeSubstrModifiers {
		modifier := excludeSubstrModifier.(GarbageCollectorExcludeSubstrModifier)
		gc.excludeSubstr = append(gc.excludeSubstr, modifier.ExcludeSubstr()...)
	}
	loggerProvider, err := ctx.Module(new(gotenberg.LoggerProvider))
	if err != nil {
		return fmt.Errorf("get logger provider: %w", err)
	}
	logger, err := loggerProvider.(gotenberg.LoggerProvider).Logger(gc)
	if err != nil {
		return fmt.Errorf("get logger: %w", err)
	}
	gc.logger = logger
	return nil
}
func (gc *GarbageCollector) Start() error {
	gc.ticker = time.NewTicker(gc.graceDuration + time.Duration(1)*time.Second)
	gc.done = make(chan bool, 1)
	go func() {
		for {
			func() {
				gcMu.RLock()
				defer gcMu.RUnlock()
				select {
				case <-gc.done:
					return
				case <-gc.ticker.C:
					gc.collect(false)
				}
			}()
		}
	}()
	return nil
}
func (gc GarbageCollector) collect(force bool) {
	expirationTime := time.Now().Add(-gc.graceDuration)
	skipDirOrNil := func(info os.FileInfo) error {
		if info.IsDir() {
			return filepath.SkipDir
		}
		return nil
	}
	removePath := func(path string) {
		err := os.RemoveAll(path)
		if err != nil {
			gc.logger.Error(fmt.Sprintf("remove '%s': %s", path, err))
		}
		gc.logger.Debug(fmt.Sprintf("'%s' removed", path))
	}
	err := filepath.Walk(gc.rootPath, func(path string, info os.FileInfo, pathErr error) error {
		if pathErr != nil {
			return pathErr
		}
		if path == gc.rootPath {
			return nil
		}
		for _, substr := range gc.excludeSubstr {
			if strings.Contains(info.Name(), substr) {
				return skipDirOrNil(info)
			}
		}
		if force {
			removePath(path)
			return skipDirOrNil(info)
		}
		if info.ModTime().Before(expirationTime) {
			removePath(path)
		}
		return skipDirOrNil(info)
	})
	if err != nil {
		gc.logger.Error(err.Error())
	}
}