blob: 6b478ed20c85f583a871a3a969d29b172dceb81e [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
Emily Markova8cb91312024-02-02 12:30:37 -080012 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2024_data_scouting_response"
Philipp Schraderd9096a32022-02-24 17:53:09 -080013 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Emily Markova8cb91312024-02-02 12:30:37 -080014 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080015 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080016 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080017 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
Emily Markova8e39f452023-12-23 12:17:30 -080018 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response"
Emily Markova521725a2024-03-21 18:46:04 -070019 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_current_scouting_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070020 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070021 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070022 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
Emily Markova8cb91312024-02-02 12:30:37 -080023 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_2024_actions_response"
Filip Kujawa210a03b2022-11-24 14:41:11 -080024 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070025 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070026 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070027 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
Philipp Schrader86bf2b92022-03-30 20:57:30 -070028 flatbuffers "github.com/google/flatbuffers/go"
Philipp Schraderd9096a32022-02-24 17:53:09 -080029)
30
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070031// The username to submit the various requests as.
32const DefaultUsername = "debug_cli"
33
Emily Markova521725a2024-03-21 18:46:04 -070034// TODO: Make the username an argument of the Request* functions.
35var Username = DefaultUsername
36
Philipp Schraderd9096a32022-02-24 17:53:09 -080037// A struct that can be used as an `error`. It contains information about the
38// why the server was unhappy and what the corresponding request was.
39type ResponseError struct {
40 Url string
41 StatusCode int
42 ErrorResponse *error_response.ErrorResponse
43}
44
45// Required to implement the `error` interface.
46func (err *ResponseError) Error() string {
47 return fmt.Sprintf(
48 "%s returned %d %s: %s", err.Url, err.StatusCode,
49 http.StatusText(err.StatusCode), err.ErrorResponse.ErrorMessage())
50}
51
52// Parse an `ErrorResponse` message that the server sent back. This happens
53// whenever the status code is something other than 200. If the message is
54// successfully parsed, it's turned into a `ResponseError` which implements the
55// `error` interface.
56func parseErrorResponse(url string, statusCode int, responseBytes []byte) error {
57 getRootErrMessage := ""
58 defer func() {
59 if r := recover(); r != nil {
60 getRootErrMessage = fmt.Sprintf("%v", r)
61 }
62 }()
63 errorMessage := error_response.GetRootAsErrorResponse(responseBytes, 0)
64 if getRootErrMessage != "" {
65 return errors.New(fmt.Sprintf(
66 "Failed to parse response from %s with status %d %s (bytes %v) as ErrorResponse: %s",
67 url, statusCode, http.StatusText(statusCode), responseBytes, getRootErrMessage))
68 }
69
70 return &ResponseError{
71 Url: url,
72 StatusCode: statusCode,
73 ErrorResponse: errorMessage,
74 }
75}
76
77// Performs a POST request with the specified payload. The bytes that the
78// server responds with are returned.
79func performPost(url string, requestBytes []byte) ([]byte, error) {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070080 req, err := http.NewRequest("POST", url, bytes.NewReader(requestBytes))
81 if err != nil {
82 log.Printf("Failed to create a new POST request to %s: %v", url, err)
83 return nil, err
84 }
85 req.Header.Add("Authorization", "Basic "+
Emily Markova521725a2024-03-21 18:46:04 -070086 base64.StdEncoding.EncodeToString([]byte(Username+":")))
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070087
88 client := &http.Client{}
89 resp, err := client.Do(req)
Philipp Schraderd9096a32022-02-24 17:53:09 -080090 if err != nil {
91 log.Printf("Failed to send POST request to %s: %v", url, err)
92 return nil, err
93 }
94 responseBytes, err := io.ReadAll(resp.Body)
95 if err != nil {
96 log.Printf("Failed to parse response bytes from POST to %s: %v", url, err)
97 return nil, err
98 }
99 if resp.StatusCode != http.StatusOK {
100 return nil, parseErrorResponse(url, resp.StatusCode, responseBytes)
101 }
102 return responseBytes, nil
103}
104
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700105// Sends a message to the server and returns the deserialized response.
106// The first generic argument must be specified.
107func sendMessage[FbT interface{}, Fb interface{ UnPack() *FbT }](url string, requestBytes []byte, parser func([]byte, flatbuffers.UOffsetT) Fb) (*FbT, error) {
108 responseBytes, err := performPost(url, requestBytes)
109 if err != nil {
110 return nil, err
111 }
112 response := parser(responseBytes, 0)
113 return response.UnPack(), nil
114}
115
Philipp Schrader20440f82022-03-16 20:07:09 -0700116func RequestAllMatches(server string, requestBytes []byte) (*request_all_matches_response.RequestAllMatchesResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700117 return sendMessage[request_all_matches_response.RequestAllMatchesResponseT](
118 server+"/requests/request/all_matches", requestBytes,
119 request_all_matches_response.GetRootAsRequestAllMatchesResponse)
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800120}
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800121
Filip Kujawaf882e022022-12-14 13:14:08 -0800122func RequestAllDriverRankings(server string, requestBytes []byte) (*request_all_driver_rankings_response.RequestAllDriverRankingsResponseT, error) {
123 return sendMessage[request_all_driver_rankings_response.RequestAllDriverRankingsResponseT](
124 server+"/requests/request/all_driver_rankings", requestBytes,
125 request_all_driver_rankings_response.GetRootAsRequestAllDriverRankingsResponse)
126}
127
Emily Markova8cb91312024-02-02 12:30:37 -0800128func Request2024DataScouting(server string, requestBytes []byte) (*request_2024_data_scouting_response.Request2024DataScoutingResponseT, error) {
129 return sendMessage[request_2024_data_scouting_response.Request2024DataScoutingResponseT](
130 server+"/requests/request/2024_data_scouting", requestBytes,
131 request_2024_data_scouting_response.GetRootAsRequest2024DataScoutingResponse)
132}
133
Alex Perry81f96ba2022-03-13 18:26:19 -0700134func SubmitNotes(server string, requestBytes []byte) (*submit_notes_response.SubmitNotesResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700135 return sendMessage[submit_notes_response.SubmitNotesResponseT](
136 server+"/requests/submit/submit_notes", requestBytes,
137 submit_notes_response.GetRootAsSubmitNotesResponse)
Alex Perry81f96ba2022-03-13 18:26:19 -0700138}
139
140func RequestNotes(server string, requestBytes []byte) (*request_notes_for_team_response.RequestNotesForTeamResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700141 return sendMessage[request_notes_for_team_response.RequestNotesForTeamResponseT](
142 server+"/requests/request/notes_for_team", requestBytes,
143 request_notes_for_team_response.GetRootAsRequestNotesForTeamResponse)
Alex Perry81f96ba2022-03-13 18:26:19 -0700144}
Milo Lin1d59f0c2022-06-22 20:30:58 -0700145
Emily Markovafaecfe12023-07-01 12:40:03 -0700146func RequestPitImages(server string, requestBytes []byte) (*request_pit_images_response.RequestPitImagesResponseT, error) {
147 return sendMessage[request_pit_images_response.RequestPitImagesResponseT](
148 server+"/requests/request/pit_images", requestBytes,
149 request_pit_images_response.GetRootAsRequestPitImagesResponse)
150}
151
Emily Markova8e39f452023-12-23 12:17:30 -0800152func RequestAllPitImages(server string, requestBytes []byte) (*request_all_pit_images_response.RequestAllPitImagesResponseT, error) {
153 return sendMessage[request_all_pit_images_response.RequestAllPitImagesResponseT](
154 server+"/requests/request/all_pit_images", requestBytes,
155 request_all_pit_images_response.GetRootAsRequestAllPitImagesResponse)
156}
157
Filip Kujawaf882e022022-12-14 13:14:08 -0800158func RequestAllNotes(server string, requestBytes []byte) (*request_all_notes_response.RequestAllNotesResponseT, error) {
159 return sendMessage[request_all_notes_response.RequestAllNotesResponseT](
160 server+"/requests/request/all_notes", requestBytes,
161 request_all_notes_response.GetRootAsRequestAllNotesResponse)
162}
163
Milo Lin1d59f0c2022-06-22 20:30:58 -0700164func RequestShiftSchedule(server string, requestBytes []byte) (*request_shift_schedule_response.RequestShiftScheduleResponseT, error) {
165 return sendMessage[request_shift_schedule_response.RequestShiftScheduleResponseT](
166 server+"/requests/request/shift_schedule", requestBytes,
167 request_shift_schedule_response.GetRootAsRequestShiftScheduleResponse)
168}
169
Emily Markova521725a2024-03-21 18:46:04 -0700170func RequestCurrentScouting(server string, requestBytes []byte) (*request_current_scouting_response.RequestCurrentScoutingResponseT, error) {
171 return sendMessage[request_current_scouting_response.RequestCurrentScoutingResponseT](
172 server+"/requests/request/current_scouting", requestBytes,
173 request_current_scouting_response.GetRootAsRequestCurrentScoutingResponse)
174}
175
Milo Lin1d59f0c2022-06-22 20:30:58 -0700176func SubmitShiftSchedule(server string, requestBytes []byte) (*submit_shift_schedule_response.SubmitShiftScheduleResponseT, error) {
177 return sendMessage[submit_shift_schedule_response.SubmitShiftScheduleResponseT](
178 server+"/requests/submit/shift_schedule", requestBytes,
179 submit_shift_schedule_response.GetRootAsSubmitShiftScheduleResponse)
180}
Filip Kujawa210a03b2022-11-24 14:41:11 -0800181
182func SubmitDriverRanking(server string, requestBytes []byte) (*submit_driver_ranking_response.SubmitDriverRankingResponseT, error) {
183 return sendMessage[submit_driver_ranking_response.SubmitDriverRankingResponseT](
184 server+"/requests/submit/submit_driver_ranking", requestBytes,
185 submit_driver_ranking_response.GetRootAsSubmitDriverRankingResponse)
186}
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800187
Emily Markova8cb91312024-02-02 12:30:37 -0800188func Submit2024Actions(server string, requestBytes []byte) (*submit_2024_actions_response.Submit2024ActionsResponseT, error) {
189 return sendMessage[submit_2024_actions_response.Submit2024ActionsResponseT](
190 server+"/requests/submit/submit_2024_actions", requestBytes,
191 submit_2024_actions_response.GetRootAsSubmit2024ActionsResponse)
192}
193
Emily Markovafaecfe12023-07-01 12:40:03 -0700194func SubmitPitImage(server string, requestBytes []byte) (*submit_pit_image_response.SubmitPitImageResponseT, error) {
195 return sendMessage[submit_pit_image_response.SubmitPitImageResponseT](
196 server+"/requests/submit/submit_pit_image", requestBytes,
197 submit_pit_image_response.GetRootAsSubmitPitImageResponse)
198}
199
Emily Markova8cb91312024-02-02 12:30:37 -0800200func Delete2024DataScouting(server string, requestBytes []byte) (*delete_2024_data_scouting_response.Delete2024DataScoutingResponseT, error) {
201 return sendMessage[delete_2024_data_scouting_response.Delete2024DataScoutingResponseT](
202 server+"/requests/delete/delete_2024_data_scouting", requestBytes,
203 delete_2024_data_scouting_response.GetRootAsDelete2024DataScoutingResponse)
204}