blob: 625157ae301c5395922d3d081908bfcc87961b2f [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 {
Yash Chainani37261d42022-04-19 16:21:27 -070016 ApiKey string `json:"api_key"`
17 BaseUrl string `json:"base_url"`
18 Year int32 `json:"year"`
19 EventCode string `json:"event_code"`
Het Satasiyac6df3322022-02-05 14:12:30 -080020}
21
Yash Chainani4e2b6462022-03-26 15:23:17 -070022// Takes in year and FIRST event code and returns requested information according to TBA.
Het Satasiyac6df3322022-02-05 14:12:30 -080023// Also takes in a file path to the JSON config file that contains your TBA API key.
24// It defaults to <workspace root>/config.json
25// the config is expected to have the following contents:
26//{
27// api_key:"myTBAapiKey"
28//}
Yash Chainani4e2b6462022-03-26 15:23:17 -070029func getJson(year int32, eventCode, configPath, category string) ([]byte, error) {
Philipp Schraderd3fac192022-03-02 20:35:46 -080030 if configPath == "" {
31 configPath = os.Getenv("BUILD_WORKSPACE_DIRECTORY") + "/scouting_config.json"
Het Satasiyac6df3322022-02-05 14:12:30 -080032 }
Philipp Schraderd3fac192022-03-02 20:35:46 -080033
Het Satasiyac6df3322022-02-05 14:12:30 -080034 // Takes the filepath and grabs the api key from the json.
Philipp Schraderd3fac192022-03-02 20:35:46 -080035 content, err := ioutil.ReadFile(configPath)
Het Satasiyac6df3322022-02-05 14:12:30 -080036 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080037 return nil, errors.New(fmt.Sprint("Failed to open config at ", configPath, ": ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080038 }
39 // Parses the JSON parameters into a struct.
Philipp Schraderd3fac192022-03-02 20:35:46 -080040 var config scrapingConfig
41 if err := json.Unmarshal([]byte(content), &config); err != nil {
42 return nil, errors.New(fmt.Sprint("Failed to parse config file as JSON: ", err))
43 }
44
45 // Perform some basic validation on the data.
46 if config.ApiKey == "" {
47 return nil, errors.New("Missing 'api_key' in config JSON.")
48 }
49 if config.BaseUrl == "" {
50 config.BaseUrl = "https://www.thebluealliance.com"
Het Satasiyac6df3322022-02-05 14:12:30 -080051 }
Yash Chainani37261d42022-04-19 16:21:27 -070052 if config.Year == 0 {
53 config.Year = year
54 }
55 if config.EventCode == "" {
56 config.EventCode = eventCode
57 }
Het Satasiyac6df3322022-02-05 14:12:30 -080058
59 // Create the TBA event key for the year and event code.
Yash Chainani37261d42022-04-19 16:21:27 -070060 eventKey := strconv.Itoa(int(config.Year)) + config.EventCode
Het Satasiyac6df3322022-02-05 14:12:30 -080061
62 // Create a get request for the match info.
Yash Chainani4e2b6462022-03-26 15:23:17 -070063 req, err := http.NewRequest("GET", config.BaseUrl+"/api/v3/event/"+eventKey+"/"+category, nil)
Het Satasiyac6df3322022-02-05 14:12:30 -080064 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080065 return nil, errors.New(fmt.Sprint("Failed to build http request: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080066 }
67
68 // Add the auth key header to the request.
Philipp Schraderd3fac192022-03-02 20:35:46 -080069 req.Header.Add("X-TBA-Auth-Key", config.ApiKey)
Het Satasiyac6df3322022-02-05 14:12:30 -080070
Philipp Schraderd3fac192022-03-02 20:35:46 -080071 // Make the API request.
72 client := &http.Client{}
Het Satasiyac6df3322022-02-05 14:12:30 -080073 resp, err := client.Do(req)
Het Satasiyac6df3322022-02-05 14:12:30 -080074 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080075 return nil, errors.New(fmt.Sprint("Failed to make TBA API request: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080076 }
77
Het Satasiyac6df3322022-02-05 14:12:30 -080078 defer resp.Body.Close()
Philipp Schraderd3fac192022-03-02 20:35:46 -080079 if resp.StatusCode != 200 {
80 return nil, errors.New(fmt.Sprint("Got unexpected status code from TBA API request: ", resp.Status))
81 }
Het Satasiyac6df3322022-02-05 14:12:30 -080082
83 // Get all bytes from response body.
84 bodyBytes, err := ioutil.ReadAll(resp.Body)
85 if err != nil {
Philipp Schraderd3fac192022-03-02 20:35:46 -080086 return nil, errors.New(fmt.Sprint("Failed to read TBA API response: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -080087 }
88
Yash Chainani4e2b6462022-03-26 15:23:17 -070089 return bodyBytes, nil
90}
91
92// Return all matches in event according to TBA
93func AllMatches(year int32, eventCode, configPath string) ([]Match, error) {
94 bodyBytes, err := getJson(year, eventCode, configPath, "matches")
95
96 if err != nil {
97 return nil, err
98 }
99
Het Satasiyac6df3322022-02-05 14:12:30 -0800100 var matches []Match
101 // Unmarshal json into go usable format.
Philipp Schraderd3fac192022-03-02 20:35:46 -0800102 if err := json.Unmarshal([]byte(bodyBytes), &matches); err != nil {
103 return nil, errors.New(fmt.Sprint("Failed to parse JSON received from TBA: ", err))
Het Satasiyac6df3322022-02-05 14:12:30 -0800104 }
105
106 return matches, nil
107}
Yash Chainani4e2b6462022-03-26 15:23:17 -0700108
109// Return event rankings according to TBA
110func AllRankings(year int32, eventCode, configPath string) (EventRanking, error) {
111 bodyBytes, err := getJson(year, eventCode, configPath, "rankings")
112
113 if err != nil {
114 return EventRanking{}, err
115 }
116
117 var rankings EventRanking
118 // Unmarshal json into go usable format.
119 if err := json.Unmarshal([]byte(bodyBytes), &rankings); err != nil {
120 return EventRanking{}, errors.New(fmt.Sprint("Failed to parse JSON received from TBA: ", err))
121 }
122
123 return rankings, nil
124}