package checker import ( "context" "fmt" "log" "strings" "sync" "time" sdk "git.happydns.org/checker-sdk-go/checker" ) // Collect reads the discovered endpoints auto-filled into // opts[OptionEndpoints], filters the TLS-relevant ones, probes them // concurrently (capped at MaxConcurrentProbes), and returns a TLSData payload // keyed by endpoint Id so consumers (via RelatedObservation.EndpointID) can // pick their own probe from the shared observation. func (p *tlsProvider) Collect(ctx context.Context, opts sdk.CheckerOptions) (any, error) { eps, ok := sdk.GetOption[[]endpointInput](opts, OptionEndpoints) if !ok { return nil, fmt.Errorf("no endpoints in options: did the host wire AutoFillDiscoveredEndpoints?") } timeoutMs := sdk.GetIntOption(opts, OptionProbeTimeoutMs, DefaultProbeTimeoutMs) if timeoutMs <= 0 { timeoutMs = DefaultProbeTimeoutMs } timeout := time.Duration(timeoutMs) * time.Millisecond var filtered []endpointInput for _, ep := range eps { if !isTLSRelevant(ep.Type) { continue } filtered = append(filtered, ep) } if len(filtered) == 0 { return nil, fmt.Errorf("no TLS-relevant endpoints to probe (received %d)", len(eps)) } probes := make(map[string]TLSProbe, len(filtered)) var mu sync.Mutex var wg sync.WaitGroup sem := make(chan struct{}, MaxConcurrentProbes) for _, ep := range filtered { wg.Add(1) sem <- struct{}{} go func() { defer wg.Done() defer func() { <-sem }() pr := probe(ctx, ep, timeout) log.Printf("checker-tls: %s %s:%d → tls=%s issues=%d elapsed=%dms err=%q", ep.Type, pr.Host, pr.Port, pr.TLSVersion, len(pr.Issues), pr.ElapsedMS, pr.Error) mu.Lock() probes[ep.Id] = pr mu.Unlock() }() } wg.Wait() return &TLSData{ Probes: probes, CollectedAt: time.Now(), }, nil } func isTLSRelevant(t string) bool { return t == "tls" || strings.HasPrefix(t, "starttls-") }