Files
ExploreDNS/internal/output/formatter.go
T
c96d18859f fix: address code review issues on PR #10 (HAN-384)
- runner.go: store fingerprints in local var, call formatter.SetFingerprints()
  instead of mutating caller's *Config; removes Fingerprints field from Config
- fingerprint.go: use singleflight.Group in Query to coalesce concurrent
  probes for the same IP, eliminating the double-probe race
- output layer: add SetFingerprints(map[string]string) to Formatter interface;
  textFormatter and jsonFormatter each hold their own fingerprints field
- formatter_test.go: add TestTextFormatterWriteSummaryShowsVersions and
  TestJSONFormatterWriteSummaryShowsVersions verifying version output

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-06-08 02:59:38 +10:00

97 lines
2.2 KiB
Go

package output
import (
"fmt"
"io"
"os"
"github.com/hits/ExploreDNS/internal/traverse"
)
type Format int
const (
FormatText Format = iota
FormatJSON
)
type Config struct {
Format Format
Domain string
QueryType string
ShowProgress bool
ShowResolves bool
ShowServers bool
ShowVersions bool
ShowAllStats bool
ShowResults bool
ShowSummaryResults bool
Verbose bool
Quiet bool
Color bool
Debug int
}
func DefaultConfig() *Config {
return &Config{
Format: FormatText,
ShowProgress: true,
ShowResolves: true,
ShowServers: true,
ShowVersions: true,
ShowAllStats: true,
ShowResults: true,
ShowSummaryResults: true,
Color: os.Getenv("NO_COLOR") == "",
}
}
type Formatter interface {
WriteProgress(event traverse.TraversalEvent) error
WriteResolve(event traverse.TraversalEvent) error
WriteResult(result traverse.TraversalResult) error
WriteSummary(results []traverse.TraversalResult) error
Flush() error
// SetFingerprints supplies server-version data to the formatter.
// Call before WriteSummary when ShowVersions is true.
SetFingerprints(fps map[string]string)
}
func NewFormatter(cfg *Config, w io.Writer) Formatter {
if cfg == nil {
cfg = DefaultConfig()
}
if w == nil {
w = os.Stdout
}
if cfg.Format == FormatJSON {
return newJSONFormatter(cfg, w)
}
return newTextFormatter(cfg, w)
}
func AttachHooks(cfg *Config, formatter Formatter) *traverse.TraverserHooks {
if cfg == nil || formatter == nil {
return nil
}
logErr := func(context string, err error) {
if err != nil && cfg.Debug > 0 {
fmt.Fprintf(os.Stderr, "Debug: formatter %s: %v\n", context, err)
}
}
return &traverse.TraverserHooks{
OnEvent: func(event traverse.TraversalEvent) {
switch {
case event.IsResolve && cfg.ShowResolves:
logErr("WriteResolve", formatter.WriteResolve(event))
case !event.IsResolve && cfg.ShowProgress:
logErr("WriteProgress", formatter.WriteProgress(event))
}
if event.Stage == traverse.EventComplete && cfg.ShowAllStats {
logErr("WriteResult", formatter.WriteResult(event.Result))
}
},
}
}