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
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}}
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}}
| Screen |
Derived state |
Player status |
Server link |
Received |
Heartbeat |
{{range .Overview.Screens}}
|
{{.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}}
|
{{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
}