feat(api): display_state im Player-Status-Report persistieren

This commit is contained in:
Jesko Anschütz 2026-03-26 23:05:25 +01:00
parent fbcda1e2b8
commit f985a99ea1
2 changed files with 23 additions and 13 deletions

View file

@ -2,12 +2,15 @@ package httpapi
import (
"errors"
"log/slog"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"
storePackage "git.az-it.net/az/morz-infoboard/server/backend/internal/store"
)
type screenStatusSummary struct {
@ -47,6 +50,7 @@ type playerStatusRequest struct {
HeartbeatEverySeconds int `json:"heartbeat_every_seconds"`
StartedAt string `json:"started_at"`
LastHeartbeatAt string `json:"last_heartbeat_at"`
DisplayState string `json:"display_state,omitempty"`
}
// playerStatusMQTTConfig is the MQTT configuration returned to agents in the
@ -63,7 +67,7 @@ type playerStatusResponse struct {
MQTT *playerStatusMQTTConfig `json:"mqtt,omitempty"`
}
func handlePlayerStatus(store playerStatusStore, mqttBroker, mqttUsername, mqttPassword string) http.HandlerFunc {
func handlePlayerStatus(store playerStatusStore, screenStore *storePackage.ScreenStore, mqttBroker, mqttUsername, mqttPassword string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var request playerStatusRequest
if err := decodeJSON(r, &request); err != nil {
@ -130,6 +134,12 @@ func handlePlayerStatus(store playerStatusStore, mqttBroker, mqttUsername, mqttP
LastHeartbeatAt: request.LastHeartbeatAt,
})
if request.DisplayState != "" && screenStore != nil {
if err := screenStore.UpsertDisplayState(r.Context(), request.ScreenID, request.DisplayState); err != nil {
slog.Error("upsert display state", "screen_id", request.ScreenID, "err", err)
}
}
resp := playerStatusResponse{Status: "accepted"}
if mqttBroker != "" {
resp.MQTT = &playerStatusMQTTConfig{

View file

@ -26,7 +26,7 @@ func TestHandlePlayerStatusAccepted(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(store, "", "", "")(w, req)
handlePlayerStatus(store, nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusOK; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -66,7 +66,7 @@ func TestHandlePlayerStatusRejectsInvalidJSON(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewBufferString("{"))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -83,7 +83,7 @@ func TestHandlePlayerStatusRejectsMissingScreenID(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -102,7 +102,7 @@ func TestHandlePlayerStatusStoresNormalizedScreenID(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(store, "", "", "")(w, req)
handlePlayerStatus(store, nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusOK; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -122,7 +122,7 @@ func TestHandlePlayerStatusRejectsMissingTimestamp(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -138,7 +138,7 @@ func TestHandlePlayerStatusRejectsMissingStatus(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -155,7 +155,7 @@ func TestHandlePlayerStatusRejectsUnknownStatus(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -173,7 +173,7 @@ func TestHandlePlayerStatusRejectsUnknownServerConnectivity(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -191,7 +191,7 @@ func TestHandlePlayerStatusRejectsNonPositiveHeartbeatInterval(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -208,7 +208,7 @@ func TestHandlePlayerStatusRejectsMalformedTimestamps(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -226,7 +226,7 @@ func TestHandlePlayerStatusRejectsMalformedStartedAt(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)
@ -244,7 +244,7 @@ func TestHandlePlayerStatusRejectsMalformedLastHeartbeatAt(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/v1/player/status", bytes.NewReader(body))
w := httptest.NewRecorder()
handlePlayerStatus(newInMemoryPlayerStatusStore(), "", "", "")(w, req)
handlePlayerStatus(newInMemoryPlayerStatusStore(), nil, "", "", "")(w, req)
if got, want := w.Code, http.StatusBadRequest; got != want {
t.Fatalf("status = %d, want %d", got, want)