Formatting
This commit is contained in:
parent
1393937904
commit
aa287d21cf
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user