| package scraping |
| |
| // A library to grab match data from The Blue Alliance. |
| import ( |
| "encoding/json" |
| "errors" |
| "fmt" |
| "io/ioutil" |
| "net/http" |
| "os" |
| "strconv" |
| ) |
| |
| // Stores the TBA API key to access the API. |
| type scrapingConfig struct { |
| ApiKey string `json:"api_key"` |
| BaseUrl string `json:"base_url"` |
| Year int32 `json:"year"` |
| EventCode string `json:"event_code"` |
| } |
| |
| // Takes in year and FIRST event code and returns requested information according to TBA. |
| // Also takes in a file path to the JSON config file that contains your TBA API key. |
| // It defaults to <workspace root>/config.json |
| // the config is expected to have the following contents: |
| //{ |
| // api_key:"myTBAapiKey" |
| //} |
| func getJson(year int32, eventCode, configPath, category string) ([]byte, error) { |
| if configPath == "" { |
| configPath = os.Getenv("BUILD_WORKSPACE_DIRECTORY") + "/scouting_config.json" |
| } |
| |
| // Takes the filepath and grabs the api key from the json. |
| content, err := ioutil.ReadFile(configPath) |
| if err != nil { |
| return nil, errors.New(fmt.Sprint("Failed to open config at ", configPath, ": ", err)) |
| } |
| // Parses the JSON parameters into a struct. |
| var config scrapingConfig |
| if err := json.Unmarshal([]byte(content), &config); err != nil { |
| return nil, errors.New(fmt.Sprint("Failed to parse config file as JSON: ", err)) |
| } |
| |
| // Perform some basic validation on the data. |
| if config.ApiKey == "" { |
| return nil, errors.New("Missing 'api_key' in config JSON.") |
| } |
| if config.BaseUrl == "" { |
| config.BaseUrl = "https://www.thebluealliance.com" |
| } |
| if config.Year == 0 { |
| config.Year = year |
| } |
| if config.EventCode == "" { |
| config.EventCode = eventCode |
| } |
| |
| // Create the TBA event key for the year and event code. |
| eventKey := strconv.Itoa(int(config.Year)) + config.EventCode |
| |
| // Create a get request for the match info. |
| req, err := http.NewRequest("GET", config.BaseUrl+"/api/v3/event/"+eventKey+"/"+category, nil) |
| if err != nil { |
| return nil, errors.New(fmt.Sprint("Failed to build http request: ", err)) |
| } |
| |
| // Add the auth key header to the request. |
| req.Header.Add("X-TBA-Auth-Key", config.ApiKey) |
| |
| // Make the API request. |
| client := &http.Client{} |
| resp, err := client.Do(req) |
| if err != nil { |
| return nil, errors.New(fmt.Sprint("Failed to make TBA API request: ", err)) |
| } |
| |
| defer resp.Body.Close() |
| if resp.StatusCode != 200 { |
| return nil, errors.New(fmt.Sprint("Got unexpected status code from TBA API request: ", resp.Status)) |
| } |
| |
| // Get all bytes from response body. |
| bodyBytes, err := ioutil.ReadAll(resp.Body) |
| if err != nil { |
| return nil, errors.New(fmt.Sprint("Failed to read TBA API response: ", err)) |
| } |
| |
| return bodyBytes, nil |
| } |
| |
| func GetAllData[T interface{}](year int32, eventCode, configPath string, category string) (T, error) { |
| var result T |
| bodyBytes, err := getJson(year, eventCode, configPath, category) |
| if err != nil { |
| return result, err |
| } |
| |
| // Unmarshal the JSON data into the in-memory format. |
| if err = json.Unmarshal([]byte(bodyBytes), &result); err != nil { |
| return result, errors.New(fmt.Sprint("Failed to parse ", category, " JSON received from TBA: ", err)) |
| } |
| |
| return result, nil |
| } |