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 @@
+
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}} | +