blob: 88b4eac0198bdf1e551711e9b6544e0431f7abed [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
Filip Kujawac1ded372023-05-27 14:33:43 -070012 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2023_data_scouting_response"
Emily Markova8cb91312024-02-02 12:30:37 -080013 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2024_data_scouting_response"
Philipp Schraderd9096a32022-02-24 17:53:09 -080014 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Emily Markova290147d2023-03-03 22:40:06 -080015 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_data_scouting_response"
Emily Markova8cb91312024-02-02 12:30:37 -080016 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080017 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080018 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080019 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
Emily Markova8e39f452023-12-23 12:17:30 -080020 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response"
Emily Markova521725a2024-03-21 18:46:04 -070021 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_current_scouting_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070022 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070023 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070024 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
Emily Markova8cb91312024-02-02 12:30:37 -080025 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_2024_actions_response"
Sabina Leaver9b4eb312023-02-20 19:58:17 -080026 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response"
Filip Kujawa210a03b2022-11-24 14:41:11 -080027 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070028 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070029 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070030 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
Philipp Schrader86bf2b92022-03-30 20:57:30 -070031 flatbuffers "github.com/google/flatbuffers/go"
Philipp Schraderd9096a32022-02-24 17:53:09 -080032)
33
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070034// The username to submit the various requests as.
35const DefaultUsername = "debug_cli"
36
Emily Markova521725a2024-03-21 18:46:04 -070037// TODO: Make the username an argument of the Request* functions.
38var Username = DefaultUsername
39
Philipp Schraderd9096a32022-02-24 17:53:09 -080040// A struct that can be used as an `error`. It contains information about the
41// why the server was unhappy and what the corresponding request was.
42type ResponseError struct {
43 Url string
44 StatusCode int
45 ErrorResponse *error_response.ErrorResponse
46}
47
48// Required to implement the `error` interface.
49func (err *ResponseError) Error() string {
50 return fmt.Sprintf(
51 "%s returned %d %s: %s", err.Url, err.StatusCode,
52 http.StatusText(err.StatusCode), err.ErrorResponse.ErrorMessage())
53}
54
55// Parse an `ErrorResponse` message that the server sent back. This happens
56// whenever the status code is something other than 200. If the message is
57// successfully parsed, it's turned into a `ResponseError` which implements the
58// `error` interface.
59func parseErrorResponse(url string, statusCode int, responseBytes []byte) error {
60 getRootErrMessage := ""
61 defer func() {
62 if r := recover(); r != nil {
63 getRootErrMessage = fmt.Sprintf("%v", r)
64 }
65 }()
66 errorMessage := error_response.GetRootAsErrorResponse(responseBytes, 0)
67 if getRootErrMessage != "" {
68 return errors.New(fmt.Sprintf(
69 "Failed to parse response from %s with status %d %s (bytes %v) as ErrorResponse: %s",
70 url, statusCode, http.StatusText(statusCode), responseBytes, getRootErrMessage))
71 }
72
73 return &ResponseError{
74 Url: url,
75 StatusCode: statusCode,
76 ErrorResponse: errorMessage,
77 }
78}
79
80// Performs a POST request with the specified payload. The bytes that the
81// server responds with are returned.
82func performPost(url string, requestBytes []byte) ([]byte, error) {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070083 req, err := http.NewRequest("POST", url, bytes.NewReader(requestBytes))
84 if err != nil {
85 log.Printf("Failed to create a new POST request to %s: %v", url, err)
86 return nil, err
87 }
88 req.Header.Add("Authorization", "Basic "+
Emily Markova521725a2024-03-21 18:46:04 -070089 base64.StdEncoding.EncodeToString([]byte(Username+":")))
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070090
91 client := &http.Client{}
92 resp, err := client.Do(req)
Philipp Schraderd9096a32022-02-24 17:53:09 -080093 if err != nil {
94 log.Printf("Failed to send POST request to %s: %v", url, err)
95 return nil, err
96 }
97 responseBytes, err := io.ReadAll(resp.Body)
98 if err != nil {
99 log.Printf("Failed to parse response bytes from POST to %s: %v", url, err)
100 return nil, err
101 }
102 if resp.StatusCode != http.StatusOK {
103 return nil, parseErrorResponse(url, resp.StatusCode, responseBytes)
104 }
105 return responseBytes, nil
106}
107
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700108// Sends a message to the server and returns the deserialized response.
109// The first generic argument must be specified.
110func sendMessage[FbT interface{}, Fb interface{ UnPack() *FbT }](url string, requestBytes []byte, parser func([]byte, flatbuffers.UOffsetT) Fb) (*FbT, error) {
111 responseBytes, err := performPost(url, requestBytes)
112 if err != nil {
113 return nil, err
114 }
115 response := parser(responseBytes, 0)
116 return response.UnPack(), nil
117}
118
Philipp Schrader20440f82022-03-16 20:07:09 -0700119func RequestAllMatches(server string, requestBytes []byte) (*request_all_matches_response.RequestAllMatchesResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700120 return sendMessage[request_all_matches_response.RequestAllMatchesResponseT](
121 server+"/requests/request/all_matches", requestBytes,
122 request_all_matches_response.GetRootAsRequestAllMatchesResponse)
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800123}
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800124
Filip Kujawaf882e022022-12-14 13:14:08 -0800125func RequestAllDriverRankings(server string, requestBytes []byte) (*request_all_driver_rankings_response.RequestAllDriverRankingsResponseT, error) {
126 return sendMessage[request_all_driver_rankings_response.RequestAllDriverRankingsResponseT](
127 server+"/requests/request/all_driver_rankings", requestBytes,
128 request_all_driver_rankings_response.GetRootAsRequestAllDriverRankingsResponse)
129}
130
Emily Markova290147d2023-03-03 22:40:06 -0800131func Request2023DataScouting(server string, requestBytes []byte) (*request_2023_data_scouting_response.Request2023DataScoutingResponseT, error) {
132 return sendMessage[request_2023_data_scouting_response.Request2023DataScoutingResponseT](
133 server+"/requests/request/2023_data_scouting", requestBytes,
134 request_2023_data_scouting_response.GetRootAsRequest2023DataScoutingResponse)
135}
136
Emily Markova8cb91312024-02-02 12:30:37 -0800137func Request2024DataScouting(server string, requestBytes []byte) (*request_2024_data_scouting_response.Request2024DataScoutingResponseT, error) {
138 return sendMessage[request_2024_data_scouting_response.Request2024DataScoutingResponseT](
139 server+"/requests/request/2024_data_scouting", requestBytes,
140 request_2024_data_scouting_response.GetRootAsRequest2024DataScoutingResponse)
141}
142
Alex Perry81f96ba2022-03-13 18:26:19 -0700143func SubmitNotes(server string, requestBytes []byte) (*submit_notes_response.SubmitNotesResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700144 return sendMessage[submit_notes_response.SubmitNotesResponseT](
145 server+"/requests/submit/submit_notes", requestBytes,
146 submit_notes_response.GetRootAsSubmitNotesResponse)
Alex Perry81f96ba2022-03-13 18:26:19 -0700147}
148
149func RequestNotes(server string, requestBytes []byte) (*request_notes_for_team_response.RequestNotesForTeamResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700150 return sendMessage[request_notes_for_team_response.RequestNotesForTeamResponseT](
151 server+"/requests/request/notes_for_team", requestBytes,
152 request_notes_for_team_response.GetRootAsRequestNotesForTeamResponse)
Alex Perry81f96ba2022-03-13 18:26:19 -0700153}
Milo Lin1d59f0c2022-06-22 20:30:58 -0700154
Emily Markovafaecfe12023-07-01 12:40:03 -0700155func RequestPitImages(server string, requestBytes []byte) (*request_pit_images_response.RequestPitImagesResponseT, error) {
156 return sendMessage[request_pit_images_response.RequestPitImagesResponseT](
157 server+"/requests/request/pit_images", requestBytes,
158 request_pit_images_response.GetRootAsRequestPitImagesResponse)
159}
160
Emily Markova8e39f452023-12-23 12:17:30 -0800161func RequestAllPitImages(server string, requestBytes []byte) (*request_all_pit_images_response.RequestAllPitImagesResponseT, error) {
162 return sendMessage[request_all_pit_images_response.RequestAllPitImagesResponseT](
163 server+"/requests/request/all_pit_images", requestBytes,
164 request_all_pit_images_response.GetRootAsRequestAllPitImagesResponse)
165}
166
Filip Kujawaf882e022022-12-14 13:14:08 -0800167func RequestAllNotes(server string, requestBytes []byte) (*request_all_notes_response.RequestAllNotesResponseT, error) {
168 return sendMessage[request_all_notes_response.RequestAllNotesResponseT](
169 server+"/requests/request/all_notes", requestBytes,
170 request_all_notes_response.GetRootAsRequestAllNotesResponse)
171}
172
Milo Lin1d59f0c2022-06-22 20:30:58 -0700173func RequestShiftSchedule(server string, requestBytes []byte) (*request_shift_schedule_response.RequestShiftScheduleResponseT, error) {
174 return sendMessage[request_shift_schedule_response.RequestShiftScheduleResponseT](
175 server+"/requests/request/shift_schedule", requestBytes,
176 request_shift_schedule_response.GetRootAsRequestShiftScheduleResponse)
177}
178
Emily Markova521725a2024-03-21 18:46:04 -0700179func RequestCurrentScouting(server string, requestBytes []byte) (*request_current_scouting_response.RequestCurrentScoutingResponseT, error) {
180 return sendMessage[request_current_scouting_response.RequestCurrentScoutingResponseT](
181 server+"/requests/request/current_scouting", requestBytes,
182 request_current_scouting_response.GetRootAsRequestCurrentScoutingResponse)
183}
184
Milo Lin1d59f0c2022-06-22 20:30:58 -0700185func SubmitShiftSchedule(server string, requestBytes []byte) (*submit_shift_schedule_response.SubmitShiftScheduleResponseT, error) {
186 return sendMessage[submit_shift_schedule_response.SubmitShiftScheduleResponseT](
187 server+"/requests/submit/shift_schedule", requestBytes,
188 submit_shift_schedule_response.GetRootAsSubmitShiftScheduleResponse)
189}
Filip Kujawa210a03b2022-11-24 14:41:11 -0800190
191func SubmitDriverRanking(server string, requestBytes []byte) (*submit_driver_ranking_response.SubmitDriverRankingResponseT, error) {
192 return sendMessage[submit_driver_ranking_response.SubmitDriverRankingResponseT](
193 server+"/requests/submit/submit_driver_ranking", requestBytes,
194 submit_driver_ranking_response.GetRootAsSubmitDriverRankingResponse)
195}
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800196
Emily Markova8cb91312024-02-02 12:30:37 -0800197func Submit2024Actions(server string, requestBytes []byte) (*submit_2024_actions_response.Submit2024ActionsResponseT, error) {
198 return sendMessage[submit_2024_actions_response.Submit2024ActionsResponseT](
199 server+"/requests/submit/submit_2024_actions", requestBytes,
200 submit_2024_actions_response.GetRootAsSubmit2024ActionsResponse)
201}
202
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800203func SubmitActions(server string, requestBytes []byte) (*submit_actions_response.SubmitActionsResponseT, error) {
204 return sendMessage[submit_actions_response.SubmitActionsResponseT](
205 server+"/requests/submit/submit_actions", requestBytes,
206 submit_actions_response.GetRootAsSubmitActionsResponse)
207}
Filip Kujawac1ded372023-05-27 14:33:43 -0700208
Emily Markovafaecfe12023-07-01 12:40:03 -0700209func SubmitPitImage(server string, requestBytes []byte) (*submit_pit_image_response.SubmitPitImageResponseT, error) {
210 return sendMessage[submit_pit_image_response.SubmitPitImageResponseT](
211 server+"/requests/submit/submit_pit_image", requestBytes,
212 submit_pit_image_response.GetRootAsSubmitPitImageResponse)
213}
214
Filip Kujawac1ded372023-05-27 14:33:43 -0700215func Delete2023DataScouting(server string, requestBytes []byte) (*delete_2023_data_scouting_response.Delete2023DataScoutingResponseT, error) {
216 return sendMessage[delete_2023_data_scouting_response.Delete2023DataScoutingResponseT](
217 server+"/requests/delete/delete_2023_data_scouting", requestBytes,
218 delete_2023_data_scouting_response.GetRootAsDelete2023DataScoutingResponse)
219}
Emily Markova8cb91312024-02-02 12:30:37 -0800220
221func Delete2024DataScouting(server string, requestBytes []byte) (*delete_2024_data_scouting_response.Delete2024DataScoutingResponseT, error) {
222 return sendMessage[delete_2024_data_scouting_response.Delete2024DataScoutingResponseT](
223 server+"/requests/delete/delete_2024_data_scouting", requestBytes,
224 delete_2024_data_scouting_response.GetRootAsDelete2024DataScoutingResponse)
225}