2019-09-23 03:47:38 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2019-12-17 04:34:58 +00:00
|
|
|
"encoding/json"
|
2019-09-23 03:47:38 +00:00
|
|
|
"fmt"
|
2019-11-17 01:01:38 +00:00
|
|
|
"github.com/pkg/errors"
|
2019-09-23 03:47:38 +00:00
|
|
|
"github.com/pterodactyl/wings/config"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2020-04-10 21:39:07 +00:00
|
|
|
// Initializes the requester instance.
|
2019-09-23 03:47:38 +00:00
|
|
|
func NewRequester() *PanelRequest {
|
|
|
|
return &PanelRequest{
|
|
|
|
Response: nil,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type PanelRequest struct {
|
|
|
|
Response *http.Response
|
|
|
|
}
|
|
|
|
|
|
|
|
// Builds the base request instance that can be used with the HTTP client.
|
|
|
|
func (r *PanelRequest) GetClient() *http.Client {
|
|
|
|
return &http.Client{Timeout: time.Second * 30}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *PanelRequest) SetHeaders(req *http.Request) *http.Request {
|
|
|
|
req.Header.Set("Accept", "application/vnd.pterodactyl.v1+json")
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2020-04-10 22:22:15 +00:00
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s.%s", config.Get().AuthenticationTokenId, config.Get().AuthenticationToken))
|
2019-09-23 03:47:38 +00:00
|
|
|
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *PanelRequest) GetEndpoint(endpoint string) string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
"%s/api/remote/%s",
|
|
|
|
strings.TrimSuffix(config.Get().PanelLocation, "/"),
|
|
|
|
strings.TrimPrefix(strings.TrimPrefix(endpoint, "/"), "api/remote/"),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *PanelRequest) Get(url string) (*http.Response, error) {
|
|
|
|
c := r.GetClient()
|
|
|
|
|
|
|
|
req, err := http.NewRequest(http.MethodGet, r.GetEndpoint(url), nil)
|
|
|
|
req = r.SetHeaders(req)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
zap.S().Debugw("GET request to endpoint", zap.String("endpoint", r.GetEndpoint(url)), zap.Any("headers", req.Header))
|
|
|
|
|
|
|
|
return c.Do(req)
|
|
|
|
}
|
|
|
|
|
2019-12-07 23:53:07 +00:00
|
|
|
func (r *PanelRequest) Post(url string, data []byte) (*http.Response, error) {
|
|
|
|
c := r.GetClient()
|
|
|
|
|
|
|
|
req, err := http.NewRequest(http.MethodPost, r.GetEndpoint(url), bytes.NewBuffer(data))
|
|
|
|
req = r.SetHeaders(req)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
zap.S().Debugw("POST request to endpoint", zap.String("endpoint", r.GetEndpoint(url)), zap.Any("headers", req.Header))
|
|
|
|
|
|
|
|
return c.Do(req)
|
|
|
|
}
|
|
|
|
|
2019-09-23 03:47:38 +00:00
|
|
|
// Determines if the API call encountered an error. If no request has been made
|
|
|
|
// the response will be false.
|
|
|
|
func (r *PanelRequest) HasError() bool {
|
|
|
|
if r.Response == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-12-07 23:53:07 +00:00
|
|
|
return r.Response.StatusCode >= 300 || r.Response.StatusCode < 200
|
2019-09-23 03:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reads the body from the response and returns it, then replaces it on the response
|
|
|
|
// so that it can be read again later.
|
|
|
|
func (r *PanelRequest) ReadBody() ([]byte, error) {
|
|
|
|
var b []byte
|
|
|
|
if r.Response == nil {
|
|
|
|
return nil, errors.New("no response exists on interface")
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.Response.Body != nil {
|
|
|
|
b, _ = ioutil.ReadAll(r.Response.Body)
|
|
|
|
}
|
|
|
|
|
|
|
|
r.Response.Body = ioutil.NopCloser(bytes.NewBuffer(b))
|
|
|
|
|
|
|
|
return b, nil
|
|
|
|
}
|
2019-12-07 23:53:07 +00:00
|
|
|
|
|
|
|
func (r *PanelRequest) HttpResponseCode() int {
|
|
|
|
if r.Response == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.Response.StatusCode
|
|
|
|
}
|
|
|
|
|
2019-12-17 04:34:58 +00:00
|
|
|
type RequestError struct {
|
|
|
|
Code string `json:"code"`
|
|
|
|
Status string `json:"status"`
|
|
|
|
Detail string `json:"detail"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the error response in a string form that can be more easily consumed.
|
|
|
|
func (re *RequestError) String() string {
|
|
|
|
return fmt.Sprintf("%s: %s (HTTP/%s)", re.Code, re.Detail, re.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
type RequestErrorBag struct {
|
|
|
|
Errors []RequestError `json:"errors"`
|
|
|
|
}
|
|
|
|
|
2019-09-23 03:47:38 +00:00
|
|
|
// Returns the 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)
|
2019-12-17 04:34:58 +00:00
|
|
|
func (r *PanelRequest) Error() *RequestError {
|
|
|
|
body, _ := r.ReadBody()
|
2019-09-23 03:47:38 +00:00
|
|
|
|
2019-12-17 04:34:58 +00:00
|
|
|
bag := RequestErrorBag{}
|
|
|
|
json.Unmarshal(body, &bag)
|
2019-09-23 03:47:38 +00:00
|
|
|
|
2019-12-17 04:34:58 +00:00
|
|
|
if len(bag.Errors) == 0 {
|
|
|
|
return new(RequestError)
|
2019-09-23 03:47:38 +00:00
|
|
|
}
|
|
|
|
|
2019-12-17 04:34:58 +00:00
|
|
|
return &bag.Errors[0]
|
|
|
|
}
|