blob: 63ece723edcd573079623e5ff345e88455b42b12 [file] [log] [blame]
Philipp Schraderd9096a32022-02-24 17:53:09 -08001package debug
2
3import (
4 "bytes"
Philipp Schraderfae8a7e2022-03-13 22:51:54 -07005 "encoding/base64"
Philipp Schraderd9096a32022-02-24 17:53:09 -08006 "errors"
7 "fmt"
8 "io"
9 "log"
10 "net/http"
11
12 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Philipp Schraderd3fac192022-03-02 20:35:46 -080013 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_response"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080014 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
Philipp Schraderacf96232022-03-01 22:03:30 -080015 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting_response"
Philipp Schraderd1c4bef2022-02-28 22:51:30 -080016 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070017 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
Philipp Schraderd9096a32022-02-24 17:53:09 -080018 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070019 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
Philipp Schraderd9096a32022-02-24 17:53:09 -080020)
21
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070022// The username to submit the various requests as.
23const DefaultUsername = "debug_cli"
24
Philipp Schraderd9096a32022-02-24 17:53:09 -080025// A struct that can be used as an `error`. It contains information about the
26// why the server was unhappy and what the corresponding request was.
27type ResponseError struct {
28 Url string
29 StatusCode int
30 ErrorResponse *error_response.ErrorResponse
31}
32
33// Required to implement the `error` interface.
34func (err *ResponseError) Error() string {
35 return fmt.Sprintf(
36 "%s returned %d %s: %s", err.Url, err.StatusCode,
37 http.StatusText(err.StatusCode), err.ErrorResponse.ErrorMessage())
38}
39
40// Parse an `ErrorResponse` message that the server sent back. This happens
41// whenever the status code is something other than 200. If the message is
42// successfully parsed, it's turned into a `ResponseError` which implements the
43// `error` interface.
44func parseErrorResponse(url string, statusCode int, responseBytes []byte) error {
45 getRootErrMessage := ""
46 defer func() {
47 if r := recover(); r != nil {
48 getRootErrMessage = fmt.Sprintf("%v", r)
49 }
50 }()
51 errorMessage := error_response.GetRootAsErrorResponse(responseBytes, 0)
52 if getRootErrMessage != "" {
53 return errors.New(fmt.Sprintf(
54 "Failed to parse response from %s with status %d %s (bytes %v) as ErrorResponse: %s",
55 url, statusCode, http.StatusText(statusCode), responseBytes, getRootErrMessage))
56 }
57
58 return &ResponseError{
59 Url: url,
60 StatusCode: statusCode,
61 ErrorResponse: errorMessage,
62 }
63}
64
65// Performs a POST request with the specified payload. The bytes that the
66// server responds with are returned.
67func performPost(url string, requestBytes []byte) ([]byte, error) {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070068 req, err := http.NewRequest("POST", url, bytes.NewReader(requestBytes))
69 if err != nil {
70 log.Printf("Failed to create a new POST request to %s: %v", url, err)
71 return nil, err
72 }
73 req.Header.Add("Authorization", "Basic "+
74 base64.StdEncoding.EncodeToString([]byte(DefaultUsername+":")))
75
76 client := &http.Client{}
77 resp, err := client.Do(req)
Philipp Schraderd9096a32022-02-24 17:53:09 -080078 if err != nil {
79 log.Printf("Failed to send POST request to %s: %v", url, err)
80 return nil, err
81 }
82 responseBytes, err := io.ReadAll(resp.Body)
83 if err != nil {
84 log.Printf("Failed to parse response bytes from POST to %s: %v", url, err)
85 return nil, err
86 }
87 if resp.StatusCode != http.StatusOK {
88 return nil, parseErrorResponse(url, resp.StatusCode, responseBytes)
89 }
90 return responseBytes, nil
91}
92
93// Sends a `SubmitDataScouting` message to the server and returns the
94// deserialized response.
Philipp Schrader20440f82022-03-16 20:07:09 -070095func SubmitDataScouting(server string, requestBytes []byte) (*submit_data_scouting_response.SubmitDataScoutingResponseT, error) {
Philipp Schraderd9096a32022-02-24 17:53:09 -080096 responseBytes, err := performPost(server+"/requests/submit/data_scouting", requestBytes)
97 if err != nil {
98 return nil, err
99 }
100 log.Printf("Parsing SubmitDataScoutingResponse")
101 response := submit_data_scouting_response.GetRootAsSubmitDataScoutingResponse(responseBytes, 0)
102 return response.UnPack(), nil
103}
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800104
105// Sends a `RequestAllMatches` message to the server and returns the
106// deserialized response.
Philipp Schrader20440f82022-03-16 20:07:09 -0700107func RequestAllMatches(server string, requestBytes []byte) (*request_all_matches_response.RequestAllMatchesResponseT, error) {
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800108 responseBytes, err := performPost(server+"/requests/request/all_matches", requestBytes)
109 if err != nil {
110 return nil, err
111 }
112 log.Printf("Parsing RequestAllMatchesResponse")
113 response := request_all_matches_response.GetRootAsRequestAllMatchesResponse(responseBytes, 0)
114 return response.UnPack(), nil
115}
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800116
117// Sends a `RequestMatchesForTeam` message to the server and returns the
118// deserialized response.
Philipp Schrader20440f82022-03-16 20:07:09 -0700119func RequestMatchesForTeam(server string, requestBytes []byte) (*request_matches_for_team_response.RequestMatchesForTeamResponseT, error) {
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800120 responseBytes, err := performPost(server+"/requests/request/matches_for_team", requestBytes)
121 if err != nil {
122 return nil, err
123 }
124 log.Printf("Parsing RequestMatchesForTeamResponse")
125 response := request_matches_for_team_response.GetRootAsRequestMatchesForTeamResponse(responseBytes, 0)
126 return response.UnPack(), nil
127}
Philipp Schraderacf96232022-03-01 22:03:30 -0800128
129// Sends a `RequestDataScouting` message to the server and returns the
130// deserialized response.
Philipp Schrader20440f82022-03-16 20:07:09 -0700131func RequestDataScouting(server string, requestBytes []byte) (*request_data_scouting_response.RequestDataScoutingResponseT, error) {
Philipp Schraderacf96232022-03-01 22:03:30 -0800132 responseBytes, err := performPost(server+"/requests/request/data_scouting", requestBytes)
133 if err != nil {
134 return nil, err
135 }
136 log.Printf("Parsing RequestDataScoutingResponse")
137 response := request_data_scouting_response.GetRootAsRequestDataScoutingResponse(responseBytes, 0)
138 return response.UnPack(), nil
139}
Philipp Schraderd3fac192022-03-02 20:35:46 -0800140
141// Sends a `RefreshMatchList` message to the server and returns the
142// deserialized response.
Philipp Schrader20440f82022-03-16 20:07:09 -0700143func RefreshMatchList(server string, requestBytes []byte) (*refresh_match_list_response.RefreshMatchListResponseT, error) {
Philipp Schraderd3fac192022-03-02 20:35:46 -0800144 responseBytes, err := performPost(server+"/requests/refresh_match_list", requestBytes)
145 if err != nil {
146 return nil, err
147 }
148 log.Printf("Parsing RefreshMatchListResponse")
149 response := refresh_match_list_response.GetRootAsRefreshMatchListResponse(responseBytes, 0)
150 return response.UnPack(), nil
151}
Alex Perry81f96ba2022-03-13 18:26:19 -0700152
153func SubmitNotes(server string, requestBytes []byte) (*submit_notes_response.SubmitNotesResponseT, error) {
154 responseBytes, err := performPost(server+"/requests/submit/submit_notes", requestBytes)
155 if err != nil {
156 return nil, err
157 }
158
159 response := submit_notes_response.GetRootAsSubmitNotesResponse(responseBytes, 0)
160 return response.UnPack(), nil
161}
162
163func RequestNotes(server string, requestBytes []byte) (*request_notes_for_team_response.RequestNotesForTeamResponseT, error) {
164 responseBytes, err := performPost(server+"/requests/request/notes_for_team", requestBytes)
165 if err != nil {
166 return nil, err
167 }
168
169 response := request_notes_for_team_response.GetRootAsRequestNotesForTeamResponse(responseBytes, 0)
170 return response.UnPack(), nil
171}