Formatting
This commit is contained in:
parent
1393937904
commit
aa287d21cf
|
@ -1,15 +1,8 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/apex/log"
|
|
||||||
"github.com/pterodactyl/wings/config"
|
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -39,91 +32,12 @@ type InstallationScript struct {
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type allServerResponse struct {
|
|
||||||
Data []RawServerData `json:"data"`
|
|
||||||
Meta Pagination `json:"meta"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RawServerData struct {
|
type RawServerData struct {
|
||||||
Uuid string `json:"uuid"`
|
Uuid string `json:"uuid"`
|
||||||
Settings json.RawMessage `json:"settings"`
|
Settings json.RawMessage `json:"settings"`
|
||||||
ProcessConfiguration json.RawMessage `json:"process_configuration"`
|
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.
|
// Fetches the server configuration and returns the struct for it.
|
||||||
func (r *Request) GetServerConfiguration(uuid string) (ServerConfigurationResponse, error) {
|
func (r *Request) GetServerConfiguration(uuid string) (ServerConfigurationResponse, error) {
|
||||||
var cfg ServerConfigurationResponse
|
var cfg ServerConfigurationResponse
|
||||||
|
|
|
@ -13,16 +13,16 @@ import (
|
||||||
"github.com/pterodactyl/wings/system"
|
"github.com/pterodactyl/wings/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A custom response type that allows for commonly used error handling and response
|
// Response is a custom response type that allows for commonly used error
|
||||||
// parsing from the Panel API. This just embeds the normal HTTP response from Go and
|
// handling and response parsing from the Panel API. This just embeds the normal
|
||||||
// we attach a few helper functions to it.
|
// HTTP response from Go and we attach a few helper functions to it.
|
||||||
type Response struct {
|
type Response struct {
|
||||||
*http.Response
|
*http.Response
|
||||||
}
|
}
|
||||||
|
|
||||||
// A generic type allowing for easy binding use when making requests to API endpoints
|
// A generic type allowing for easy binding use when making requests to API
|
||||||
// that only expect a singular argument or something that would not benefit from being
|
// endpoints that only expect a singular argument or something that would not
|
||||||
// a typed struct.
|
// benefit from being a typed struct.
|
||||||
//
|
//
|
||||||
// Inspired by gin.H, same concept.
|
// Inspired by gin.H, same concept.
|
||||||
type d map[string]interface{}
|
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.
|
// Same concept as d, but a map of strings, used for querying GET requests.
|
||||||
type q map[string]string
|
type q map[string]string
|
||||||
|
|
||||||
// requestOnce creates a http request and executes it once.
|
// requestOnce creates a http request and executes it once. Prefer request()
|
||||||
// Prefer request() over this method when possible.
|
// over this method when possible. It appends the path to the endpoint of the
|
||||||
// It appends the path to the endpoint of the client and adds the authentication token to the request.
|
// 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) {
|
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)
|
req, err := http.NewRequest(method, c.baseUrl+path, body)
|
||||||
if err != nil {
|
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))
|
return c.request(ctx, http.MethodPost, path, bytes.NewBuffer(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if the API call encountered an error. If no request has been made
|
// HasError determines if the API call encountered an error. If no request has
|
||||||
// the response will be false. This function will evaluate to true if the response
|
// been made the response will be false. This function will evaluate to true if
|
||||||
// code is anything 300 or higher.
|
// the response code is anything 300 or higher.
|
||||||
func (r *Response) HasError() bool {
|
func (r *Response) HasError() bool {
|
||||||
if r.Response == nil {
|
if r.Response == nil {
|
||||||
return false
|
return false
|
||||||
|
@ -123,8 +123,9 @@ func (r *Response) Read() ([]byte, error) {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binds a given interface with the data returned in the response. This is a shortcut
|
// BindJSON binds a given interface with the data returned in the response. This
|
||||||
// for calling Read and then manually calling json.Unmarshal on the raw bytes.
|
// is a shortcut for calling Read and then manually calling json.Unmarshal on
|
||||||
|
// the raw bytes.
|
||||||
func (r *Response) BindJSON(v interface{}) error {
|
func (r *Response) BindJSON(v interface{}) error {
|
||||||
b, err := r.Read()
|
b, err := r.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -134,8 +135,8 @@ func (r *Response) BindJSON(v interface{}) error {
|
||||||
return json.Unmarshal(b, &v)
|
return json.Unmarshal(b, &v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the first error message from the API call as a string.
|
// Returns the first error message from the API call as a string. The error
|
||||||
// The error message will be formatted similar to the below example:
|
// message will be formatted similar to the below example:
|
||||||
//
|
//
|
||||||
// HttpNotFoundException: The requested resource does not exist. (HTTP/404)
|
// HttpNotFoundException: The requested resource does not exist. (HTTP/404)
|
||||||
func (r *Response) Error() error {
|
func (r *Response) Error() error {
|
||||||
|
|
|
@ -17,64 +17,42 @@ const (
|
||||||
ProcessStopNativeStop = "stop"
|
ProcessStopNativeStop = "stop"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Holds the server configuration data returned from the Panel. When a server process
|
// ServerConfigurationResponse holds the server configuration data returned from
|
||||||
// is started, Wings communicates with the Panel to fetch the latest build information
|
// the Panel. When a server process is started, Wings communicates with the
|
||||||
// as well as get all of the details needed to parse the given Egg.
|
// 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
|
// This means we do not need to hit Wings each time part of the server is
|
||||||
// the Panel serves as the source of truth at all times. This also means if a configuration
|
// updated, and the Panel serves as the source of truth at all times. This also
|
||||||
// is accidentally wiped on Wings we can self-recover without too much hassle, so long
|
// means if a configuration is accidentally wiped on Wings we can self-recover
|
||||||
// as Wings is aware of what servers should exist on it.
|
// without too much hassle, so long as Wings is aware of what servers should
|
||||||
|
// exist on it.
|
||||||
type ServerConfigurationResponse struct {
|
type ServerConfigurationResponse struct {
|
||||||
Settings json.RawMessage `json:"settings"`
|
Settings json.RawMessage `json:"settings"`
|
||||||
ProcessConfiguration *api.ProcessConfiguration `json:"process_configuration"`
|
ProcessConfiguration *api.ProcessConfiguration `json:"process_configuration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines installation script information for a server process. This is used when
|
// InstallationScript defines installation script information for a server
|
||||||
// a server is installed for the first time, and when a server is marked for re-installation.
|
// 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 {
|
type InstallationScript struct {
|
||||||
ContainerImage string `json:"container_image"`
|
ContainerImage string `json:"container_image"`
|
||||||
Entrypoint string `json:"entrypoint"`
|
Entrypoint string `json:"entrypoint"`
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type allServerResponse struct {
|
// RawServerData is a raw response from the API for a server.
|
||||||
Data []api.RawServerData `json:"data"`
|
|
||||||
Meta api.Pagination `json:"meta"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RawServerData struct {
|
type RawServerData struct {
|
||||||
Uuid string `json:"uuid"`
|
Uuid string `json:"uuid"`
|
||||||
Settings json.RawMessage `json:"settings"`
|
Settings json.RawMessage `json:"settings"`
|
||||||
ProcessConfiguration json.RawMessage `json:"process_configuration"`
|
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
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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++ {
|
for page := meta.CurrentPage + 1; page <= meta.LastPage; page++ {
|
||||||
page := page
|
page := page
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
ps, _, err := c.GetServersPaged(ctx, int(page), limit)
|
ps, _, err := c.getServersPaged(ctx, int(page), limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -165,3 +143,30 @@ func (c *client) SetTransferStatus(ctx context.Context, uuid string, successful
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
return resp.Error()
|
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