package checker import ( "encoding/json" "fmt" "html/template" "strings" sdk "git.happydns.org/checker-sdk-go/checker" ) type tmplSubTest struct { Name string StatusCSS string StatusText string DurationMs int64 Detail string Error string Fix string } type tmplEndpoint struct { URI string Transport string Source string Open bool BadgeText string BadgeCSS string SubTests []tmplSubTest } type tmplData struct { Zone string Mode string OverallText string OverallCSS string HeadlineFix string HeadlineDetail string GlobalError string Endpoints []tmplEndpoint } var stunturnTemplate = template.Must(template.New("stunturn").Parse(` STUN/TURN Report

STUN/TURN check

{{.OverallText}}
{{if .Zone}}Zone: {{.Zone}} · {{end}} Mode: {{.Mode}} · {{len .Endpoints}} endpoint(s) probed
{{if .HeadlineFix}}
How to fix: {{.HeadlineFix}} {{if .HeadlineDetail}}
{{.HeadlineDetail}}
{{end}}
{{end}}
{{if .GlobalError}}
Discovery failed: {{.GlobalError}}
{{end}} {{range .Endpoints}} {{.URI}} {{.BadgeText}}

Transport: {{.Transport}} · Source: {{.Source}}

{{range .SubTests}} {{end}}
TestStatusDurationDetail
{{.Name}} {{.StatusText}} {{if .DurationMs}}{{.DurationMs}} ms{{end}} {{if .Detail}}{{.Detail}}{{end}} {{if .Error}}
⚠ {{.Error}}
{{end}} {{if .Fix}}
Fix: {{.Fix}}
{{end}}
{{end}} `)) // GetHTMLReport implements sdk.CheckerHTMLReporter. func (p *stunTurnProvider) GetHTMLReport(ctx sdk.ReportContext) (string, error) { var d StunTurnData if err := json.Unmarshal(ctx.Data(), &d); err != nil { return "", fmt.Errorf("unmarshal stun/turn report: %w", err) } worst := SubTestOK var headlineFix, headlineDetail string td := tmplData{ Zone: d.Zone, Mode: d.Mode, GlobalError: d.GlobalError, } for _, ep := range d.Endpoints { te := tmplEndpoint{ URI: ep.Endpoint.URI, Transport: string(ep.Endpoint.Transport), Source: ep.Endpoint.Source, } w := ep.Worst() if statusRank(w) > statusRank(worst) { worst = w } te.BadgeCSS, te.BadgeText = badge(w) te.Open = w != SubTestOK && w != SubTestSkipped && w != SubTestInfo if te.Open && headlineFix == "" { if f := ep.FirstFailure(); f != nil && f.Fix != "" { headlineFix = f.Fix if f.Detail != "" { headlineDetail = fmt.Sprintf("[%s] %s: %s", ep.Endpoint.URI, f.Name, f.Detail) } else if f.Error != "" { headlineDetail = fmt.Sprintf("[%s] %s: %s", ep.Endpoint.URI, f.Name, f.Error) } } } for _, st := range ep.SubTests { css, txt := badge(st.Status) te.SubTests = append(te.SubTests, tmplSubTest{ Name: st.Name, StatusCSS: css, StatusText: txt, DurationMs: st.DurationMs, Detail: st.Detail, Error: st.Error, Fix: st.Fix, }) } td.Endpoints = append(td.Endpoints, te) } td.OverallCSS, td.OverallText = badge(worst) td.HeadlineFix = headlineFix td.HeadlineDetail = headlineDetail var buf strings.Builder if err := stunturnTemplate.Execute(&buf, td); err != nil { return "", fmt.Errorf("render stun/turn report: %w", err) } return buf.String(), nil } func badge(s SubTestStatus) (cssClass, label string) { switch s { case SubTestOK: return "ok", "OK" case SubTestInfo: return "info", "INFO" case SubTestWarn: return "warn", "WARN" case SubTestCrit: return "crit", "CRIT" case SubTestError: return "error", "ERROR" case SubTestSkipped: return "skipped", "SKIPPED" } return "info", string(s) }