mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 21:56:50 -04:00
Refactor display registry to not broadcast all config changes to all displays.
This commit is contained in:
@@ -33,11 +33,6 @@ type ArenaNotifiers struct {
|
||||
ControlPanelColorNotifier *websocket.Notifier
|
||||
}
|
||||
|
||||
type DisplayConfigurationMessage struct {
|
||||
Displays map[string]*Display
|
||||
DisplayUrls map[string]string
|
||||
}
|
||||
|
||||
type MatchTimeMessage struct {
|
||||
MatchState
|
||||
MatchTimeSec int
|
||||
@@ -107,16 +102,14 @@ func (arena *Arena) generateAudienceDisplayModeMessage() interface{} {
|
||||
}
|
||||
|
||||
func (arena *Arena) generateDisplayConfigurationMessage() interface{} {
|
||||
// Notify() for this notifier must always called from a method that has a lock on the display mutex.
|
||||
// Make a copy of the map to avoid potential data races; otherwise the same map would get iterated through as it is
|
||||
// serialized to JSON.
|
||||
displaysCopy := make(map[string]*Display)
|
||||
displayUrls := make(map[string]string)
|
||||
// serialized to JSON, outside the mutex lock.
|
||||
displaysCopy := make(map[string]Display)
|
||||
for displayId, display := range arena.Displays {
|
||||
displaysCopy[displayId] = display
|
||||
displayUrls[displayId] = display.ToUrl()
|
||||
displaysCopy[displayId] = *display
|
||||
}
|
||||
|
||||
return &DisplayConfigurationMessage{displaysCopy, displayUrls}
|
||||
return displaysCopy
|
||||
}
|
||||
|
||||
func (arena *Arena) generateEventStatusMessage() interface{} {
|
||||
|
||||
106
field/display.go
106
field/display.go
@@ -7,6 +7,7 @@ package field
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/websocket"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
@@ -60,64 +61,69 @@ var displayTypePaths = map[DisplayType]string{
|
||||
var displayRegistryMutex sync.Mutex
|
||||
|
||||
type Display struct {
|
||||
Id string
|
||||
Nickname string
|
||||
Type DisplayType
|
||||
Configuration map[string]string
|
||||
IpAddress string
|
||||
ConnectionCount int
|
||||
lastConnectedTime time.Time
|
||||
DisplayConfiguration DisplayConfiguration
|
||||
IpAddress string
|
||||
ConnectionCount int
|
||||
Notifier *websocket.Notifier
|
||||
lastConnectedTime time.Time
|
||||
}
|
||||
|
||||
type DisplayConfiguration struct {
|
||||
Id string
|
||||
Nickname string
|
||||
Type DisplayType
|
||||
Configuration map[string]string
|
||||
}
|
||||
|
||||
// Parses the given display URL path and query string to extract the configuration.
|
||||
func DisplayFromUrl(path string, query map[string][]string) (*Display, error) {
|
||||
func DisplayFromUrl(path string, query map[string][]string) (*DisplayConfiguration, error) {
|
||||
if _, ok := query["displayId"]; !ok {
|
||||
return nil, fmt.Errorf("Display ID not present in request.")
|
||||
}
|
||||
|
||||
var display Display
|
||||
display.Id = query["displayId"][0]
|
||||
var displayConfig DisplayConfiguration
|
||||
displayConfig.Id = query["displayId"][0]
|
||||
if nickname, ok := query["nickname"]; ok {
|
||||
display.Nickname, _ = url.QueryUnescape(nickname[0])
|
||||
displayConfig.Nickname, _ = url.QueryUnescape(nickname[0])
|
||||
}
|
||||
|
||||
// Determine type from the websocket connection URL. This way of doing it isn't super efficient, but it's not really
|
||||
// a concern since it should happen relatively infrequently.
|
||||
for displayType, displayPath := range displayTypePaths {
|
||||
if path == displayPath+"/websocket" {
|
||||
display.Type = displayType
|
||||
displayConfig.Type = displayType
|
||||
break
|
||||
}
|
||||
}
|
||||
if display.Type == InvalidDisplay {
|
||||
if displayConfig.Type == InvalidDisplay {
|
||||
return nil, fmt.Errorf("Could not determine display type from path %s.", path)
|
||||
}
|
||||
|
||||
// Put any remaining query parameters into the per-type configuration map.
|
||||
display.Configuration = make(map[string]string)
|
||||
displayConfig.Configuration = make(map[string]string)
|
||||
for key, value := range query {
|
||||
if key != "displayId" && key != "nickname" {
|
||||
display.Configuration[key], _ = url.QueryUnescape(value[0])
|
||||
displayConfig.Configuration[key], _ = url.QueryUnescape(value[0])
|
||||
}
|
||||
}
|
||||
|
||||
return &display, nil
|
||||
return &displayConfig, nil
|
||||
}
|
||||
|
||||
// Returns the URL string for the given display that includes all of its configuration parameters.
|
||||
func (display *Display) ToUrl() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString(displayTypePaths[display.Type])
|
||||
builder.WriteString(displayTypePaths[display.DisplayConfiguration.Type])
|
||||
builder.WriteString("?displayId=")
|
||||
builder.WriteString(url.QueryEscape(display.Id))
|
||||
if display.Nickname != "" {
|
||||
builder.WriteString(url.QueryEscape(display.DisplayConfiguration.Id))
|
||||
if display.DisplayConfiguration.Nickname != "" {
|
||||
builder.WriteString("&nickname=")
|
||||
builder.WriteString(url.QueryEscape(display.Nickname))
|
||||
builder.WriteString(url.QueryEscape(display.DisplayConfiguration.Nickname))
|
||||
}
|
||||
|
||||
// Sort the keys so that the URL generated is deterministic.
|
||||
var keys []string
|
||||
for key := range display.Configuration {
|
||||
for key := range display.DisplayConfiguration.Configuration {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
@@ -125,11 +131,15 @@ func (display *Display) ToUrl() string {
|
||||
builder.WriteString("&")
|
||||
builder.WriteString(url.QueryEscape(key))
|
||||
builder.WriteString("=")
|
||||
builder.WriteString(url.QueryEscape(display.Configuration[key]))
|
||||
builder.WriteString(url.QueryEscape(display.DisplayConfiguration.Configuration[key]))
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func (display *Display) generateDisplayConfigurationMessage() interface{} {
|
||||
return display.ToUrl()
|
||||
}
|
||||
|
||||
// Returns an unused ID that can be used for a new display.
|
||||
func (arena *Arena) NextDisplayId() string {
|
||||
displayRegistryMutex.Lock()
|
||||
@@ -146,55 +156,63 @@ func (arena *Arena) NextDisplayId() string {
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the given display to the arena registry and triggers a notification.
|
||||
func (arena *Arena) RegisterDisplay(display *Display) {
|
||||
// Creates or gets the given display in the arena registry and triggers a notification.
|
||||
func (arena *Arena) RegisterDisplay(displayConfig *DisplayConfiguration, ipAddress string) *Display {
|
||||
displayRegistryMutex.Lock()
|
||||
defer displayRegistryMutex.Unlock()
|
||||
|
||||
existingDisplay, ok := arena.Displays[display.Id]
|
||||
if ok && display.Type == PlaceholderDisplay {
|
||||
display, ok := arena.Displays[displayConfig.Id]
|
||||
if ok && displayConfig.Type == PlaceholderDisplay {
|
||||
// Don't rewrite the registered configuration if the new one is a placeholder -- if it is reconnecting after a
|
||||
// restart, it should adopt the existing configuration.
|
||||
arena.Displays[display.Id].ConnectionCount++
|
||||
arena.Displays[displayConfig.Id].ConnectionCount++
|
||||
arena.Displays[displayConfig.Id].IpAddress = ipAddress
|
||||
} else {
|
||||
if ok {
|
||||
display.ConnectionCount = existingDisplay.ConnectionCount + 1
|
||||
} else {
|
||||
display.ConnectionCount = 1
|
||||
if !ok {
|
||||
display = new(Display)
|
||||
display.Notifier = websocket.NewNotifier("displayConfiguration",
|
||||
display.generateDisplayConfigurationMessage)
|
||||
arena.Displays[displayConfig.Id] = display
|
||||
}
|
||||
display.DisplayConfiguration = *displayConfig
|
||||
display.IpAddress = ipAddress
|
||||
display.ConnectionCount += 1
|
||||
display.lastConnectedTime = time.Now()
|
||||
arena.Displays[display.Id] = display
|
||||
display.Notifier.Notify()
|
||||
}
|
||||
arena.DisplayConfigurationNotifier.Notify()
|
||||
|
||||
return display
|
||||
}
|
||||
|
||||
// Updates the given display in the arena registry. Triggers a notification if the display configuration changed.
|
||||
func (arena *Arena) UpdateDisplay(display *Display) error {
|
||||
func (arena *Arena) UpdateDisplay(displayConfig DisplayConfiguration) error {
|
||||
displayRegistryMutex.Lock()
|
||||
defer displayRegistryMutex.Unlock()
|
||||
|
||||
existingDisplay, ok := arena.Displays[display.Id]
|
||||
display, ok := arena.Displays[displayConfig.Id]
|
||||
if !ok {
|
||||
return fmt.Errorf("Display %s doesn't exist.", display.Id)
|
||||
return fmt.Errorf("Display %s doesn't exist.", displayConfig.Id)
|
||||
}
|
||||
display.ConnectionCount = existingDisplay.ConnectionCount
|
||||
if !reflect.DeepEqual(existingDisplay, display) {
|
||||
arena.Displays[display.Id] = display
|
||||
if !reflect.DeepEqual(displayConfig, display.DisplayConfiguration) {
|
||||
display.DisplayConfiguration = displayConfig
|
||||
display.Notifier.Notify()
|
||||
arena.DisplayConfigurationNotifier.Notify()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marks the given display as having disconnected in the arena registry and triggers a notification.
|
||||
func (arena *Arena) MarkDisplayDisconnected(display *Display) {
|
||||
func (arena *Arena) MarkDisplayDisconnected(displayId string) {
|
||||
displayRegistryMutex.Lock()
|
||||
defer displayRegistryMutex.Unlock()
|
||||
|
||||
if existingDisplay, ok := arena.Displays[display.Id]; ok {
|
||||
if existingDisplay.Type == PlaceholderDisplay && existingDisplay.Nickname == "" &&
|
||||
len(existingDisplay.Configuration) == 0 {
|
||||
if existingDisplay, ok := arena.Displays[displayId]; ok {
|
||||
if existingDisplay.DisplayConfiguration.Type == PlaceholderDisplay &&
|
||||
existingDisplay.DisplayConfiguration.Nickname == "" &&
|
||||
len(existingDisplay.DisplayConfiguration.Configuration) == 0 {
|
||||
// If the display is an unconfigured placeholder, just remove it entirely to prevent clutter.
|
||||
delete(arena.Displays, existingDisplay.Id)
|
||||
delete(arena.Displays, existingDisplay.DisplayConfiguration.Id)
|
||||
} else {
|
||||
existingDisplay.ConnectionCount -= 1
|
||||
}
|
||||
@@ -210,7 +228,7 @@ func (arena *Arena) purgeDisconnectedDisplays() {
|
||||
|
||||
deleted := false
|
||||
for id, display := range arena.Displays {
|
||||
if display.ConnectionCount == 0 && display.Nickname == "" &&
|
||||
if display.ConnectionCount == 0 && display.DisplayConfiguration.Nickname == "" &&
|
||||
time.Now().Sub(display.lastConnectedTime).Minutes() >= displayPurgeTtlMin {
|
||||
delete(arena.Displays, id)
|
||||
deleted = true
|
||||
|
||||
@@ -52,8 +52,8 @@ func TestDisplayFromUrl(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDisplayToUrl(t *testing.T) {
|
||||
display := &Display{Id: "254", Nickname: "Test Nickname", Type: PitDisplay,
|
||||
Configuration: map[string]string{"f": "1", "z": "#fff", "a": "3", "c": "4"}}
|
||||
display := &Display{DisplayConfiguration: DisplayConfiguration{Id: "254", Nickname: "Test Nickname",
|
||||
Type: PitDisplay, Configuration: map[string]string{"f": "1", "z": "#fff", "a": "3", "c": "4"}}}
|
||||
assert.Equal(t, "/displays/pit?displayId=254&nickname=Test+Nickname&a=3&c=4&f=1&z=%23fff", display.ToUrl())
|
||||
}
|
||||
|
||||
@@ -62,51 +62,57 @@ func TestNextDisplayId(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "100", arena.NextDisplayId())
|
||||
|
||||
display := &Display{Id: "100"}
|
||||
arena.RegisterDisplay(display)
|
||||
displayConfig := &DisplayConfiguration{Id: "100"}
|
||||
arena.RegisterDisplay(displayConfig, "")
|
||||
assert.Equal(t, "101", arena.NextDisplayId())
|
||||
}
|
||||
|
||||
func TestDisplayRegisterUnregister(t *testing.T) {
|
||||
arena := setupTestArena(t)
|
||||
|
||||
display := &Display{Id: "254", Nickname: "Placeholder", Type: PlaceholderDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(display)
|
||||
displayConfig := &DisplayConfiguration{Id: "254", Nickname: "Placeholder", Type: PlaceholderDisplay,
|
||||
Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(displayConfig, "1.2.3.4")
|
||||
if assert.Contains(t, arena.Displays, "254") {
|
||||
assert.Equal(t, "Placeholder", arena.Displays["254"].Nickname)
|
||||
assert.Equal(t, PlaceholderDisplay, arena.Displays["254"].Type)
|
||||
assert.Equal(t, "Placeholder", arena.Displays["254"].DisplayConfiguration.Nickname)
|
||||
assert.Equal(t, PlaceholderDisplay, arena.Displays["254"].DisplayConfiguration.Type)
|
||||
assert.Equal(t, 1, arena.Displays["254"].ConnectionCount)
|
||||
assert.Equal(t, "1.2.3.4", arena.Displays["254"].IpAddress)
|
||||
}
|
||||
notifier := arena.Displays["254"].Notifier
|
||||
|
||||
// Register a second instance of the same display.
|
||||
display2 := &Display{Id: "254", Nickname: "Pit", Type: PitDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(display2)
|
||||
displayConfig2 := &DisplayConfiguration{Id: "254", Nickname: "Pit", Type: PitDisplay,
|
||||
Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(displayConfig2, "2.3.4.5")
|
||||
if assert.Contains(t, arena.Displays, "254") {
|
||||
assert.Equal(t, "Pit", arena.Displays["254"].Nickname)
|
||||
assert.Equal(t, PitDisplay, arena.Displays["254"].Type)
|
||||
assert.Equal(t, "Pit", arena.Displays["254"].DisplayConfiguration.Nickname)
|
||||
assert.Equal(t, PitDisplay, arena.Displays["254"].DisplayConfiguration.Type)
|
||||
assert.Equal(t, 2, arena.Displays["254"].ConnectionCount)
|
||||
assert.Equal(t, "2.3.4.5", arena.Displays["254"].IpAddress)
|
||||
assert.Same(t, notifier, arena.Displays["254"].Notifier)
|
||||
}
|
||||
|
||||
// Register a second display.
|
||||
display3 := &Display{Id: "148", Type: FieldMonitorDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(display3)
|
||||
displayConfig3 := &DisplayConfiguration{Id: "148", Type: FieldMonitorDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(displayConfig3, "3.4.5.6")
|
||||
if assert.Contains(t, arena.Displays, "148") {
|
||||
assert.Equal(t, 1, arena.Displays["148"].ConnectionCount)
|
||||
}
|
||||
|
||||
// Update the first display.
|
||||
display4 := &Display{Id: "254", Nickname: "Alliance", Type: AllianceStationDisplay,
|
||||
displayConfig4 := DisplayConfiguration{Id: "254", Nickname: "Alliance", Type: AllianceStationDisplay,
|
||||
Configuration: map[string]string{"station": "B2"}}
|
||||
arena.UpdateDisplay(display4)
|
||||
arena.UpdateDisplay(displayConfig4)
|
||||
if assert.Contains(t, arena.Displays, "254") {
|
||||
assert.Equal(t, "Alliance", arena.Displays["254"].Nickname)
|
||||
assert.Equal(t, AllianceStationDisplay, arena.Displays["254"].Type)
|
||||
assert.Equal(t, "Alliance", arena.Displays["254"].DisplayConfiguration.Nickname)
|
||||
assert.Equal(t, AllianceStationDisplay, arena.Displays["254"].DisplayConfiguration.Type)
|
||||
assert.Equal(t, 2, arena.Displays["254"].ConnectionCount)
|
||||
}
|
||||
|
||||
// Disconnect both displays.
|
||||
arena.MarkDisplayDisconnected(display)
|
||||
arena.MarkDisplayDisconnected(display3)
|
||||
arena.MarkDisplayDisconnected(displayConfig.Id)
|
||||
arena.MarkDisplayDisconnected(displayConfig3.Id)
|
||||
if assert.Contains(t, arena.Displays, "148") {
|
||||
assert.Equal(t, 0, arena.Displays["148"].ConnectionCount)
|
||||
}
|
||||
@@ -118,8 +124,8 @@ func TestDisplayRegisterUnregister(t *testing.T) {
|
||||
func TestDisplayUpdateError(t *testing.T) {
|
||||
arena := setupTestArena(t)
|
||||
|
||||
display := &Display{Id: "254", Configuration: map[string]string{}}
|
||||
err := arena.UpdateDisplay(display)
|
||||
displayConfig := DisplayConfiguration{Id: "254", Configuration: map[string]string{}}
|
||||
err := arena.UpdateDisplay(displayConfig)
|
||||
if assert.NotNil(t, err) {
|
||||
assert.Contains(t, err.Error(), "doesn't exist")
|
||||
}
|
||||
@@ -129,41 +135,41 @@ func TestDisplayPurge(t *testing.T) {
|
||||
arena := setupTestArena(t)
|
||||
|
||||
// Unnamed placeholder gets immediately purged upon disconnection.
|
||||
display := &Display{Id: "254", Type: PlaceholderDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(display)
|
||||
displayConfig := &DisplayConfiguration{Id: "254", Type: PlaceholderDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(displayConfig, "1.2.3.4")
|
||||
assert.Contains(t, arena.Displays, "254")
|
||||
arena.MarkDisplayDisconnected(display)
|
||||
arena.MarkDisplayDisconnected(displayConfig.Id)
|
||||
assert.NotContains(t, arena.Displays, "254")
|
||||
|
||||
// Named placeholder does not get immediately purged upon disconnection.
|
||||
display.Nickname = "Bob"
|
||||
arena.RegisterDisplay(display)
|
||||
displayConfig.Nickname = "Bob"
|
||||
arena.RegisterDisplay(displayConfig, "1.2.3.4")
|
||||
assert.Contains(t, arena.Displays, "254")
|
||||
arena.MarkDisplayDisconnected(display)
|
||||
arena.MarkDisplayDisconnected(displayConfig.Id)
|
||||
assert.Contains(t, arena.Displays, "254")
|
||||
|
||||
// Unnamed configured display does not get immediately purged upon disconnection.
|
||||
display = &Display{Id: "1114", Type: FieldMonitorDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(display)
|
||||
// Unnamed configured displayConfig does not get immediately purged upon disconnection.
|
||||
displayConfig = &DisplayConfiguration{Id: "1114", Type: FieldMonitorDisplay, Configuration: map[string]string{}}
|
||||
arena.RegisterDisplay(displayConfig, "1.2.3.4")
|
||||
assert.Contains(t, arena.Displays, "1114")
|
||||
arena.MarkDisplayDisconnected(display)
|
||||
arena.MarkDisplayDisconnected(displayConfig.Id)
|
||||
assert.Contains(t, arena.Displays, "1114")
|
||||
arena.purgeDisconnectedDisplays()
|
||||
assert.Contains(t, arena.Displays, "1114")
|
||||
|
||||
// Unnamed configured display gets purged by periodic task.
|
||||
arena.RegisterDisplay(display)
|
||||
// Unnamed configured displayConfig gets purged by periodic task.
|
||||
arena.RegisterDisplay(displayConfig, "1.2.3.4")
|
||||
assert.Contains(t, arena.Displays, "1114")
|
||||
arena.MarkDisplayDisconnected(display)
|
||||
arena.MarkDisplayDisconnected(displayConfig.Id)
|
||||
arena.Displays["1114"].lastConnectedTime = time.Now().Add(-displayPurgeTtlMin * time.Minute)
|
||||
arena.purgeDisconnectedDisplays()
|
||||
assert.NotContains(t, arena.Displays, "1114")
|
||||
|
||||
// Named configured display does not get purged by periodic task.
|
||||
display.Nickname = "Brunhilda"
|
||||
arena.RegisterDisplay(display)
|
||||
// Named configured displayConfig does not get purged by periodic task.
|
||||
displayConfig.Nickname = "Brunhilda"
|
||||
arena.RegisterDisplay(displayConfig, "1.2.3.4")
|
||||
assert.Contains(t, arena.Displays, "1114")
|
||||
arena.MarkDisplayDisconnected(display)
|
||||
arena.MarkDisplayDisconnected(displayConfig.Id)
|
||||
arena.Displays["1114"].lastConnectedTime = time.Now().Add(-displayPurgeTtlMin * time.Minute)
|
||||
arena.purgeDisconnectedDisplays()
|
||||
assert.Contains(t, arena.Displays, "1114")
|
||||
|
||||
@@ -40,13 +40,11 @@ var CheesyWebsocket = function(path, events) {
|
||||
// Insert an event to allow reconfiguration if this is a display.
|
||||
if (!events.hasOwnProperty("displayConfiguration")) {
|
||||
events.displayConfiguration = function (event) {
|
||||
if (displayId in event.data.DisplayUrls) {
|
||||
var newUrl = event.data.DisplayUrls[displayId];
|
||||
var newUrl = event.data;
|
||||
|
||||
// Reload the display if the configuration has changed.
|
||||
if (newUrl !== window.location.pathname + window.location.search) {
|
||||
window.location = newUrl;
|
||||
}
|
||||
// Reload the display if the configuration has changed.
|
||||
if (newUrl !== window.location.pathname + window.location.search) {
|
||||
window.location = newUrl;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,14 +38,14 @@ var reloadAllDisplays = function() {
|
||||
var handleDisplayConfiguration = function(data) {
|
||||
$("#displayContainer").empty();
|
||||
|
||||
$.each(data.Displays, function(displayId, display) {
|
||||
$.each(data, function(displayId, display) {
|
||||
var displayRow = displayTemplate(display);
|
||||
$("#displayContainer").append(displayRow);
|
||||
$("#displayNickname" + displayId).val(display.Nickname);
|
||||
$("#displayType" + displayId).val(display.Type);
|
||||
$("#displayNickname" + displayId).val(display.DisplayConfiguration.Nickname);
|
||||
$("#displayType" + displayId).val(display.DisplayConfiguration.Type);
|
||||
|
||||
// Convert configuration map to query string format.
|
||||
var configurationString = $.map(Object.entries(display.Configuration), function(entry) {
|
||||
var configurationString = $.map(Object.entries(display.DisplayConfiguration.Configuration), function(entry) {
|
||||
return entry.join("=");
|
||||
}).join("&");
|
||||
$("#displayConfiguration" + displayId).val(configurationString);
|
||||
|
||||
@@ -31,30 +31,30 @@
|
||||
|
||||
<script id="displayTemplate" type="text/x-handlebars-template">
|
||||
<tr{{"{{#unless ConnectionCount}}"}} class="danger"{{"{{/unless}}"}}>
|
||||
<td>{{"{{Id}}"}}</td>
|
||||
<td>{{"{{DisplayConfiguration.Id}}"}}</td>
|
||||
<td>{{"{{ConnectionCount}}"}}</td>
|
||||
<td>{{"{{IpAddress}}"}}</td>
|
||||
<td><input type="text" id="displayNickname{{"{{Id}}"}}" size="30" /></td>
|
||||
<td><input type="text" id="displayNickname{{"{{DisplayConfiguration.Id}}"}}" size="30" /></td>
|
||||
<td>
|
||||
<select id="displayType{{"{{Id}}"}}">
|
||||
<select id="displayType{{"{{DisplayConfiguration.Id}}"}}">
|
||||
{{range $type, $typeName := .DisplayTypeNames}}
|
||||
<option value="{{$type}}">{{$typeName}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="displayConfiguration{{"{{Id}}"}}" size="50" />
|
||||
<input type="text" id="displayConfiguration{{"{{DisplayConfiguration.Id}}"}}" size="50" />
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-info btn-xs" title="Save Changes"
|
||||
onclick="configureDisplay('{{"{{Id}}"}}');">
|
||||
onclick="configureDisplay('{{"{{DisplayConfiguration.Id}}"}}');">
|
||||
<i class="glyphicon glyphicon-ok"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary btn-xs" title="Undo Changes" onclick="undoChanges();">
|
||||
<i class="glyphicon glyphicon-arrow-left"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-success btn-xs" title="Reload Display"
|
||||
onclick="reloadDisplay('{{"{{Id}}"}}');">
|
||||
onclick="reloadDisplay('{{"{{DisplayConfiguration.Id}}"}}');">
|
||||
<i class="glyphicon glyphicon-refresh"></i>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
@@ -40,7 +40,7 @@ func (web *Web) allianceStationDisplayWebsocketHandler(w http.ResponseWriter, r
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -50,7 +50,7 @@ func (web *Web) allianceStationDisplayWebsocketHandler(w http.ResponseWriter, r
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.MatchTimingNotifier, web.arena.AllianceStationDisplayModeNotifier,
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.MatchTimingNotifier, web.arena.AllianceStationDisplayModeNotifier,
|
||||
web.arena.ArenaStatusNotifier, web.arena.MatchLoadNotifier, web.arena.MatchTimeNotifier,
|
||||
web.arena.RealtimeScoreNotifier, web.arena.DisplayConfigurationNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
web.arena.RealtimeScoreNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
@@ -36,13 +36,13 @@ func TestAllianceStationDisplayWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
readWebsocketType(t, ws, "matchTiming")
|
||||
readWebsocketType(t, ws, "allianceStationDisplayMode")
|
||||
readWebsocketType(t, ws, "arenaStatus")
|
||||
readWebsocketType(t, ws, "matchLoad")
|
||||
readWebsocketType(t, ws, "matchTime")
|
||||
readWebsocketType(t, ws, "realtimeScore")
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
|
||||
// Change to a different screen.
|
||||
web.arena.AllianceStationDisplayMode = "logo"
|
||||
|
||||
@@ -40,7 +40,7 @@ func (web *Web) announcerDisplayWebsocketHandler(w http.ResponseWriter, r *http.
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -50,7 +50,7 @@ func (web *Web) announcerDisplayWebsocketHandler(w http.ResponseWriter, r *http.
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.MatchTimingNotifier, web.arena.MatchLoadNotifier, web.arena.MatchTimeNotifier,
|
||||
web.arena.RealtimeScoreNotifier, web.arena.ScorePostedNotifier, web.arena.AudienceDisplayModeNotifier,
|
||||
web.arena.DisplayConfigurationNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.MatchTimingNotifier, web.arena.MatchLoadNotifier,
|
||||
web.arena.MatchTimeNotifier, web.arena.RealtimeScoreNotifier, web.arena.ScorePostedNotifier,
|
||||
web.arena.AudienceDisplayModeNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@ func TestAnnouncerDisplayWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
readWebsocketType(t, ws, "matchTiming")
|
||||
readWebsocketType(t, ws, "matchLoad")
|
||||
readWebsocketType(t, ws, "matchTime")
|
||||
readWebsocketType(t, ws, "realtimeScore")
|
||||
readWebsocketType(t, ws, "scorePosted")
|
||||
readWebsocketType(t, ws, "audienceDisplayMode")
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
|
||||
web.arena.MatchLoadNotifier.Notify()
|
||||
readWebsocketType(t, ws, "matchLoad")
|
||||
|
||||
@@ -43,7 +43,7 @@ func (web *Web) audienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.R
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -53,8 +53,8 @@ func (web *Web) audienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.R
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.MatchTimingNotifier, web.arena.AudienceDisplayModeNotifier,
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.MatchTimingNotifier, web.arena.AudienceDisplayModeNotifier,
|
||||
web.arena.MatchLoadNotifier, web.arena.MatchTimeNotifier, web.arena.RealtimeScoreNotifier,
|
||||
web.arena.PlaySoundNotifier, web.arena.ScorePostedNotifier, web.arena.AllianceSelectionNotifier,
|
||||
web.arena.LowerThirdNotifier, web.arena.DisplayConfigurationNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
web.arena.LowerThirdNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ func TestAudienceDisplayWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
readWebsocketType(t, ws, "matchTiming")
|
||||
readWebsocketType(t, ws, "audienceDisplayMode")
|
||||
readWebsocketType(t, ws, "matchLoad")
|
||||
@@ -44,7 +45,6 @@ func TestAudienceDisplayWebsocket(t *testing.T) {
|
||||
readWebsocketType(t, ws, "scorePosted")
|
||||
readWebsocketType(t, ws, "allianceSelection")
|
||||
readWebsocketType(t, ws, "lowerThird")
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
|
||||
// Run through a match cycle.
|
||||
web.arena.MatchLoadNotifier.Notify()
|
||||
|
||||
@@ -54,18 +54,16 @@ func (web *Web) enforceDisplayConfiguration(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
// Constructs, registers, and returns the display object for the given incoming websocket request.
|
||||
func (web *Web) registerDisplay(r *http.Request) (*field.Display, error) {
|
||||
display, err := field.DisplayFromUrl(r.URL.Path, r.URL.Query())
|
||||
displayConfig, err := field.DisplayFromUrl(r.URL.Path, r.URL.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Extract the source IP address of the request and store it in the display object.
|
||||
if ipAddress := r.Header.Get("X-Real-IP"); ipAddress != "" {
|
||||
display.IpAddress = ipAddress
|
||||
} else {
|
||||
display.IpAddress = regexp.MustCompile("(.*):\\d+$").FindStringSubmatch(r.RemoteAddr)[1]
|
||||
var ipAddress string
|
||||
if ipAddress = r.Header.Get("X-Real-IP"); ipAddress == "" {
|
||||
ipAddress = regexp.MustCompile("(.*):\\d+$").FindStringSubmatch(r.RemoteAddr)[1]
|
||||
}
|
||||
|
||||
web.arena.RegisterDisplay(display)
|
||||
return display, nil
|
||||
return web.arena.RegisterDisplay(displayConfig, ipAddress), nil
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (web *Web) fieldMonitorDisplayWebsocketHandler(w http.ResponseWriter, r *ht
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -49,6 +49,5 @@ func (web *Web) fieldMonitorDisplayWebsocketHandler(w http.ResponseWriter, r *ht
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.ArenaStatusNotifier, web.arena.DisplayConfigurationNotifier,
|
||||
web.arena.ReloadDisplaysNotifier)
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.ArenaStatusNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@ func TestFieldMonitorDisplayWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
readWebsocketType(t, ws, "arenaStatus")
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
readWebsocketType(t, ws, "arenaStatus")
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (web *Web) pitDisplayWebsocketHandler(w http.ResponseWriter, r *http.Reques
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -49,6 +49,5 @@ func (web *Web) pitDisplayWebsocketHandler(w http.ResponseWriter, r *http.Reques
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.EventStatusNotifier, web.arena.DisplayConfigurationNotifier,
|
||||
web.arena.ReloadDisplaysNotifier)
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.EventStatusNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ func TestPitDisplayWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
readWebsocketType(t, ws, "eventStatus")
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
readWebsocketType(t, ws, "eventStatus")
|
||||
|
||||
// Check forced reloading as that is the only purpose the pit websocket serves.
|
||||
web.arena.ReloadDisplaysNotifier.Notify()
|
||||
|
||||
@@ -39,7 +39,7 @@ func (web *Web) placeholderDisplayWebsocketHandler(w http.ResponseWriter, r *htt
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -49,5 +49,5 @@ func (web *Web) placeholderDisplayWebsocketHandler(w http.ResponseWriter, r *htt
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.DisplayConfigurationNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
@@ -37,15 +37,15 @@ func TestPlaceholderDisplayWebsocket(t *testing.T) {
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
|
||||
if assert.Contains(t, web.arena.Displays, "123") {
|
||||
assert.Equal(t, "blop", web.arena.Displays["123"].Nickname)
|
||||
if assert.Equal(t, 1, len(web.arena.Displays["123"].Configuration)) {
|
||||
assert.Equal(t, "b", web.arena.Displays["123"].Configuration["a"])
|
||||
assert.Equal(t, "blop", web.arena.Displays["123"].DisplayConfiguration.Nickname)
|
||||
if assert.Equal(t, 1, len(web.arena.Displays["123"].DisplayConfiguration.Configuration)) {
|
||||
assert.Equal(t, "b", web.arena.Displays["123"].DisplayConfiguration.Configuration["a"])
|
||||
}
|
||||
}
|
||||
|
||||
// Reconfigure the display and verify that the new configuration is received.
|
||||
display := &field.Display{Id: "123", Nickname: "Alliance", Type: field.AllianceStationDisplay,
|
||||
displayConfig := field.DisplayConfiguration{Id: "123", Nickname: "Alliance", Type: field.AllianceStationDisplay,
|
||||
Configuration: map[string]string{"station": "B2"}}
|
||||
web.arena.UpdateDisplay(display)
|
||||
web.arena.UpdateDisplay(displayConfig)
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func (web *Web) queueingDisplayWebsocketHandler(w http.ResponseWriter, r *http.R
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -79,6 +79,6 @@ func (web *Web) queueingDisplayWebsocketHandler(w http.ResponseWriter, r *http.R
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.MatchTimingNotifier, web.arena.MatchLoadNotifier, web.arena.MatchTimeNotifier,
|
||||
web.arena.EventStatusNotifier, web.arena.DisplayConfigurationNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.MatchTimingNotifier, web.arena.MatchLoadNotifier,
|
||||
web.arena.MatchTimeNotifier, web.arena.EventStatusNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ func TestQueueingDisplayWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
readWebsocketType(t, ws, "matchTiming")
|
||||
readWebsocketType(t, ws, "matchLoad")
|
||||
readWebsocketType(t, ws, "matchTime")
|
||||
readWebsocketType(t, ws, "eventStatus")
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ func (web *Web) displaysWebsocketHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
switch messageType {
|
||||
case "configureDisplay":
|
||||
var display field.Display
|
||||
err = mapstructure.Decode(data, &display)
|
||||
var displayConfig field.DisplayConfiguration
|
||||
err = mapstructure.Decode(data, &displayConfig)
|
||||
if err != nil {
|
||||
ws.WriteError(err.Error())
|
||||
continue
|
||||
}
|
||||
if err = web.arena.UpdateDisplay(&display); err != nil {
|
||||
if err = web.arena.UpdateDisplay(displayConfig); err != nil {
|
||||
ws.WriteError(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -32,37 +32,37 @@ func TestSetupDisplaysWebsocket(t *testing.T) {
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
message := readDisplayConfiguration(t, ws)
|
||||
assert.Empty(t, message.Displays)
|
||||
assert.Empty(t, message.DisplayUrls)
|
||||
assert.Empty(t, message)
|
||||
|
||||
// Connect a couple of displays and verify the resulting configuration messages.
|
||||
displayConn1, _, _ := gorillawebsocket.DefaultDialer.Dial(wsUrl+"/display/websocket?displayId=1", nil)
|
||||
defer displayConn1.Close()
|
||||
displayWs1 := websocket.NewTestWebsocket(displayConn1)
|
||||
assert.Equal(t, "/display?displayId=1", readWebsocketType(t, displayWs1, "displayConfiguration"))
|
||||
readDisplayConfiguration(t, ws)
|
||||
displayConn2, _, _ := gorillawebsocket.DefaultDialer.Dial(wsUrl+
|
||||
"/displays/alliance_station/websocket?displayId=2&station=R2", nil)
|
||||
defer displayConn2.Close()
|
||||
expectedDisplay1 := &field.Display{Id: "1", Type: field.PlaceholderDisplay, Configuration: map[string]string{},
|
||||
ConnectionCount: 1, IpAddress: "127.0.0.1"}
|
||||
expectedDisplay2 := &field.Display{Id: "2", Type: field.AllianceStationDisplay,
|
||||
Configuration: map[string]string{"station": "R2"}, ConnectionCount: 1, IpAddress: "127.0.0.1"}
|
||||
message = readDisplayConfiguration(t, ws)
|
||||
if assert.Equal(t, 2, len(message.Displays)) {
|
||||
assert.Equal(t, expectedDisplay1, message.Displays["1"])
|
||||
assert.Equal(t, expectedDisplay2, message.Displays["2"])
|
||||
assert.Equal(t, expectedDisplay1.ToUrl(), message.DisplayUrls["1"])
|
||||
assert.Equal(t, expectedDisplay2.ToUrl(), message.DisplayUrls["2"])
|
||||
if assert.Equal(t, 2, len(message)) {
|
||||
assert.Equal(t, field.DisplayConfiguration{"1", "", field.PlaceholderDisplay, map[string]string{}},
|
||||
message["1"].DisplayConfiguration)
|
||||
assert.Equal(t, 1, message["1"].ConnectionCount)
|
||||
assert.Equal(t, "127.0.0.1", message["1"].IpAddress)
|
||||
assert.Equal(t, field.DisplayConfiguration{"2", "", field.AllianceStationDisplay,
|
||||
map[string]string{"station": "R2"}}, message["2"].DisplayConfiguration)
|
||||
assert.Equal(t, 1, message["2"].ConnectionCount)
|
||||
assert.Equal(t, "127.0.0.1", message["2"].IpAddress)
|
||||
}
|
||||
|
||||
// Reconfigure a display and verify the result.
|
||||
expectedDisplay1.Nickname = "Audience Display"
|
||||
expectedDisplay1.Type = field.AudienceDisplay
|
||||
expectedDisplay1.Configuration["background"] = "#00f"
|
||||
expectedDisplay1.Configuration["reversed"] = "true"
|
||||
ws.Write("configureDisplay", expectedDisplay1)
|
||||
displayConfig := field.DisplayConfiguration{Id: "1", Nickname: "Audience Display", Type: field.AudienceDisplay,
|
||||
Configuration: map[string]string{"background": "#00f", "reversed": "true"}}
|
||||
ws.Write("configureDisplay", displayConfig)
|
||||
message = readDisplayConfiguration(t, ws)
|
||||
assert.Equal(t, expectedDisplay1, message.Displays["1"])
|
||||
assert.Equal(t, expectedDisplay1.ToUrl(), message.DisplayUrls["1"])
|
||||
assert.Equal(t, displayConfig, message["1"].DisplayConfiguration)
|
||||
assert.Equal(t, "/displays/audience?displayId=1&nickname=Audience+Display&background=%2300f&reversed=true",
|
||||
readWebsocketType(t, displayWs1, "displayConfiguration"))
|
||||
}
|
||||
|
||||
func TestSetupDisplaysWebsocketReloadDisplays(t *testing.T) {
|
||||
@@ -82,7 +82,7 @@ func TestSetupDisplaysWebsocketReloadDisplays(t *testing.T) {
|
||||
displayConn, _, _ := gorillawebsocket.DefaultDialer.Dial(wsUrl+"/display/websocket?displayId=1", nil)
|
||||
defer displayConn.Close()
|
||||
displayWs := websocket.NewTestWebsocket(displayConn)
|
||||
readDisplayConfiguration(t, displayWs)
|
||||
assert.Equal(t, "/display?displayId=1", readWebsocketType(t, displayWs, "displayConfiguration"))
|
||||
readDisplayConfiguration(t, ws)
|
||||
|
||||
// Reset a display selectively and verify the resulting message.
|
||||
@@ -92,10 +92,10 @@ func TestSetupDisplaysWebsocketReloadDisplays(t *testing.T) {
|
||||
assert.Equal(t, nil, readWebsocketType(t, displayWs, "reload"))
|
||||
}
|
||||
|
||||
func readDisplayConfiguration(t *testing.T, ws *websocket.Websocket) *field.DisplayConfigurationMessage {
|
||||
func readDisplayConfiguration(t *testing.T, ws *websocket.Websocket) map[string]field.Display {
|
||||
message := readWebsocketType(t, ws, "displayConfiguration")
|
||||
var displayConfigurationMessage field.DisplayConfigurationMessage
|
||||
var displayConfigurationMessage map[string]field.Display
|
||||
err := mapstructure.Decode(message, &displayConfigurationMessage)
|
||||
assert.Nil(t, err)
|
||||
return &displayConfigurationMessage
|
||||
return displayConfigurationMessage
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (web *Web) twitchDisplayWebsocketHandler(w http.ResponseWriter, r *http.Req
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
defer web.arena.MarkDisplayDisconnected(display.DisplayConfiguration.Id)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -49,5 +49,5 @@ func (web *Web) twitchDisplayWebsocketHandler(w http.ResponseWriter, r *http.Req
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.DisplayConfigurationNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
ws.HandleNotifiers(display.Notifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user