Periodically refresh the match list for scouting
I've had a few instances where students thought that we didn't support
eliminations matches because they don't show up when first importing
the match list. The eliminations matches are only importable after the
alliance selections.
To work around this, the webserver now periodically imports the latest
match list. This means we don't need anyone to manually use the
"Import Match List" tab on the app anymore. I deleted that tab as
part of this patch.
The new `scouting/webserver/match_list/match_list.go` file is largely
just the code that I deleted from
`scouting/webserver/requests/requests.go`. I.e. it's really just
moving code around. The main difference now is that instead of
`requests.go` handling match list imports,
`scouting/webserver/main.go` now starts a background task to scrape
the match list every 10 minutes or so.
Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: Ic37df45261f03a323069c1b38c4fd9682a9c4a3e
diff --git a/scouting/webserver/BUILD b/scouting/webserver/BUILD
index e1ab726..934aff1 100644
--- a/scouting/webserver/BUILD
+++ b/scouting/webserver/BUILD
@@ -8,8 +8,8 @@
visibility = ["//visibility:private"],
deps = [
"//scouting/db",
- "//scouting/scraping",
"//scouting/scraping/background",
+ "//scouting/webserver/match_list",
"//scouting/webserver/rankings",
"//scouting/webserver/requests",
"//scouting/webserver/server",
diff --git a/scouting/webserver/main.go b/scouting/webserver/main.go
index 77cc3c4..1811b7f 100644
--- a/scouting/webserver/main.go
+++ b/scouting/webserver/main.go
@@ -14,8 +14,8 @@
"time"
"github.com/frc971/971-Robot-Code/scouting/db"
- "github.com/frc971/971-Robot-Code/scouting/scraping"
"github.com/frc971/971-Robot-Code/scouting/scraping/background"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/match_list"
"github.com/frc971/971-Robot-Code/scouting/webserver/rankings"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests"
"github.com/frc971/971-Robot-Code/scouting/webserver/server"
@@ -120,19 +120,20 @@
}
defer database.Delete()
- scrapeMatchList := func(year int32, eventCode string) ([]scraping.Match, error) {
- if *blueAllianceConfigPtr == "" {
- return nil, errors.New("Cannot scrape TBA's match list without a config file.")
- }
- return scraping.GetAllData[[]scraping.Match](year, eventCode, *blueAllianceConfigPtr, "matches")
- }
-
scoutingServer := server.NewScoutingServer()
static.ServePages(scoutingServer, *dirPtr)
- requests.HandleRequests(database, scrapeMatchList, scoutingServer)
+ requests.HandleRequests(database, scoutingServer)
scoutingServer.Start(*portPtr)
fmt.Println("Serving", *dirPtr, "on port", *portPtr)
+ // Since Go doesn't support default arguments, we use 0 and "" to
+ // indicate that we want to source the values from the config.
+
+ matchListScraper := background.BackgroundScraper{}
+ matchListScraper.Start(func() {
+ match_list.GetMatchList(database, 0, "", *blueAllianceConfigPtr)
+ })
+
rankingsScraper := background.BackgroundScraper{}
rankingsScraper.Start(func() {
rankings.GetRankings(database, 0, "", *blueAllianceConfigPtr)
@@ -148,5 +149,6 @@
fmt.Println("Shutting down.")
scoutingServer.Stop()
rankingsScraper.Stop()
+ matchListScraper.Stop()
fmt.Println("Successfully shut down.")
}
diff --git a/scouting/webserver/match_list/BUILD b/scouting/webserver/match_list/BUILD
new file mode 100644
index 0000000..e32b93c
--- /dev/null
+++ b/scouting/webserver/match_list/BUILD
@@ -0,0 +1,12 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "match_list",
+ srcs = ["match_list.go"],
+ importpath = "github.com/frc971/971-Robot-Code/scouting/webserver/match_list",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//scouting/db",
+ "//scouting/scraping",
+ ],
+)
diff --git a/scouting/webserver/match_list/match_list.go b/scouting/webserver/match_list/match_list.go
new file mode 100644
index 0000000..9029438
--- /dev/null
+++ b/scouting/webserver/match_list/match_list.go
@@ -0,0 +1,138 @@
+package match_list
+
+import (
+ "errors"
+ "fmt"
+ "github.com/frc971/971-Robot-Code/scouting/db"
+ "github.com/frc971/971-Robot-Code/scouting/scraping"
+ "log"
+ "strconv"
+ "strings"
+)
+
+type Database interface {
+ AddToMatch(db.TeamMatch) error
+}
+
+func parseTeamKey(teamKey string) (int, error) {
+ // TBA prefixes teams with "frc". Not sure why. Get rid of that.
+ teamKey = strings.TrimPrefix(teamKey, "frc")
+ magnitude := 0
+ if strings.HasSuffix(teamKey, "A") {
+ magnitude = 0
+ teamKey = strings.TrimSuffix(teamKey, "A")
+ } else if strings.HasSuffix(teamKey, "B") {
+ magnitude = 9
+ teamKey = strings.TrimSuffix(teamKey, "B")
+ } else if strings.HasSuffix(teamKey, "C") {
+ magnitude = 8
+ teamKey = strings.TrimSuffix(teamKey, "C")
+ } else if strings.HasSuffix(teamKey, "D") {
+ magnitude = 7
+ teamKey = strings.TrimSuffix(teamKey, "D")
+ } else if strings.HasSuffix(teamKey, "E") {
+ magnitude = 6
+ teamKey = strings.TrimSuffix(teamKey, "E")
+ } else if strings.HasSuffix(teamKey, "F") {
+ magnitude = 5
+ teamKey = strings.TrimSuffix(teamKey, "F")
+ }
+
+ if magnitude != 0 {
+ teamKey = strconv.Itoa(magnitude) + teamKey
+ }
+
+ result, err := strconv.Atoi(teamKey)
+ return result, err
+}
+
+// Parses the alliance data from the specified match and returns the three red
+// teams and the three blue teams.
+func parseTeamKeys(match *scraping.Match) ([3]int32, [3]int32, error) {
+ redKeys := match.Alliances.Red.TeamKeys
+ blueKeys := match.Alliances.Blue.TeamKeys
+
+ if len(redKeys) != 3 || len(blueKeys) != 3 {
+ return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
+ "Found %d red teams and %d blue teams.", len(redKeys), len(blueKeys)))
+ }
+
+ var red [3]int32
+ for i, key := range redKeys {
+ team, err := parseTeamKey(key)
+ if err != nil {
+ return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
+ "Failed to parse red %d team '%s' as integer: %v", i+1, key, err))
+ }
+ red[i] = int32(team)
+ }
+ var blue [3]int32
+ for i, key := range blueKeys {
+ team, err := parseTeamKey(key)
+ if err != nil {
+ return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
+ "Failed to parse blue %d team '%s' as integer: %v", i+1, key, err))
+ }
+ blue[i] = int32(team)
+ }
+ return red, blue, nil
+}
+
+func GetMatchList(database Database, year int32, eventCode string, blueAllianceConfig string) {
+ matches, err := scraping.GetAllData[[]scraping.Match](year, eventCode, blueAllianceConfig, "matches")
+ if err != nil {
+ log.Println("Failed to scrape match list: ", err)
+ return
+ }
+
+ for _, match := range matches {
+ // Make sure the data is valid.
+ red, blue, err := parseTeamKeys(&match)
+ if err != nil {
+ log.Println("TheBlueAlliance data for match %d is malformed: %v", match.MatchNumber, err)
+ return
+ }
+
+ team_matches := []db.TeamMatch{
+ {
+ MatchNumber: int32(match.MatchNumber),
+ SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
+ Alliance: "R", AlliancePosition: 1, TeamNumber: red[0],
+ },
+ {
+ MatchNumber: int32(match.MatchNumber),
+ SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
+ Alliance: "R", AlliancePosition: 2, TeamNumber: red[1],
+ },
+ {
+ MatchNumber: int32(match.MatchNumber),
+ SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
+ Alliance: "R", AlliancePosition: 3, TeamNumber: red[2],
+ },
+ {
+ MatchNumber: int32(match.MatchNumber),
+ SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
+ Alliance: "B", AlliancePosition: 1, TeamNumber: blue[0],
+ },
+ {
+ MatchNumber: int32(match.MatchNumber),
+ SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
+ Alliance: "B", AlliancePosition: 2, TeamNumber: blue[1],
+ },
+ {
+ MatchNumber: int32(match.MatchNumber),
+ SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
+ Alliance: "B", AlliancePosition: 3, TeamNumber: blue[2],
+ },
+ }
+
+ for _, match := range team_matches {
+ // Iterate through matches to check they can be added to database.
+ err = database.AddToMatch(match)
+ if err != nil {
+ log.Println("Failed to add team %d from match %d to the database: %v", match.TeamNumber, match.MatchNumber, err)
+ return
+ }
+ }
+ }
+}
diff --git a/scouting/webserver/requests/BUILD b/scouting/webserver/requests/BUILD
index 9eb207d..e0d3e87 100644
--- a/scouting/webserver/requests/BUILD
+++ b/scouting/webserver/requests/BUILD
@@ -8,10 +8,7 @@
visibility = ["//visibility:public"],
deps = [
"//scouting/db",
- "//scouting/scraping",
"//scouting/webserver/requests/messages:error_response_go_fbs",
- "//scouting/webserver/requests/messages:refresh_match_list_go_fbs",
- "//scouting/webserver/requests/messages:refresh_match_list_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_driver_rankings_go_fbs",
"//scouting/webserver/requests/messages:request_all_driver_rankings_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_matches_go_fbs",
@@ -46,11 +43,8 @@
target_compatible_with = ["@platforms//cpu:x86_64"],
deps = [
"//scouting/db",
- "//scouting/scraping",
"//scouting/webserver/requests/debug",
"//scouting/webserver/requests/messages:error_response_go_fbs",
- "//scouting/webserver/requests/messages:refresh_match_list_go_fbs",
- "//scouting/webserver/requests/messages:refresh_match_list_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_driver_rankings_go_fbs",
"//scouting/webserver/requests/messages:request_all_driver_rankings_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_matches_go_fbs",
diff --git a/scouting/webserver/requests/debug/BUILD b/scouting/webserver/requests/debug/BUILD
index 650ba82..1473b3c 100644
--- a/scouting/webserver/requests/debug/BUILD
+++ b/scouting/webserver/requests/debug/BUILD
@@ -8,7 +8,6 @@
visibility = ["//visibility:public"],
deps = [
"//scouting/webserver/requests/messages:error_response_go_fbs",
- "//scouting/webserver/requests/messages:refresh_match_list_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_driver_rankings_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
diff --git a/scouting/webserver/requests/debug/cli/cli_test.py b/scouting/webserver/requests/debug/cli/cli_test.py
index 6d33082..4e47b2d 100644
--- a/scouting/webserver/requests/debug/cli/cli_test.py
+++ b/scouting/webserver/requests/debug/cli/cli_test.py
@@ -13,8 +13,19 @@
from typing import Any, Dict, List
import unittest
+from rules_python.python.runfiles import runfiles
+
import scouting.testing.scouting_test_servers
+RUNFILES = runfiles.Create()
+
+# This regex finds the number of matches that the web server has imported. This
+# is intended to parse the output of the debug cli's `-requestAllMatches`
+# option.
+MATCH_LIST_LENGTH_EXTRACTION_RE = re.compile(
+ r"MatchList: \(\[\]\*request_all_matches_response.MatchT\) \(len=(\d+) cap=.*\) \{"
+)
+
def write_json_request(content: Dict[str, Any]):
"""Writes a JSON file with the specified dict content."""
@@ -37,29 +48,52 @@
)
+def find_num_matches_for_event(year, event_code):
+ with open(
+ RUNFILES.Rlocation(
+ f"org_frc971/scouting/scraping/test_data/{year}_{event_code}.json"
+ ), "r") as file:
+ raw_match_list = json.load(file)
+ return len(raw_match_list)
+
+
class TestDebugCli(unittest.TestCase):
def setUp(self):
self.servers = scouting.testing.scouting_test_servers.Runner()
- self.servers.start(8080)
def tearDown(self):
self.servers.stop()
- def refresh_match_list(self, year=2016, event_code="nytr"):
- """Triggers the webserver to fetch the match list."""
- json_path = write_json_request({
- "year": year,
- "event_code": event_code,
- })
- exit_code, stdout, stderr = run_debug_cli(
- ["-refreshMatchList", json_path])
- self.assertEqual(exit_code, 0, f"{year}{event_code}: {stderr}")
- self.assertIn(
- "(refresh_match_list_response.RefreshMatchListResponseT)", stdout)
+ def start_servers(self, year=2016, event_code="nytr"):
+ self.servers.start(8080, year=year, event_code=event_code)
+
+ expected_num_matches = find_num_matches_for_event(year, event_code)
+ json_path = write_json_request({})
+
+ # Wait until the match list is imported. This is done automatically
+ # when the web server starts up.
+ sys.stderr.write("Waiting for match list to be imported.\n")
+ while True:
+ exit_code, stdout, stderr = run_debug_cli(
+ ["-requestAllMatches", json_path])
+ self.assertEqual(exit_code, 0, stderr)
+
+ match = MATCH_LIST_LENGTH_EXTRACTION_RE.search(stdout)
+ if match:
+ num_matches_imported = int(match.group(1))
+
+ if num_matches_imported == expected_num_matches:
+ break
+ else:
+ sys.stderr.write(
+ f"Waiting until {expected_num_matches} are imported. "
+ f"Currently at {num_matches_imported}.\n")
+
+ time.sleep(0.25)
def test_submit_and_request_data_scouting(self):
- self.refresh_match_list(year=2020, event_code="fake")
+ self.start_servers(year=2020, event_code="fake")
# First submit some data to be added to the database.
json_path = write_json_request({
@@ -142,7 +176,7 @@
}"""), stdout)
def test_submit_and_request_notes(self):
- self.refresh_match_list(year=2020, event_code="fake")
+ self.start_servers(year=2020, event_code="fake")
# First submit some data to be added to the database.
json_path = write_json_request({
@@ -179,7 +213,7 @@
}"""), stdout)
def test_submit_and_request_driver_ranking(self):
- self.refresh_match_list(year=2020, event_code="fake")
+ self.start_servers(year=2020, event_code="fake")
# First submit some data to be added to the database.
json_path = write_json_request({
@@ -209,7 +243,7 @@
}"""), stdout)
def test_request_all_matches(self):
- self.refresh_match_list()
+ self.start_servers()
# RequestAllMatches has no fields.
json_path = write_json_request({})
@@ -222,24 +256,6 @@
stdout)
self.assertEqual(stdout.count("MatchNumber:"), 90)
- def test_request_all_matches(self):
- """Makes sure that we can import the match list multiple times without problems."""
- request_all_matches_outputs = []
- for _ in range(2):
- self.refresh_match_list()
-
- # RequestAllMatches has no fields.
- json_path = write_json_request({})
- exit_code, stdout, stderr = run_debug_cli(
- ["-requestAllMatches", json_path])
-
- self.assertEqual(exit_code, 0, stderr)
- request_all_matches_outputs.append(stdout)
-
- self.maxDiff = None
- self.assertEqual(request_all_matches_outputs[0],
- request_all_matches_outputs[1])
-
if __name__ == "__main__":
unittest.main()
diff --git a/scouting/webserver/requests/debug/cli/main.go b/scouting/webserver/requests/debug/cli/main.go
index 066dec5..9279dba 100644
--- a/scouting/webserver/requests/debug/cli/main.go
+++ b/scouting/webserver/requests/debug/cli/main.go
@@ -97,8 +97,6 @@
"If specified, parse the file as a requestAllDriverRankings JSON request.")
requestAllNotesPtr := flag.String("requestAllNotes", "",
"If specified, parse the file as a requestAllNotes JSON request.")
- refreshMatchListPtr := flag.String("refreshMatchList", "",
- "If specified, parse the file as a RefreshMatchList JSON request.")
flag.Parse()
spew.Config.Indent = *indentPtr
@@ -155,11 +153,4 @@
*requestAllNotesPtr,
*addressPtr,
debug.RequestAllNotes)
-
- maybePerformRequest(
- "RefreshMatchList",
- "scouting/webserver/requests/messages/refresh_match_list.fbs",
- *refreshMatchListPtr,
- *addressPtr,
- debug.RefreshMatchList)
}
diff --git a/scouting/webserver/requests/debug/debug.go b/scouting/webserver/requests/debug/debug.go
index 130850c..1f215f7 100644
--- a/scouting/webserver/requests/debug/debug.go
+++ b/scouting/webserver/requests/debug/debug.go
@@ -10,7 +10,6 @@
"net/http"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
- "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
@@ -130,12 +129,6 @@
request_data_scouting_response.GetRootAsRequestDataScoutingResponse)
}
-func RefreshMatchList(server string, requestBytes []byte) (*refresh_match_list_response.RefreshMatchListResponseT, error) {
- return sendMessage[refresh_match_list_response.RefreshMatchListResponseT](
- server+"/requests/refresh_match_list", requestBytes,
- refresh_match_list_response.GetRootAsRefreshMatchListResponse)
-}
-
func SubmitNotes(server string, requestBytes []byte) (*submit_notes_response.SubmitNotesResponseT, error) {
return sendMessage[submit_notes_response.SubmitNotesResponseT](
server+"/requests/submit/submit_notes", requestBytes,
diff --git a/scouting/webserver/requests/messages/BUILD b/scouting/webserver/requests/messages/BUILD
index 2e118d5..124613c 100644
--- a/scouting/webserver/requests/messages/BUILD
+++ b/scouting/webserver/requests/messages/BUILD
@@ -13,8 +13,6 @@
"request_all_notes_response",
"request_data_scouting",
"request_data_scouting_response",
- "refresh_match_list",
- "refresh_match_list_response",
"submit_notes",
"submit_notes_response",
"request_notes_for_team",
diff --git a/scouting/webserver/requests/messages/refresh_match_list.fbs b/scouting/webserver/requests/messages/refresh_match_list.fbs
deleted file mode 100644
index c4384c7..0000000
--- a/scouting/webserver/requests/messages/refresh_match_list.fbs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace scouting.webserver.requests;
-
-table RefreshMatchList {
- year: int (id: 0);
- event_code: string (id: 1);
-}
-
-root_type RefreshMatchList;
diff --git a/scouting/webserver/requests/messages/refresh_match_list_response.fbs b/scouting/webserver/requests/messages/refresh_match_list_response.fbs
deleted file mode 100644
index ba80272..0000000
--- a/scouting/webserver/requests/messages/refresh_match_list_response.fbs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace scouting.webserver.requests;
-
-table RefreshMatchListResponse {
-}
-
-root_type RefreshMatchListResponse;
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index d56f380..fab725c 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -12,10 +12,7 @@
"strings"
"github.com/frc971/971-Robot-Code/scouting/db"
- "github.com/frc971/971-Robot-Code/scouting/scraping"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
- "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list"
- "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches"
@@ -52,8 +49,6 @@
type RequestAllNotesResponseT = request_all_notes_response.RequestAllNotesResponseT
type RequestDataScouting = request_data_scouting.RequestDataScouting
type RequestDataScoutingResponseT = request_data_scouting_response.RequestDataScoutingResponseT
-type RefreshMatchList = refresh_match_list.RefreshMatchList
-type RefreshMatchListResponseT = refresh_match_list_response.RefreshMatchListResponseT
type SubmitNotes = submit_notes.SubmitNotes
type SubmitNotesResponseT = submit_notes_response.SubmitNotesResponseT
type RequestNotesForTeam = request_notes_for_team.RequestNotesForTeam
@@ -85,8 +80,6 @@
AddDriverRanking(db.DriverRankingData) error
}
-type ScrapeMatchList func(int32, string) ([]scraping.Match, error)
-
// Handles unknown requests. Just returns a 404.
func unknown(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusNotFound)
@@ -417,152 +410,6 @@
w.Write(builder.FinishedBytes())
}
-func parseTeamKey(teamKey string) (int, error) {
- // TBA prefixes teams with "frc". Not sure why. Get rid of that.
- teamKey = strings.TrimPrefix(teamKey, "frc")
- magnitude := 0
- if strings.HasSuffix(teamKey, "A") {
- magnitude = 0
- teamKey = strings.TrimSuffix(teamKey, "A")
- } else if strings.HasSuffix(teamKey, "B") {
- magnitude = 9
- teamKey = strings.TrimSuffix(teamKey, "B")
- } else if strings.HasSuffix(teamKey, "C") {
- magnitude = 8
- teamKey = strings.TrimSuffix(teamKey, "C")
- } else if strings.HasSuffix(teamKey, "D") {
- magnitude = 7
- teamKey = strings.TrimSuffix(teamKey, "D")
- } else if strings.HasSuffix(teamKey, "E") {
- magnitude = 6
- teamKey = strings.TrimSuffix(teamKey, "E")
- } else if strings.HasSuffix(teamKey, "F") {
- magnitude = 5
- teamKey = strings.TrimSuffix(teamKey, "F")
- }
-
- if magnitude != 0 {
- teamKey = strconv.Itoa(magnitude) + teamKey
- }
-
- result, err := strconv.Atoi(teamKey)
- return result, err
-}
-
-// Parses the alliance data from the specified match and returns the three red
-// teams and the three blue teams.
-func parseTeamKeys(match *scraping.Match) ([3]int32, [3]int32, error) {
- redKeys := match.Alliances.Red.TeamKeys
- blueKeys := match.Alliances.Blue.TeamKeys
-
- if len(redKeys) != 3 || len(blueKeys) != 3 {
- return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
- "Found %d red teams and %d blue teams.", len(redKeys), len(blueKeys)))
- }
-
- var red [3]int32
- for i, key := range redKeys {
- team, err := parseTeamKey(key)
- if err != nil {
- return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
- "Failed to parse red %d team '%s' as integer: %v", i+1, key, err))
- }
- red[i] = int32(team)
- }
- var blue [3]int32
- for i, key := range blueKeys {
- team, err := parseTeamKey(key)
- if err != nil {
- return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
- "Failed to parse blue %d team '%s' as integer: %v", i+1, key, err))
- }
- blue[i] = int32(team)
- }
- return red, blue, nil
-}
-
-type refreshMatchListHandler struct {
- db Database
- scrape ScrapeMatchList
-}
-
-func (handler refreshMatchListHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- requestBytes, err := io.ReadAll(req.Body)
- if err != nil {
- respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
- return
- }
-
- request, success := parseRequest(w, requestBytes, "RefreshMatchList", refresh_match_list.GetRootAsRefreshMatchList)
- if !success {
- return
- }
-
- matches, err := handler.scrape(request.Year(), string(request.EventCode()))
- if err != nil {
- respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Faled to scrape match list: ", err))
- return
- }
-
- for _, match := range matches {
- // Make sure the data is valid.
- red, blue, err := parseTeamKeys(&match)
- if err != nil {
- respondWithError(w, http.StatusInternalServerError, fmt.Sprintf(
- "TheBlueAlliance data for match %d is malformed: %v", match.MatchNumber, err))
- return
- }
-
- team_matches := []db.TeamMatch{
- {
- MatchNumber: int32(match.MatchNumber),
- SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
- Alliance: "R", AlliancePosition: 1, TeamNumber: red[0],
- },
- {
- MatchNumber: int32(match.MatchNumber),
- SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
- Alliance: "R", AlliancePosition: 2, TeamNumber: red[1],
- },
- {
- MatchNumber: int32(match.MatchNumber),
- SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
- Alliance: "R", AlliancePosition: 3, TeamNumber: red[2],
- },
- {
- MatchNumber: int32(match.MatchNumber),
- SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
- Alliance: "B", AlliancePosition: 1, TeamNumber: blue[0],
- },
- {
- MatchNumber: int32(match.MatchNumber),
- SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
- Alliance: "B", AlliancePosition: 2, TeamNumber: blue[1],
- },
- {
- MatchNumber: int32(match.MatchNumber),
- SetNumber: int32(match.SetNumber), CompLevel: match.CompLevel,
- Alliance: "B", AlliancePosition: 3, TeamNumber: blue[2],
- },
- }
-
- for _, match := range team_matches {
- // Iterate through matches to check they can be added to database.
- err = handler.db.AddToMatch(match)
- if err != nil {
- respondWithError(w, http.StatusInternalServerError, fmt.Sprintf(
- "Failed to add team %d from match %d to the database: %v", match.TeamNumber, match.MatchNumber, err))
- return
- }
- }
- }
-
- var response RefreshMatchListResponseT
- builder := flatbuffers.NewBuilder(1024)
- builder.Finish((&response).Pack(builder))
- w.Write(builder.FinishedBytes())
-}
-
type submitNoteScoutingHandler struct {
db Database
}
@@ -829,14 +676,13 @@
w.Write(builder.FinishedBytes())
}
-func HandleRequests(db Database, scrape ScrapeMatchList, scoutingServer server.ScoutingServer) {
+func HandleRequests(db Database, scoutingServer server.ScoutingServer) {
scoutingServer.HandleFunc("/requests", unknown)
scoutingServer.Handle("/requests/submit/data_scouting", submitDataScoutingHandler{db})
scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db})
scoutingServer.Handle("/requests/request/all_notes", requestAllNotesHandler{db})
scoutingServer.Handle("/requests/request/all_driver_rankings", requestAllDriverRankingsHandler{db})
scoutingServer.Handle("/requests/request/data_scouting", requestDataScoutingHandler{db})
- scoutingServer.Handle("/requests/refresh_match_list", refreshMatchListHandler{db, scrape})
scoutingServer.Handle("/requests/submit/submit_notes", submitNoteScoutingHandler{db})
scoutingServer.Handle("/requests/request/notes_for_team", requestNotesForTeamHandler{db})
scoutingServer.Handle("/requests/submit/shift_schedule", submitShiftScheduleHandler{db})
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index 27a45e6..ee22022 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -8,11 +8,8 @@
"testing"
"github.com/frc971/971-Robot-Code/scouting/db"
- "github.com/frc971/971-Robot-Code/scouting/scraping"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/debug"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
- "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list"
- "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches"
@@ -37,7 +34,7 @@
func Test404(t *testing.T) {
db := MockDatabase{}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -54,7 +51,7 @@
func TestSubmitDataScoutingError(t *testing.T) {
db := MockDatabase{}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -82,7 +79,7 @@
func TestSubmitDataScouting(t *testing.T) {
db := MockDatabase{}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -201,7 +198,7 @@
},
}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -267,7 +264,7 @@
},
}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -322,7 +319,7 @@
func TestSubmitNotes(t *testing.T) {
database := MockDatabase{}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&database, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&database, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -375,7 +372,7 @@
}},
}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&database, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&database, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -417,7 +414,7 @@
},
}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -464,7 +461,7 @@
func TestSubmitShiftSchedule(t *testing.T) {
database := MockDatabase{}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&database, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&database, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -500,98 +497,10 @@
}
}
-// Validates that we can download the schedule from The Blue Alliance.
-func TestRefreshMatchList(t *testing.T) {
- scrapeMockSchedule := func(int32, string) ([]scraping.Match, error) {
- return []scraping.Match{
- {
- CompLevel: "qual",
- MatchNumber: 1,
- SetNumber: 2,
- Alliances: scraping.Alliances{
- Red: scraping.Alliance{
- TeamKeys: []string{
- "100",
- "200",
- "300",
- },
- },
- Blue: scraping.Alliance{
- TeamKeys: []string{
- "101",
- "201",
- "301",
- },
- },
- },
- WinningAlliance: "",
- EventKey: "",
- Time: 0,
- PredictedTime: 0,
- ActualTime: 0,
- PostResultTime: 0,
- ScoreBreakdowns: scraping.ScoreBreakdowns{},
- },
- }, nil
- }
-
- database := MockDatabase{}
- scoutingServer := server.NewScoutingServer()
- HandleRequests(&database, scrapeMockSchedule, scoutingServer)
- scoutingServer.Start(8080)
- defer scoutingServer.Stop()
-
- builder := flatbuffers.NewBuilder(1024)
- builder.Finish((&refresh_match_list.RefreshMatchListT{}).Pack(builder))
-
- response, err := debug.RefreshMatchList("http://localhost:8080", builder.FinishedBytes())
- if err != nil {
- t.Fatal("Failed to request all matches: ", err)
- }
-
- // Validate the response.
- expected := refresh_match_list_response.RefreshMatchListResponseT{}
- if !reflect.DeepEqual(expected, *response) {
- t.Fatal("Expected ", expected, ", but got ", *response)
- }
-
- // Make sure that the data made it into the database.
- expectedMatches := []db.TeamMatch{
- {
- MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
- Alliance: "R", AlliancePosition: 1, TeamNumber: 100,
- },
- {
- MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
- Alliance: "R", AlliancePosition: 2, TeamNumber: 200,
- },
- {
- MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
- Alliance: "R", AlliancePosition: 3, TeamNumber: 300,
- },
- {
- MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
- Alliance: "B", AlliancePosition: 1, TeamNumber: 101,
- },
- {
- MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
- Alliance: "B", AlliancePosition: 2, TeamNumber: 201,
- },
- {
- MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
- Alliance: "B", AlliancePosition: 3, TeamNumber: 301,
- },
- }
-
- if !reflect.DeepEqual(expectedMatches, database.matches) {
- t.Fatal("Expected ", expectedMatches, ", but got ", database.matches)
- }
-}
-
func TestSubmitDriverRanking(t *testing.T) {
database := MockDatabase{}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&database, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&database, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -636,7 +545,7 @@
},
}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -701,7 +610,7 @@
},
}
scoutingServer := server.NewScoutingServer()
- HandleRequests(&db, scrapeEmtpyMatchList, scoutingServer)
+ HandleRequests(&db, scoutingServer)
scoutingServer.Start(8080)
defer scoutingServer.Stop()
@@ -820,8 +729,3 @@
func (database *MockDatabase) ReturnAllDriverRankings() ([]db.DriverRankingData, error) {
return database.driver_ranking, nil
}
-
-// Returns an empty match list from the fake The Blue Alliance scraping.
-func scrapeEmtpyMatchList(int32, string) ([]scraping.Match, error) {
- return nil, nil
-}