blob: 19426cf30670d5209c9112c07f42b6b836924bc9 [file] [log] [blame]
Het Satasiyac6df3322022-02-05 14:12:30 -08001package scraping
2
3// A library to grab match data from The Blue Alliance.
4import (
5 "encoding/json"
6 "errors"
Philipp Schraderd3fac192022-03-02 20:35:46 -08007 "fmt"
Het Satasiyac6df3322022-02-05 14:12:30 -08008 "io/ioutil"
Het Satasiyac6df3322022-02-05 14:12:30 -08009 "net/http"
10 "os"
Philipp Schraderd3fac192022-03-02 20:35:46 -080011 "strconv"
Het Satasiyac6df3322022-02-05 14:12:30 -080012)
13
14// Stores the TBA API key to access the API.
Philipp Schraderd3fac192022-03-02 20:35:46 -080015type scrapingConfig struct {
16 ApiKey string `json:"api_key"`
17 BaseUrl string `json:"base_url"`
Het Satasiyac6df3322022-02-05 14:12:30 -080018}
19
Yash Chainani4e2b6462022-03-26 15:23:17 -070020// Takes in year and FIRST event code and returns requested information according to TBA.
Het Satasiyac6df3322022-02-05 14:12:30 -080021// Also takes in a file path to the JSON config file that contains your TBA API key.
22// It defaults to <workspace root>/config.json
23// the config is expected to have the following contents:
24//{
25// api_key:"myTBAapiKey"
26//}
Yash Chainani4e2b6462022-03-26 15:23:17 -070027func getJson(year int32, eventCode, configPath, category string) ([]byte, error) {
Philipp Schraderd3fac192022-03-02 20:35:46 -080028 if configPath == "" {
29 configPath = os.Getenv("BUILD_WORKSPACE_DIRECTORY") + "/scouting_config.json"
Het Satasiyac6df3322022-02-05 14:12:30 -080030 }
Philipp Schraderd3fac192022-03-02 20:35:46 -080031
Het Satasiyac6df3322022-02-05 14:12:30 -080032 // Takes the filepath and grabs the api key from the json.
Philipp Schraderd3fac192022-03-02 20:35:46 -080033 content, err := ioutil.ReadFile(configPath)
Het Satasiyac6df3322022-02-05 14:12:30 -080034 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080035 return nil, errors.New(fmt.Sprint("Failed to open config at ", configPath, ": ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080036 }
37 // Parses the JSON parameters into a struct.
Philipp Schraderd3fac192022-03-02 20:35:46 -080038 var config scrapingConfig
39 if err := json.Unmarshal([]byte(content), &config); err != nil {
40 return nil, errors.New(fmt.Sprint("Failed to parse config file as JSON: ", err))
41 }
42
43 // Perform some basic validation on the data.
44 if config.ApiKey == "" {
45 return nil, errors.New("Missing 'api_key' in config JSON.")
46 }
47 if config.BaseUrl == "" {
48 config.BaseUrl = "https://www.thebluealliance.com"
Het Satasiyac6df3322022-02-05 14:12:30 -080049 }
50
51 // Create the TBA event key for the year and event code.
Philipp Schraderd3fac192022-03-02 20:35:46 -080052 eventKey := strconv.Itoa(int(year)) + eventCode
Het Satasiyac6df3322022-02-05 14:12:30 -080053
54 // Create a get request for the match info.
Yash Chainani4e2b6462022-03-26 15:23:17 -070055 req, err := http.NewRequest("GET", config.BaseUrl+"/api/v3/event/"+eventKey+"/"+category, nil)
Het Satasiyac6df3322022-02-05 14:12:30 -080056 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080057 return nil, errors.New(fmt.Sprint("Failed to build http request: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080058 }
59
60 // Add the auth key header to the request.
Philipp Schraderd3fac192022-03-02 20:35:46 -080061 req.Header.Add("X-TBA-Auth-Key", config.ApiKey)
Het Satasiyac6df3322022-02-05 14:12:30 -080062
Philipp Schraderd3fac192022-03-02 20:35:46 -080063 // Make the API request.
64 client := &http.Client{}
Het Satasiyac6df3322022-02-05 14:12:30 -080065 resp, err := client.Do(req)
Het Satasiyac6df3322022-02-05 14:12:30 -080066 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080067 return nil, errors.New(fmt.Sprint("Failed to make TBA API request: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080068 }
69
Het Satasiyac6df3322022-02-05 14:12:30 -080070 defer resp.Body.Close()
Philipp Schraderd3fac192022-03-02 20:35:46 -080071 if resp.StatusCode != 200 {
72 return nil, errors.New(fmt.Sprint("Got unexpected status code from TBA API request: ", resp.Status))
73 }
Het Satasiyac6df3322022-02-05 14:12:30 -080074
75 // Get all bytes from response body.
76 bodyBytes, err := ioutil.ReadAll(resp.Body)
77 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080078 return nil, errors.New(fmt.Sprint("Failed to read TBA API response: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080079 }
80
Yash Chainani4e2b6462022-03-26 15:23:17 -070081 return bodyBytes, nil
82}
83
84// Return all matches in event according to TBA
85func AllMatches(year int32, eventCode, configPath string) ([]Match, error) {
86 bodyBytes, err := getJson(year, eventCode, configPath, "matches")
87
88 if err != nil {
89 return nil, err
90 }
91
Het Satasiyac6df3322022-02-05 14:12:30 -080092 var matches []Match
93 // Unmarshal json into go usable format.
Philipp Schraderd3fac192022-03-02 20:35:46 -080094 if err := json.Unmarshal([]byte(bodyBytes), &matches); err != nil {
95 return nil, errors.New(fmt.Sprint("Failed to parse JSON received from TBA: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080096 }
97
98 return matches, nil
99}
Yash Chainani4e2b6462022-03-26 15:23:17 -0700100
101// Return event rankings according to TBA
102func AllRankings(year int32, eventCode, configPath string) (EventRanking, error) {
103 bodyBytes, err := getJson(year, eventCode, configPath, "rankings")
104
105 if err != nil {
106 return EventRanking{}, err
107 }
108
109 var rankings EventRanking
110 // Unmarshal json into go usable format.
111 if err := json.Unmarshal([]byte(bodyBytes), &rankings); err != nil {
112 return EventRanking{}, errors.New(fmt.Sprint("Failed to parse JSON received from TBA: ", err))
113 }
114
115 return rankings, nil
116}