diff --git a/fta_display.go b/fta_display.go index 653b337..3bd677e 100644 --- a/fta_display.go +++ b/fta_display.go @@ -6,6 +6,8 @@ package main import ( + "io" + "log" "net/http" "text/template" ) @@ -16,18 +18,109 @@ func FtaDisplayHandler(w http.ResponseWriter, r *http.Request) { return } + // Retrieve the next few matches to show which defenses they will require. + numUpcomingMatches := 3 + matches, err := db.GetMatchesByType(mainArena.currentMatch.Type) + if err != nil { + handleWebErr(w, err) + return + } + var upcomingMatches []Match + for _, match := range matches { + if match.Status != "complete" { + upcomingMatches = append(upcomingMatches, match) + if len(upcomingMatches) == numUpcomingMatches { + break + } + } + } + template := template.New("").Funcs(templateHelpers) - _, err := template.ParseFiles("templates/fta_display.html", "templates/base.html") + _, err = template.ParseFiles("templates/fta_display.html", "templates/base.html") if err != nil { handleWebErr(w, err) return } data := struct { *EventSettings - }{eventSettings} + UpcomingMatches []Match + DefenseNames map[string]string + }{eventSettings, upcomingMatches, defenseNames} err = template.ExecuteTemplate(w, "base", data) if err != nil { handleWebErr(w, err) return } } + +// The websocket endpoint for the FTA display client to receive status updates. +func FtaDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) { + // TODO(patrick): Enable authentication once Safari (for iPad) supports it over Websocket. + + websocket, err := NewWebsocket(w, r) + if err != nil { + handleWebErr(w, err) + return + } + defer websocket.Close() + + robotStatusListener := mainArena.robotStatusNotifier.Listen() + defer close(robotStatusListener) + defenseSelectionListener := mainArena.defenseSelectionNotifier.Listen() + defer close(defenseSelectionListener) + reloadDisplaysListener := mainArena.reloadDisplaysNotifier.Listen() + defer close(reloadDisplaysListener) + + // Send the various notifications immediately upon connection. + err = websocket.Write("status", mainArena) + if err != nil { + log.Printf("Websocket error: %s", err) + return + } + + // Spin off a goroutine to listen for notifications and pass them on through the websocket. + go func() { + for { + var messageType string + var message interface{} + select { + case _, ok := <-robotStatusListener: + if !ok { + return + } + messageType = "status" + message = mainArena + case _, ok := <-defenseSelectionListener: + if !ok { + return + } + messageType = "reload" + message = nil + case _, ok := <-reloadDisplaysListener: + if !ok { + return + } + messageType = "reload" + message = nil + } + err = websocket.Write(messageType, message) + if err != nil { + // The client has probably closed the connection; nothing to do here. + return + } + } + }() + + // Loop, waiting for commands and responding to them, until the client closes the connection. + for { + _, _, err := websocket.Read() + if err != nil { + if err == io.EOF { + // Client has closed the connection; nothing to do here. + return + } + log.Printf("Websocket error: %s", err) + return + } + } +} diff --git a/static/js/fta_display.js b/static/js/fta_display.js index 2f18537..4c2ea31 100644 --- a/static/js/fta_display.js +++ b/static/js/fta_display.js @@ -63,7 +63,7 @@ $(function() { $("[data-toggle=tooltip]").tooltip({"placement": "top"}); // Set up the websocket back to the server. - websocket = new CheesyWebsocket("/match_play/websocket", { + websocket = new CheesyWebsocket("/displays/fta/websocket", { status: function(event) { handleStatus(event.data); } }); }); diff --git a/templates/fta_display.html b/templates/fta_display.html index cf2dd09..3ac0e54 100644 --- a/templates/fta_display.html +++ b/templates/fta_display.html @@ -41,6 +41,44 @@
+
+
+ Upcoming Defenses + + + + + + + + + + + + + {{range $match := .UpcomingMatches}} + + + + + + + + + + + + + + + + + + {{end}} + +

Match

1

2

3

4

5

{{$match.DisplayName}}{{index $.DefenseNames $match.RedDefense1}}{{index $.DefenseNames $match.RedDefense2}}{{index $.DefenseNames $match.RedDefense3}}{{index $.DefenseNames $match.RedDefense4}}{{index $.DefenseNames $match.RedDefense5}}
 {{index $.DefenseNames $match.BlueDefense1}}{{index $.DefenseNames $match.BlueDefense2}}{{index $.DefenseNames $match.BlueDefense3}}{{index $.DefenseNames $match.BlueDefense4}}{{index $.DefenseNames $match.BlueDefense5}}
+
+
{{end}} {{define "script"}} diff --git a/web.go b/web.go index 09c24dd..c3ddf3d 100644 --- a/web.go +++ b/web.go @@ -212,6 +212,7 @@ func newHandler() http.Handler { router.HandleFunc("/displays/alliance_station", AllianceStationDisplayHandler).Methods("GET") router.HandleFunc("/displays/alliance_station/websocket", AllianceStationDisplayWebsocketHandler).Methods("GET") router.HandleFunc("/displays/fta", FtaDisplayHandler).Methods("GET") + router.HandleFunc("/displays/fta/websocket", FtaDisplayWebsocketHandler).Methods("GET") router.HandleFunc("/api/matches/{type}", MatchesApiHandler).Methods("GET") router.HandleFunc("/api/rankings", RankingsApiHandler).Methods("GET") router.HandleFunc("/", IndexHandler).Methods("GET")