package httpapi import ( "html/template" "net/http" "strings" "time" ) type statusPageData struct { GeneratedAt string Overview screenStatusOverview } var statusPageTemplate = template.Must(template.New("status-page").Funcs(template.FuncMap{ "connectivityLabel": connectivityLabel, "statusClass": statusClass, "timestampLabel": timestampLabel, }).Parse(` Screen Status

Screen Status

A compact browser view of the latest screen reports from the current in-memory status overview. Offline and degraded screens stay at the top for quick diagnostics.

{{.Overview.Summary.Total}} screens
Updated {{.GeneratedAt}}
{{.Overview.Summary.Total}} Total known screens
{{.Overview.Summary.Offline}} Offline
{{.Overview.Summary.Degraded}} Degraded
{{.Overview.Summary.Online}} Online
{{.Overview.Summary.Stale}} Stale reports

Latest reports

{{if .Overview.Screens}}
{{range .Overview.Screens}} {{end}}
Screen Derived state Player status Server link Received Heartbeat
{{.ScreenID}}
{{if .MQTTBroker}}{{.MQTTBroker}}{{else if .ServerURL}}{{.ServerURL}}{{else}}No endpoint details{{end}}
{{.DerivedState}}
{{.Status}}
{{if .Stale}}Marked stale by server freshness check{{else}}Fresh within expected heartbeat window{{end}}
{{connectivityLabel .ServerConnectivity}} {{if .ServerURL}}{{.ServerURL}}{{end}}
{{timestampLabel .ReceivedAt}}
{{if .LastHeartbeatAt}}Heartbeat {{timestampLabel .LastHeartbeatAt}}{{end}}
{{if gt .HeartbeatEverySeconds 0}}{{.HeartbeatEverySeconds}}s{{else}}-{{end}} {{if .StartedAt}}Started {{timestampLabel .StartedAt}}{{end}}
{{else}}

No screen has reported status yet. Once a player posts to the existing status API, it will appear here automatically.

{{end}}
`)) func handleStatusPage(store playerStatusStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { overview, err := buildScreenStatusOverview(store, r.URL.Query()) if err != nil { writeOverviewQueryError(w, err) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusOK) data := statusPageData{ GeneratedAt: store.Now().Format(time.RFC3339), Overview: overview, } if err := statusPageTemplate.Execute(w, data); err != nil { http.Error(w, "failed to render status page", http.StatusInternalServerError) } } } func statusClass(value string) string { trimmed := strings.TrimSpace(value) if trimmed == "" { return "degraded" } return trimmed } func connectivityLabel(value string) string { trimmed := strings.TrimSpace(value) if trimmed == "" { return "unknown" } return trimmed } func timestampLabel(value string) string { trimmed := strings.TrimSpace(value) if trimmed == "" { return "-" } return trimmed }