blob: 2462ccb49e9acc76557a583283dd91f5aa10775d [file] [log] [blame]
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08001package requests
2
3import (
4 "fmt"
5 "io"
6 "net/http"
7
Philipp Schrader8747f1b2022-02-23 23:56:22 -08008 "github.com/frc971/971-Robot-Code/scouting/db"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08009 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
10 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting"
11 _ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting_response"
12 "github.com/frc971/971-Robot-Code/scouting/webserver/server"
13 flatbuffers "github.com/google/flatbuffers/go"
14)
15
Philipp Schrader8747f1b2022-02-23 23:56:22 -080016// The interface we expect the database abstraction to conform to.
17// We use an interface here because it makes unit testing easier.
18type Database interface {
19 AddToMatch(db.Match) error
20 AddToStats(db.Stats) error
21 ReturnMatches() ([]db.Match, error)
22 ReturnStats() ([]db.Stats, error)
23 QueryMatches(int) ([]db.Match, error)
24 QueryStats(int) ([]db.Stats, error)
25}
26
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080027// Handles unknown requests. Just returns a 404.
28func unknown(w http.ResponseWriter, req *http.Request) {
29 w.WriteHeader(http.StatusNotFound)
30}
31
32func respondWithError(w http.ResponseWriter, statusCode int, errorMessage string) {
33 builder := flatbuffers.NewBuilder(1024)
34 builder.Finish((&error_response.ErrorResponseT{
35 ErrorMessage: errorMessage,
36 }).Pack(builder))
37 w.WriteHeader(statusCode)
38 w.Write(builder.FinishedBytes())
39}
40
41func respondNotImplemented(w http.ResponseWriter) {
42 respondWithError(w, http.StatusNotImplemented, "")
43}
44
45// TODO(phil): Can we turn this into a generic?
46func parseSubmitDataScouting(w http.ResponseWriter, buf []byte) (*submit_data_scouting.SubmitDataScouting, bool) {
47 success := true
48 defer func() {
49 if r := recover(); r != nil {
50 respondWithError(w, http.StatusBadRequest, fmt.Sprintf("Failed to parse SubmitDataScouting: %v", r))
51 success = false
52 }
53 }()
54 result := submit_data_scouting.GetRootAsSubmitDataScouting(buf, 0)
55 return result, success
56}
57
58// Handles a SubmitDataScouting request.
Philipp Schrader8747f1b2022-02-23 23:56:22 -080059type submitDataScoutingHandler struct {
60 db Database
61}
62
63func (handler submitDataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080064 requestBytes, err := io.ReadAll(req.Body)
65 if err != nil {
66 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
67 return
68 }
69
70 _, success := parseSubmitDataScouting(w, requestBytes)
71 if !success {
72 return
73 }
74
75 // TODO(phil): Actually handle the request.
Philipp Schrader8747f1b2022-02-23 23:56:22 -080076 // We have access to the database via "handler.db" here. For example:
77 // stats := handler.db.ReturnStats()
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080078
79 respondNotImplemented(w)
80}
81
Philipp Schrader8747f1b2022-02-23 23:56:22 -080082func HandleRequests(db Database, scoutingServer server.ScoutingServer) {
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080083 scoutingServer.HandleFunc("/requests", unknown)
Philipp Schrader8747f1b2022-02-23 23:56:22 -080084 scoutingServer.Handle("/requests/submit/data_scouting", submitDataScoutingHandler{db})
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080085}