From fcccda27613564347dd7982ca1fba89e2d6247ba Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 1 Nov 2020 14:04:57 -0800 Subject: [PATCH] Endpoint fixes for GET requests and error handling --- api/api.go | 26 +++++++++++++++++--------- api/backup_endpoints.go | 8 +------- api/error.go | 7 ++++++- api/server_endpoints.go | 7 ++++--- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/api/api.go b/api/api.go index 7dabba4..40b569c 100644 --- a/api/api.go +++ b/api/api.go @@ -27,6 +27,9 @@ func New() *Request { // Inspired by gin.H, same concept. type D map[string]interface{} +// Same concept as D, but a map of strings, used for querying GET requests. +type Q map[string]string + // A custom API requester struct for Wings. type Request struct{} @@ -63,7 +66,7 @@ func (r *Request) Endpoint(endpoint string) string { // Makes a HTTP request to the given endpoint, attaching the necessary request headers from // Wings to ensure that the request is properly handled by the Panel. -func (r *Request) Make(method, url string, body io.Reader) (*Response, error) { +func (r *Request) Make(method, url string, body io.Reader, opts ...func(r *http.Request)) (*Response, error) { req, err := http.NewRequest(method, url, body) if err != nil { return nil, errors.WithStack(err) @@ -74,6 +77,12 @@ func (r *Request) Make(method, url string, body io.Reader) (*Response, error) { req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s.%s", config.Get().AuthenticationTokenId, config.Get().AuthenticationToken)) + // Make any options calls that will allow us to make modifications to the request + // before it is sent off. + for _, cb := range opts { + cb(req) + } + r.debug(req) res, err := r.Client().Do(req) @@ -103,13 +112,12 @@ func (r *Request) debug(req *http.Request) { // Makes a GET request to the given Panel API endpoint. If any data is passed as the // second argument it will be passed through on the request as URL parameters. -func (r *Request) Get(url string, data interface{}) (*Response, error) { - b, err := json.Marshal(data) - if err != nil { - return nil, errors.WithStack(err) - } - - return r.Make(http.MethodGet, r.Endpoint(url), bytes.NewBuffer(b)) +func (r *Request) Get(url string, data Q) (*Response, error) { + return r.Make(http.MethodGet, r.Endpoint(url), nil, func(r *http.Request) { + for k, v := range data { + r.URL.Query().Set(k, v) + } + }) } // Makes a POST request to the given Panel API endpoint. @@ -166,7 +174,7 @@ func (r *Response) Bind(v interface{}) error { // similar to the below example: // // HttpNotFoundException: The requested resource does not exist. (HTTP/404) -func (r *Response) Error() *RequestError { +func (r *Response) Error() error { if !r.HasError() { return nil } diff --git a/api/backup_endpoints.go b/api/backup_endpoints.go index 7e7ea4a..9d30404 100644 --- a/api/backup_endpoints.go +++ b/api/backup_endpoints.go @@ -1,7 +1,6 @@ package api import ( - "encoding/json" "fmt" "github.com/pkg/errors" ) @@ -16,12 +15,7 @@ type BackupRequest struct { // Notifies the panel that a specific backup has been completed and is now // available for a user to view and download. func (r *Request) SendBackupStatus(backup string, data BackupRequest) error { - b, err := json.Marshal(data) - if err != nil { - return errors.WithStack(err) - } - - resp, err := r.Post(fmt.Sprintf("/backups/%s", backup), b) + resp, err := r.Post(fmt.Sprintf("/backups/%s", backup), data) if err != nil { return errors.WithStack(err) } diff --git a/api/error.go b/api/error.go index 72a747d..5290488 100644 --- a/api/error.go +++ b/api/error.go @@ -24,5 +24,10 @@ func IsRequestError(err error) bool { // Returns the error response in a string form that can be more easily consumed. func (re *RequestError) Error() string { - return fmt.Sprintf("Error response from Panel: %s: %s (HTTP/%d)", re.Code, re.Detail, re.response.StatusCode) + c := 0 + if re.response != nil { + c = re.response.StatusCode + } + + return fmt.Sprintf("Error response from Panel: %s: %s (HTTP/%d)", re.Code, re.Detail, c) } diff --git a/api/server_endpoints.go b/api/server_endpoints.go index ab32b00..6b402be 100644 --- a/api/server_endpoints.go +++ b/api/server_endpoints.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" "github.com/pterodactyl/wings/config" "golang.org/x/sync/errgroup" + "strconv" "sync" ) @@ -54,7 +55,7 @@ type RawServerData struct { // be loaded. If so, those requests are spun-up in additional routines and the final resulting // slice of all servers will be returned. func (r *Request) GetServers() ([]RawServerData, error) { - resp, err := r.Get("/servers", D{"per_page": config.Get().RemoteQuery.BootServersPerPage}) + resp, err := r.Get("/servers", Q{"per_page": strconv.Itoa(int(config.Get().RemoteQuery.BootServersPerPage))}) if err != nil { return nil, errors.WithStack(err) } @@ -82,7 +83,7 @@ func (r *Request) GetServers() ([]RawServerData, error) { g, ctx := errgroup.WithContext(context.Background()) for i := res.Meta.CurrentPage + 1; i <= res.Meta.LastPage; i++ { - page := i + page := strconv.Itoa(int(i)) g.Go(func() error { select { @@ -90,7 +91,7 @@ func (r *Request) GetServers() ([]RawServerData, error) { return ctx.Err() default: { - resp, err := r.Get("/servers", D{"page": page, "per_page": pp}) + resp, err := r.Get("/servers", Q{"page": page, "per_page": strconv.Itoa(int(pp))}) if err != nil { return err }