From 4c3850e2e410acc273fc91757bdd2b413ad4193e Mon Sep 17 00:00:00 2001 From: Patrick Fairbank Date: Sun, 15 Mar 2020 18:11:26 -0700 Subject: [PATCH] Add manual triggering of game sounds to Field Testing page. --- static/css/cheesy-arena.css | 4 ++++ static/js/setup_field_testing.js | 5 ++++ templates/setup_field_testing.html | 12 ++++++++++ web/setup_field_testing.go | 37 +++++++++++++++++++++++++++--- web/setup_field_testing_test.go | 21 +++++++++++++++++ web/web.go | 4 ++++ 6 files changed, 80 insertions(+), 3 deletions(-) diff --git a/static/css/cheesy-arena.css b/static/css/cheesy-arena.css index e2971fc..72e8c63 100644 --- a/static/css/cheesy-arena.css +++ b/static/css/cheesy-arena.css @@ -101,3 +101,7 @@ td[data-plc-value="false"] { td[data-plc-value="true"] { color: #090; } +.btn-game-sound { + width: 110px; + text-align: left; +} diff --git a/static/js/setup_field_testing.js b/static/js/setup_field_testing.js index 62277e9..095bd15 100644 --- a/static/js/setup_field_testing.js +++ b/static/js/setup_field_testing.js @@ -5,6 +5,11 @@ var websocket; +// Sends a websocket message to play a given game sound on the audience display. +var playSound = function(sound) { + websocket.send("playSound", sound); +}; + // Handles a websocket message to update the PLC IO status. var handlePlcIoChange = function(data) { $.each(data.Inputs, function(index, input) { diff --git a/templates/setup_field_testing.html b/templates/setup_field_testing.html index 7321ebe..0469019 100644 --- a/templates/setup_field_testing.html +++ b/templates/setup_field_testing.html @@ -7,6 +7,18 @@ {{define "title"}}Field Testing{{end}} {{define "body"}}
+
+
+ Game Sounds + {{range $sound := .MatchSounds}} +

+ +

+ {{end}} +
+
PLC diff --git a/web/setup_field_testing.go b/web/setup_field_testing.go index af3e34d..f22e71c 100644 --- a/web/setup_field_testing.go +++ b/web/setup_field_testing.go @@ -6,8 +6,12 @@ package web import ( + "fmt" + "github.com/Team254/cheesy-arena/game" "github.com/Team254/cheesy-arena/model" "github.com/Team254/cheesy-arena/websocket" + "io" + "log" "net/http" ) @@ -25,10 +29,11 @@ func (web *Web) fieldTestingGetHandler(w http.ResponseWriter, r *http.Request) { plc := web.arena.Plc data := struct { *model.EventSettings + MatchSounds []*game.MatchSound InputNames []string RegisterNames []string CoilNames []string - }{web.arena.EventSettings, plc.GetInputNames(), plc.GetRegisterNames(), plc.GetCoilNames()} + }{web.arena.EventSettings, game.MatchSounds, plc.GetInputNames(), plc.GetRegisterNames(), plc.GetCoilNames()} err = template.ExecuteTemplate(w, "base", data) if err != nil { handleWebErr(w, err) @@ -49,6 +54,32 @@ func (web *Web) fieldTestingWebsocketHandler(w http.ResponseWriter, r *http.Requ } defer ws.Close() - // Subscribe the websocket to the notifiers whose messages will be passed on to the client. - ws.HandleNotifiers(web.arena.Plc.IoChangeNotifier) + // Subscribe the websocket to the notifiers whose messages will be passed on to the client, in a separate goroutine. + go ws.HandleNotifiers(web.arena.Plc.IoChangeNotifier) + + // Loop, waiting for commands and responding to them, until the client closes the connection. + for { + messageType, data, err := ws.Read() + if err != nil { + if err == io.EOF { + // Client has closed the connection; nothing to do here. + return + } + log.Println(err) + return + } + + switch messageType { + case "playSound": + sound, ok := data.(string) + if !ok { + ws.WriteError(fmt.Sprintf("Failed to parse '%s' message.", messageType)) + continue + } + web.arena.PlaySoundNotifier.NotifyWithMessage(sound) + default: + ws.WriteError(fmt.Sprintf("Invalid message type '%s'.", messageType)) + continue + } + } } diff --git a/web/setup_field_testing_test.go b/web/setup_field_testing_test.go index b5553c0..4f4b4b9 100644 --- a/web/setup_field_testing_test.go +++ b/web/setup_field_testing_test.go @@ -4,12 +4,23 @@ package web import ( + "github.com/Team254/cheesy-arena/game" "github.com/Team254/cheesy-arena/websocket" gorillawebsocket "github.com/gorilla/websocket" "github.com/stretchr/testify/assert" "testing" ) +func TestSetupFieldTesting(t *testing.T) { + web := setupTestWeb(t) + + recorder := web.getHttpResponse("/setup/field_testing") + assert.Equal(t, 200, recorder.Code) + for _, sound := range game.MatchSounds { + assert.Contains(t, recorder.Body.String(), sound.Name) + } +} + func TestSetupFieldTestingWebsocket(t *testing.T) { web := setupTestWeb(t) @@ -22,4 +33,14 @@ func TestSetupFieldTestingWebsocket(t *testing.T) { // Should get a few status updates right after connection. readWebsocketType(t, ws, "plcIoChange") + + // Also create a websocket to the audience display to check that it plays the requested game sound. + audienceConn, _, err := gorillawebsocket.DefaultDialer.Dial(wsUrl+"/displays/audience/websocket?displayId=1", nil) + assert.Nil(t, err) + defer audienceConn.Close() + audienceWs := websocket.NewTestWebsocket(audienceConn) + readWebsocketMultiple(t, audienceWs, 9) + + ws.Write("playSound", "resume") + assert.Equal(t, "resume", readWebsocketType(t, audienceWs, "playSound")) } diff --git a/web/web.go b/web/web.go index b609ad8..eb9982e 100644 --- a/web/web.go +++ b/web/web.go @@ -13,6 +13,7 @@ import ( "log" "net/http" "path/filepath" + "strings" "text/template" ) @@ -59,6 +60,9 @@ func NewWeb(arena *field.Arena) *Web { } return seq }, + "toUpper": func(str string) string { + return strings.ToUpper(str) + }, } return web