Add publishing of match video split times to STEMtv.

This commit is contained in:
Patrick Fairbank
2016-08-28 00:49:52 -07:00
parent 16b955f481
commit 57725cb621
11 changed files with 125 additions and 3 deletions

View File

@@ -26,7 +26,9 @@ CREATE TABLE event_settings (
reddefenselightsaddress VARCHAR(255),
bluegoallightsaddress VARCHAR(255),
bluedefenselightsaddress VARCHAR(255),
initialtowerstrength int
initialtowerstrength int,
stemtvpublishingenabled bool,
stemtveventcode VARCHAR(16)
);
-- +goose Down

View File

@@ -13,6 +13,8 @@ import (
const elimMatchSpacingSec = 600
var elimRoundNames = map[int]string{1: "F", 2: "SF", 4: "QF", 8: "EF"}
// Incrementally creates any elimination matches that can be created, based on the results of alliance
// selection or prior elimination rounds. Returns the winning alliance once it has been determined.
func (database *Database) UpdateEliminationSchedule(startTime time.Time) ([]AllianceTeam, error) {
@@ -49,7 +51,7 @@ func (database *Database) buildEliminationMatchSet(round int, group int, numAlli
if numAlliances < 2 {
return []AllianceTeam{}, fmt.Errorf("Must have at least 2 alliances")
}
roundName, ok := map[int]string{1: "F", 2: "SF", 4: "QF", 8: "EF"}[round]
roundName, ok := elimRoundNames[round]
if !ok {
return []AllianceTeam{}, fmt.Errorf("Round of depth %d is not supported", round*2)
}

View File

@@ -32,6 +32,8 @@ type EventSettings struct {
BlueGoalLightsAddress string
BlueDefenseLightsAddress string
InitialTowerStrength int
StemTvPublishingEnabled bool
StemTvEventCode string
}
const eventSettingsId = 0

View File

@@ -6,6 +6,7 @@
package main
import (
"fmt"
"strings"
"time"
)
@@ -112,3 +113,13 @@ func (match *Match) CapitalizedType() string {
}
return strings.ToUpper(match.Type[0:1]) + match.Type[1:]
}
func (match *Match) TbaCode() string {
if match.Type == "qualification" {
return fmt.Sprintf("qm%s", match.DisplayName)
} else if match.Type == "elimination" {
return fmt.Sprintf("%s%dm%d", strings.ToLower(elimRoundNames[match.ElimRound]), match.ElimGroup,
match.ElimInstance)
}
return ""
}

View File

@@ -170,6 +170,16 @@ func MatchPlayShowResultHandler(w http.ResponseWriter, r *http.Request) {
}()
}
if eventSettings.StemTvPublishingEnabled && match.Type != "practice" {
// Publish asynchronously to STEMtv.
go func() {
err = PublishMatchVideoSplit(match, time.Now())
if err != nil {
log.Printf("Failed to publish match video split to STEMtv: %s", err.Error())
}
}()
}
http.Redirect(w, r, "/match_play", 302)
}

View File

