// Package watcher provides the main monitoring orchestrator and scheduler. package watcher import ( "context" "log/slog" "go.uber.org/fx" "sneak.berlin/go/dnswatcher/internal/config" "sneak.berlin/go/dnswatcher/internal/logger" "sneak.berlin/go/dnswatcher/internal/notify" "sneak.berlin/go/dnswatcher/internal/portcheck" "sneak.berlin/go/dnswatcher/internal/resolver" "sneak.berlin/go/dnswatcher/internal/state" "sneak.berlin/go/dnswatcher/internal/tlscheck" ) // Params contains dependencies for Watcher. type Params struct { fx.In Logger *logger.Logger Config *config.Config State *state.State Resolver *resolver.Resolver PortCheck *portcheck.Checker TLSCheck *tlscheck.Checker Notify *notify.Service } // Watcher orchestrates all monitoring checks on a schedule. type Watcher struct { log *slog.Logger config *config.Config state *state.State resolver *resolver.Resolver portCheck *portcheck.Checker tlsCheck *tlscheck.Checker notify *notify.Service cancel context.CancelFunc } // New creates a new Watcher instance. func New( lifecycle fx.Lifecycle, params Params, ) (*Watcher, error) { watcher := &Watcher{ log: params.Logger.Get(), config: params.Config, state: params.State, resolver: params.Resolver, portCheck: params.PortCheck, tlsCheck: params.TLSCheck, notify: params.Notify, } lifecycle.Append(fx.Hook{ OnStart: func(startCtx context.Context) error { ctx, cancel := context.WithCancel(startCtx) watcher.cancel = cancel go watcher.Run(ctx) return nil }, OnStop: func(_ context.Context) error { if watcher.cancel != nil { watcher.cancel() } return nil }, }) return watcher, nil } // Run starts the monitoring loop. func (w *Watcher) Run(ctx context.Context) { w.log.Info( "watcher starting", "domains", len(w.config.Domains), "hostnames", len(w.config.Hostnames), "dnsInterval", w.config.DNSInterval, "tlsInterval", w.config.TLSInterval, ) // Stub: wait for context cancellation. // Implementation will add initial check + periodic scheduling. <-ctx.Done() w.log.Info("watcher stopped") }