blob: faf4a9d6d620fa8fcbbcc330f0b83f7580451132 [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"
Philipp Schraderd9096a32022-02-24 17:53:09 -080013 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Emily Markova290147d2023-03-03 22:40:06 -080014 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_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"
Alex Perry81f96ba2022-03-13 18:26:19 -070019 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070020 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070021 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
Sabina Leaver9b4eb312023-02-20 19:58:17 -080022 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response"
Filip Kujawa210a03b2022-11-24 14:41:11 -080023 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070024 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070025 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070026 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
Philipp Schrader86bf2b92022-03-30 20:57:30 -070027 flatbuffers "github.com/google/flatbuffers/go"
Philipp Schraderd9096a32022-02-24 17:53:09 -080028)
29
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070030// The username to submit the various requests as.
31const DefaultUsername = "debug_cli"
32
Philipp Schraderd9096a32022-02-24 17:53:09 -080033// A struct that can be used as an `error`. It contains information about the
34// why the server was unhappy and what the corresponding request was.
35type ResponseError struct {
36 Url string
37 StatusCode int
38 ErrorResponse *error_response.ErrorResponse
39}
40
41// Required to implement the `error` interface.
42func (err *ResponseError) Error() string {
43 return fmt.Sprintf(
44 "%s returned %d %s: %s", err.Url, err.StatusCode,
45 http.StatusText(err.StatusCode), err.ErrorResponse.ErrorMessage())
46}
47
48// Parse an `ErrorResponse` message that the server sent back. This happens
49// whenever the status code is something other than 200. If the message is
50// successfully parsed, it's turned into a `ResponseError` which implements the
51// `error` interface.
52func parseErrorResponse(url string, statusCode int, responseBytes []byte) error {
53 getRootErrMessage := ""
54 defer func() {
55 if r := recover(); r != nil {
56 getRootErrMessage = fmt.Sprintf("%v", r)
57 }
58 }()
59 errorMessage := error_response.GetRootAsErrorResponse(responseBytes, 0)
60 if getRootErrMessage != "" {
61 return errors.New(fmt.Sprintf(
62 "Failed to parse response from %s with status %d %s (bytes %v) as ErrorResponse: %s",
63 url, statusCode, http.StatusText(statusCode), responseBytes, getRootErrMessage))
64 }
65
66 return &ResponseError{
67 Url: url,
68 StatusCode: statusCode,
69 ErrorResponse: errorMessage,
70 }
71}
72
73// Performs a POST request with the specified payload. The bytes that the
74// server responds with are returned.
75func performPost(url string, requestBytes []byte) ([]byte, error) {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070076 req, err := http.NewRequest("POST", url, bytes.NewReader(requestBytes))
77 if err != nil {
78 log.Printf("Failed to create a new POST request to %s: %v", url, err)
79 return nil, err
80 }
81 req.Header.Add("Authorization", "Basic "+
82 base64.StdEncoding.EncodeToString([]byte(DefaultUsername+":")))
83
84 client := &http.Client{}
85 resp, err := client.Do(req)
Philipp Schraderd9096a32022-02-24 17:53:09 -080086 if err != nil {
87 log.Printf("Failed to send POST request to %s: %v", url, err)
88 return nil, err
89 }
90 responseBytes, err := io.ReadAll(resp.Body)
91 if err != nil {
92 log.Printf("Failed to parse response bytes from POST to %s: %v", url, err)
93 return nil, err
94 }
95 if resp.StatusCode != http.StatusOK {
96 return nil, parseErrorResponse(url, resp.StatusCode, responseBytes)
97 }
98 return responseBytes, nil
99}
100
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700101// Sends a message to the server and returns the deserialized response.
102// The first generic argument must be specified.
103func sendMessage[FbT interface{}, Fb interface{ UnPack() *FbT }](url string, requestBytes []byte, parser func([]byte, flatbuffers.UOffsetT) Fb) (*FbT, error) {
104 responseBytes, err := performPost(url, requestBytes)
105 if err != nil {
106 return nil, err
107 }
108 response := parser(responseBytes, 0)
109 return response.UnPack(), nil
110}
111
Philipp Schrader20440f82022-03-16 20:07:09 -0700112func RequestAllMatches(server string, requestBytes []byte) (*request_all_matches_response.RequestAllMatchesResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700113 return sendMessage[request_all_matches_response.RequestAllMatchesResponseT](
114 server+"/requests/request/all_matches", requestBytes,
115 request_all_matches_response.GetRootAsRequestAllMatchesResponse)
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800116}
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800117
Filip Kujawaf882e022022-12-14 13:14:08 -0800118func RequestAllDriverRankings(server string, requestBytes []byte) (*request_all_driver_rankings_response.RequestAllDriverRankingsResponseT, error) {
119 return sendMessage[request_all_driver_rankings_response.RequestAllDriverRankingsResponseT](
120 server+"/requests/request/all_driver_rankings", requestBytes,
121 request_all_driver_rankings_response.GetRootAsRequestAllDriverRankingsResponse)
122}
123
Emily Markova290147d2023-03-03 22:40:06 -0800124func Request2023DataScouting(server string, requestBytes []byte) (*request_2023_data_scouting_response.Request2023DataScoutingResponseT, error) {
125 return sendMessage[request_2023_data_scouting_response.Request2023DataScoutingResponseT](
126 server+"/requests/request/2023_data_scouting", requestBytes,
127 request_2023_data_scouting_response.GetRootAsRequest2023DataScoutingResponse)
128}
129
Alex Perry81f96ba2022-03-13 18:26:19 -0700130func SubmitNotes(server string, requestBytes []byte) (*submit_notes_response.SubmitNotesResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700131 return sendMessage[submit_notes_response.SubmitNotesResponseT](
132 server+"/requests/submit/submit_notes", requestBytes,
133 submit_notes_response.GetRootAsSubmitNotesResponse)
Alex Perry81f96ba2022-03-13 18:26:19 -0700134}
135
136func RequestNotes(server string, requestBytes []byte) (*request_notes_for_team_response.RequestNotesForTeamResponseT, error) {
Philipp Schrader86bf2b92022-03-30 20:57:30 -0700137 return sendMessage[request_notes_for_team_response.RequestNotesForTeamResponseT](
138 server+"/requests/request/notes_for_team", requestBytes,
139 request_notes_for_team_response.GetRootAsRequestNotesForTeamResponse)
Alex Perry81f96ba2022-03-13 18:26:19 -0700140}
Milo Lin1d59f0c2022-06-22 20:30:58 -0700141
Emily Markovafaecfe12023-07-01 12:40:03 -0700142func RequestPitImages(server string, requestBytes []byte) (*request_pit_images_response.RequestPitImagesResponseT, error) {
143 return sendMessage[request_pit_images_response.RequestPitImagesResponseT](
144 server+"/requests/request/pit_images", requestBytes,
145 request_pit_images_response.GetRootAsRequestPitImagesResponse)
146}
147
Emily Markova8e39f452023-12-23 12:17:30 -0800148func RequestAllPitImages(server string, requestBytes []byte) (*request_all_pit_images_response.RequestAllPitImagesResponseT, error) {
149 return sendMessage[request_all_pit_images_response.RequestAllPitImagesResponseT](
150 server+"/requests/request/all_pit_images", requestBytes,
151 request_all_pit_images_response.GetRootAsRequestAllPitImagesResponse)
152}
153
Filip Kujawaf882e022022-12-14 13:14:08 -0800154func RequestAllNotes(server string, requestBytes []byte) (*request_all_notes_response.RequestAllNotesResponseT, error) {
155 return sendMessage[request_all_notes_response.RequestAllNotesResponseT](
156 server+"/requests/request/all_notes", requestBytes,
157 request_all_notes_response.GetRootAsRequestAllNotesResponse)
158}
159
Milo Lin1d59f0c2022-06-22 20:30:58 -0700160func RequestShiftSchedule(server string, requestBytes []byte) (*request_shift_schedule_response.RequestShiftScheduleResponseT, error) {
161 return sendMessage[request_shift_schedule_response.RequestShiftScheduleResponseT](
162 server+"/requests/request/shift_schedule", requestBytes,
163 request_shift_schedule_response.GetRootAsRequestShiftScheduleResponse)
164}
165
166func SubmitShiftSchedule(server string, requestBytes []byte) (*submit_shift_schedule_response.SubmitShiftScheduleResponseT, error) {
167 return sendMessage[submit_shift_schedule_response.SubmitShiftScheduleResponseT](
168 server+"/requests/submit/shift_schedule", requestBytes,
169 submit_shift_schedule_response.GetRootAsSubmitShiftScheduleResponse)
170}
Filip Kujawa210a03b2022-11-24 14:41:11 -0800171
172func SubmitDriverRanking(server string, requestBytes []byte) (*submit_driver_ranking_response.SubmitDriverRankingResponseT, error) {
173 return sendMessage[submit_driver_ranking_response.SubmitDriverRankingResponseT](
174 server+"/requests/submit/submit_driver_ranking", requestBytes,
175 submit_driver_ranking_response.GetRootAsSubmitDriverRankingResponse)
176}
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800177
178func SubmitActions(server string, requestBytes []byte) (*submit_actions_response.SubmitActionsResponseT, error) {
179 return sendMessage[submit_actions_response.SubmitActionsResponseT](
180 server+"/requests/submit/submit_actions", requestBytes,
181 submit_actions_response.GetRootAsSubmitActionsResponse)
182}
Filip Kujawac1ded372023-05-27 14:33:43 -0700183
Emily Markovafaecfe12023-07-01 12:40:03 -0700184func SubmitPitImage(server string, requestBytes []byte) (*submit_pit_image_response.SubmitPitImageResponseT, error) {
185 return sendMessage[submit_pit_image_response.SubmitPitImageResponseT](
186 server+"/requests/submit/submit_pit_image", requestBytes,
187 submit_pit_image_response.GetRootAsSubmitPitImageResponse)
188}
189
Filip Kujawac1ded372023-05-27 14:33:43 -0700190func Delete2023DataScouting(server string, requestBytes []byte) (*delete_2023_data_scouting_response.Delete2023DataScoutingResponseT, error) {
191 return sendMessage[delete_2023_data_scouting_response.Delete2023DataScoutingResponseT](
192 server+"/requests/delete/delete_2023_data_scouting", requestBytes,
193 delete_2023_data_scouting_response.GetRootAsDelete2023DataScoutingResponse)
194}