@@ -122,9 +122,11 @@ func TestMatchPlayShowResult(t *testing.T) {
assert.Equal(t, match.Id, mainArena.savedMatch.Id)
assert.Equal(t, match.Id, mainArena.savedMatchResult.MatchId)
// Verify TBA publishing by checking the log for the expected failure messages.
// Verify TBA and STEMtv publishing by checking the log for the expected failure messages.
tbaBaseUrl = "fakeurl"
stemTvBaseUrl = "fakeurl"
eventSettings.TbaPublishingEnabled = true
eventSettings.StemTvPublishingEnabled = true
var writer bytes.Buffer
log.SetOutput(&writer)
recorder = getHttpResponse(fmt.Sprintf("/match_play/%d/show_result", match.Id))
@@ -132,6 +134,7 @@ func TestMatchPlayShowResult(t *testing.T) {
time.Sleep(time.Millisecond * 10) // Allow some time for the asynchronous publishing to happen.
assert.Contains(t, writer.String(), "Failed to publish matches")
assert.Contains(t, writer.String(), "Failed to publish rankings")
assert.Contains(t, writer.String(), "Failed to publish match video split to STEMtv")
}
func TestMatchPlayErrors(t *testing.T) {

View File

@@ -122,3 +122,18 @@ func TestGetMatchesByType(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 1, len(matches))
}
func TestTbaCode(t *testing.T) {
match := Match{Type: "practice", DisplayName: "3"}
assert.Equal(t, "", match.TbaCode())
match = Match{Type: "qualification", DisplayName: "26"}
assert.Equal(t, "qm26", match.TbaCode())
match = Match{Type: "elimination", DisplayName: "EF2-1", ElimRound: 8, ElimGroup: 2, ElimInstance: 1}
assert.Equal(t, "ef2m1", match.TbaCode())
match = Match{Type: "elimination", DisplayName: "QF3-2", ElimRound: 4, ElimGroup: 3, ElimInstance: 2}
assert.Equal(t, "qf3m2", match.TbaCode())
match = Match{Type: "elimination", DisplayName: "SF1-3", ElimRound: 2, ElimGroup: 1, ElimInstance: 3}
assert.Equal(t, "sf1m3", match.TbaCode())
match = Match{Type: "elimination", DisplayName: "F2", ElimRound: 1, ElimGroup: 1, ElimInstance: 2}
assert.Equal(t, "f1m2", match.TbaCode())
}

View File

@@ -55,6 +55,8 @@ func SettingsPostHandler(w http.ResponseWriter, r *http.Request) {
eventSettings.TbaEventCode = r.PostFormValue("tbaEventCode")
eventSettings.TbaSecretId = r.PostFormValue("tbaSecretId")
eventSettings.TbaSecret = r.PostFormValue("tbaSecret")
eventSettings.StemTvPublishingEnabled = r.PostFormValue("stemTvPublishingEnabled") == "on"
eventSettings.StemTvEventCode = r.PostFormValue("stemTvEventCode")
eventSettings.NetworkSecurityEnabled = r.PostFormValue("networkSecurityEnabled") == "on"
eventSettings.ApAddress = r.PostFormValue("apAddress")
eventSettings.ApUsername = r.PostFormValue("apUsername")

27
stemtv.go Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2016 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Methods for publishing match video split information to STEMtv.
package main
import (
"fmt"
"net/http"
"time"
)
const (
preMatchPaddingSec = 5
postScoreDisplayPaddingSec = 10
)
var stemTvBaseUrl = "http://stemtv.io"
func PublishMatchVideoSplit(match *Match, scoreDisplayTime time.Time) error {
url := fmt.Sprintf("%s/event/api/v1.0/%s/%s/split/%d,%d", stemTvBaseUrl, eventSettings.StemTvEventCode,
match.TbaCode(), match.StartedAt.Unix()-preMatchPaddingSec,
scoreDisplayTime.Unix()+postScoreDisplayPaddingSec)
_, err := http.Get(url)
return err
}

35
stemtv_test.go Normal file
View File

@@ -0,0 +1,35 @@
// Copyright 2016 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
package main
import (
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
"time"
)
func TestPublishMatchVideoSplit(t *testing.T) {
clearDb()
defer clearDb()
var err error
db, err = OpenDatabase(testDbPath)
assert.Nil(t, err)
defer db.Close()
eventSettings, _ = db.GetEventSettings()
eventSettings.StemTvEventCode = "my_event_code"
// Mock the STEMtv server.
stemTvServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/event/api/v1.0/my_event_code/qm254/split/981187501,981187690", r.URL.String())
}))
defer stemTvServer.Close()
stemTvBaseUrl = stemTvServer.URL
matchStartedTime, _ := time.Parse("2006-01-02 15:04:05 -0700", "2001-02-03 04:05:06 -0400")
match := &Match{Type: "qualification", DisplayName: "254", StartedAt: matchStartedTime}
scoreDisplayTime, _ := time.Parse("2006-01-02 15:04:05 -0700", "2001-02-03 04:08:00 -0400")
assert.Nil(t, PublishMatchVideoSplit(match, scoreDisplayTime))
}

View File

@@ -128,6 +128,19 @@
<input type="text" class="form-control" name="tbaSecret" value="{{.TbaSecret}}">
</div>
</div>
<p>Contact STEMtv to obtain an event code.</p>
<div class="form-group">
<label class="col-lg-7 control-label">Enable STEMtv publishing</label>
<div class="col-lg-1 checkbox">
<input type="checkbox" name="stemTvPublishingEnabled"{{if .StemTvPublishingEnabled}} checked{{end}}>
</div>
</div>
<div class="form-group">
<label class="col-lg-5 control-label">STEMtv Event Code</label>
<div class="col-lg-7">
<input type="text" class="form-control" name="stemTvEventCode" value="{{.StemTvEventCode}}">
</div>
</div>
</fieldset>
<fieldset>
<legend>Authentication</legend>