From aa287d21cfba3f0462d728bba713fe06a256bcf9 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 1 Feb 2021 20:33:35 -0800 Subject: [PATCH] Formatting --- api/server_endpoints.go | 86 ----------------------------------------- remote/http.go | 33 ++++++++-------- remote/servers.go | 83 ++++++++++++++++++++------------------- 3 files changed, 61 insertions(+), 141 deletions(-) diff --git a/api/server_endpoints.go b/api/server_endpoints.go index 946b949..386732d 100644 --- a/api/server_endpoints.go +++ b/api/server_endpoints.go @@ -1,15 +1,8 @@ package api import ( - "context" "encoding/json" "fmt" - "strconv" - "sync" - - "github.com/apex/log" - "github.com/pterodactyl/wings/config" - "golang.org/x/sync/errgroup" ) const ( @@ -39,91 +32,12 @@ type InstallationScript struct { Script string `json:"script"` } -type allServerResponse struct { - Data []RawServerData `json:"data"` - Meta Pagination `json:"meta"` -} - type RawServerData struct { Uuid string `json:"uuid"` Settings json.RawMessage `json:"settings"` ProcessConfiguration json.RawMessage `json:"process_configuration"` } -// Fetches all of the server configurations from the Panel API. This will initially load the -// first 50 servers, and then check the pagination response to determine if more pages should -// 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", Q{"per_page": strconv.Itoa(config.Get().RemoteQuery.BootServersPerPage)}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.HasError() { - return nil, resp.Error() - } - - var res allServerResponse - if err := resp.Bind(&res); err != nil { - return nil, err - } - - var mu sync.Mutex - ret := res.Data - - // Check for pagination, and if it exists we'll need to then make a request to the API - // for each page that would exist and get all of the resulting servers. - if res.Meta.LastPage > 1 { - pp := res.Meta.PerPage - log.WithField("per_page", pp). - WithField("total_pages", res.Meta.LastPage). - Debug("detected multiple pages of server configurations, fetching remaining...") - - g, ctx := errgroup.WithContext(context.Background()) - for i := res.Meta.CurrentPage + 1; i <= res.Meta.LastPage; i++ { - page := strconv.Itoa(int(i)) - - g.Go(func() error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - { - resp, err := r.Get("/servers", Q{"page": page, "per_page": strconv.Itoa(int(pp))}) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.Error() != nil { - return resp.Error() - } - - var servers allServerResponse - if err := resp.Bind(&servers); err != nil { - return err - } - - mu.Lock() - defer mu.Unlock() - ret = append(ret, servers.Data...) - - return nil - } - } - }) - } - - if err := g.Wait(); err != nil { - return nil, err - } - } - - return ret, nil -} - // Fetches the server configuration and returns the struct for it. func (r *Request) GetServerConfiguration(uuid string) (ServerConfigurationResponse, error) { var cfg ServerConfigurationResponse diff --git a/remote/http.go b/remote/http.go index ff54613..5090523 100644 --- a/remote/http.go +++ b/remote/http.go @@ -13,16 +13,16 @@ import ( "github.com/pterodactyl/wings/system" ) -// A custom response type that allows for commonly used error handling and response -// parsing from the Panel API. This just embeds the normal HTTP response from Go and -// we attach a few helper functions to it. +// Response is a custom response type that allows for commonly used error +// handling and response parsing from the Panel API. This just embeds the normal +// HTTP response from Go and we attach a few helper functions to it. type Response struct { *http.Response } -// A generic type allowing for easy binding use when making requests to API endpoints -// that only expect a singular argument or something that would not benefit from being -// a typed struct. +// A generic type allowing for easy binding use when making requests to API +// endpoints that only expect a singular argument or something that would not +// benefit from being a typed struct. // // Inspired by gin.H, same concept. type d map[string]interface{} @@ -30,9 +30,9 @@ type d map[string]interface{} // Same concept as d, but a map of strings, used for querying GET requests. type q map[string]string -// requestOnce creates a http request and executes it once. -// Prefer request() over this method when possible. -// It appends the path to the endpoint of the client and adds the authentication token to the request. +// requestOnce creates a http request and executes it once. Prefer request() +// over this method when possible. It appends the path to the endpoint of the +// client and adds the authentication token to the request. func (c *client) requestOnce(ctx context.Context, method, path string, body io.Reader, opts ...func(r *http.Request)) (*Response, error) { req, err := http.NewRequest(method, c.baseUrl+path, body) if err != nil { @@ -94,9 +94,9 @@ func (c *client) post(ctx context.Context, path string, data interface{}) (*Resp return c.request(ctx, http.MethodPost, path, bytes.NewBuffer(b)) } -// Determines if the API call encountered an error. If no request has been made -// the response will be false. This function will evaluate to true if the response -// code is anything 300 or higher. +// HasError determines if the API call encountered an error. If no request has +// been made the response will be false. This function will evaluate to true if +// the response code is anything 300 or higher. func (r *Response) HasError() bool { if r.Response == nil { return false @@ -123,8 +123,9 @@ func (r *Response) Read() ([]byte, error) { return b, nil } -// Binds a given interface with the data returned in the response. This is a shortcut -// for calling Read and then manually calling json.Unmarshal on the raw bytes. +// BindJSON binds a given interface with the data returned in the response. This +// is a shortcut for calling Read and then manually calling json.Unmarshal on +// the raw bytes. func (r *Response) BindJSON(v interface{}) error { b, err := r.Read() if err != nil { @@ -134,8 +135,8 @@ func (r *Response) BindJSON(v interface{}) error { return json.Unmarshal(b, &v) } -// Returns the first error message from the API call as a string. -// The error message will be formatted similar to the below example: +// Returns the first error message from the API call as a string. The error +// message will be formatted similar to the below example: // // HttpNotFoundException: The requested resource does not exist. (HTTP/404) func (r *Response) Error() error { diff --git a/remote/servers.go b/remote/servers.go index 21b004d..feda9cf 100644 --- a/remote/servers.go +++ b/remote/servers.go @@ -17,64 +17,42 @@ const ( ProcessStopNativeStop = "stop" ) -// Holds the server configuration data returned from the Panel. When a server process -// is started, Wings communicates with the Panel to fetch the latest build information -// as well as get all of the details needed to parse the given Egg. +// ServerConfigurationResponse holds the server configuration data returned from +// the Panel. When a server process is started, Wings communicates with the +// Panel to fetch the latest build information as well as get all of the details +// needed to parse the given Egg. // -// This means we do not need to hit Wings each time part of the server is updated, and -// the Panel serves as the source of truth at all times. This also means if a configuration -// is accidentally wiped on Wings we can self-recover without too much hassle, so long -// as Wings is aware of what servers should exist on it. +// This means we do not need to hit Wings each time part of the server is +// updated, and the Panel serves as the source of truth at all times. This also +// means if a configuration is accidentally wiped on Wings we can self-recover +// without too much hassle, so long as Wings is aware of what servers should +// exist on it. type ServerConfigurationResponse struct { Settings json.RawMessage `json:"settings"` ProcessConfiguration *api.ProcessConfiguration `json:"process_configuration"` } -// Defines installation script information for a server process. This is used when -// a server is installed for the first time, and when a server is marked for re-installation. +// InstallationScript defines installation script information for a server +// process. This is used when a server is installed for the first time, and when +// a server is marked for re-installation. type InstallationScript struct { ContainerImage string `json:"container_image"` Entrypoint string `json:"entrypoint"` Script string `json:"script"` } -type allServerResponse struct { - Data []api.RawServerData `json:"data"` - Meta api.Pagination `json:"meta"` -} - +// RawServerData is a raw response from the API for a server. type RawServerData struct { Uuid string `json:"uuid"` Settings json.RawMessage `json:"settings"` ProcessConfiguration json.RawMessage `json:"process_configuration"` } -func (c *client) GetServersPaged(ctx context.Context, page, limit int) ([]api.RawServerData, api.Pagination, error) { - res, err := c.get(ctx, "/servers", q{ - "page": strconv.Itoa(page), - "per_page": strconv.Itoa(limit), - }) - if err != nil { - return nil, api.Pagination{}, err - } - defer res.Body.Close() - - if res.HasError() { - return nil, api.Pagination{}, res.Error() - } - - var r allServerResponse - if err := res.BindJSON(&r); err != nil { - return nil, api.Pagination{}, err - } - - return r.Data, r.Meta, nil -} - // GetServers returns all of the servers that are present on the Panel making -// parallel API calls to the endpoint if more than one page of servers is returned. +// parallel API calls to the endpoint if more than one page of servers is +// returned. func (c *client) GetServers(ctx context.Context, limit int) ([]api.RawServerData, error) { - servers, meta, err := c.GetServersPaged(ctx, 0, limit) + servers, meta, err := c.getServersPaged(ctx, 0, limit) if err != nil { return nil, err } @@ -85,7 +63,7 @@ func (c *client) GetServers(ctx context.Context, limit int) ([]api.RawServerData for page := meta.CurrentPage + 1; page <= meta.LastPage; page++ { page := page g.Go(func() error { - ps, _, err := c.GetServersPaged(ctx, int(page), limit) + ps, _, err := c.getServersPaged(ctx, int(page), limit) if err != nil { return err } @@ -165,3 +143,30 @@ func (c *client) SetTransferStatus(ctx context.Context, uuid string, successful defer resp.Body.Close() return resp.Error() } + +// getServersPaged returns a subset of servers from the Panel API using the +// pagination query parameters. +func (c *client) getServersPaged(ctx context.Context, page, limit int) ([]api.RawServerData, api.Pagination, error) { + res, err := c.get(ctx, "/servers", q{ + "page": strconv.Itoa(page), + "per_page": strconv.Itoa(limit), + }) + if err != nil { + return nil, api.Pagination{}, err + } + defer res.Body.Close() + + if res.HasError() { + return nil, api.Pagination{}, res.Error() + } + + var r struct { + Data []api.RawServerData `json:"data"` + Meta api.Pagination `json:"meta"` + } + if err := res.BindJSON(&r); err != nil { + return nil, api.Pagination{}, err + } + + return r.Data, r.Meta, nil +} \ No newline at end of file