package watcher import ( "context" "errors" "fmt" "log/slog" "time" "gitoa.ru/go-4devs/config" ) var ( _ config.Provider = (*Provider)(nil) _ config.WatchProvider = (*Provider)(nil) ) func New(duration time.Duration, provider config.Provider, opts ...Option) *Provider { prov := &Provider{ Provider: provider, duration: duration, logger: slog.ErrorContext, } for _, opt := range opts { opt(prov) } return prov } func WithLogger(l func(context.Context, string, ...any)) Option { return func(p *Provider) { p.logger = l } } type Option func(*Provider) type Provider struct { config.Provider duration time.Duration logger func(context.Context, string, ...any) } func (p *Provider) Watch(ctx context.Context, callback config.WatchCallback, key ...string) error { old, err := p.Provider.Value(ctx, key...) if err != nil { return fmt.Errorf("failed watch variable: %w", err) } go func(oldVar config.Value) { ticker := time.NewTicker(p.duration) defer func() { ticker.Stop() }() for { select { case <-ticker.C: newVar, err := p.Provider.Value(ctx, key...) if err != nil { p.logger(ctx, "get value%v:%v", key, err.Error()) } else if !newVar.IsEquals(oldVar) { if err := callback(ctx, oldVar, newVar); err != nil { if errors.Is(err, config.ErrStopWatch) { return } p.logger(ctx, "callback %v:%v", key, err) } oldVar = newVar } case <-ctx.Done(): return } } }(old) return nil }