checker-tls/checker/collect.go

70 lines
1.9 KiB
Go

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-")
}