terraform/vendor/github.com/nesv/go-dynect/dynect/client.go

149 lines
3.4 KiB
Go

package dynect
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
)
const (
DynAPIPrefix = "https://api.dynect.net/REST"
)
// A client for use with DynECT's REST API.
type Client struct {
Token string
CustomerName string
httpclient *http.Client
verbose bool
}
// Creates a new Httpclient.
func NewClient(customerName string) *Client {
return &Client{
CustomerName: customerName,
httpclient: &http.Client{}}
}
// Enable, or disable verbose output from the client.
//
// This will enable (or disable) logging messages that explain what the client
// is about to do, like the endpoint it is about to make a request to. If the
// request fails with an unexpected HTTP response code, then the response body
// will be logged out, as well.
func (c *Client) Verbose(p bool) {
c.verbose = p
}
// Establishes a new session with the DynECT API.
func (c *Client) Login(username, password string) error {
var req = LoginBlock{
Username: username,
Password: password,
CustomerName: c.CustomerName}
var resp LoginResponse
err := c.Do("POST", "Session", req, &resp)
if err != nil {
return err
}
c.Token = resp.Data.Token
return nil
}
func (c *Client) LoggedIn() bool {
return len(c.Token) > 0
}
func (c *Client) Logout() error {
return c.Do("DELETE", "Session", nil, nil)
}
func (c *Client) Do(method, endpoint string, requestData, responseData interface{}) error {
// Throw an error if the user tries to make a request if the client is
// logged out/unauthenticated, but make an exemption for when the
// caller is trying to log in.
if !c.LoggedIn() && method != "POST" && endpoint != "Session" {
return errors.New("Will not perform request; httpclient is closed")
}
var err error
// Marshal the request data into a byte slice.
if c.verbose {
log.Println("Marshaling request data")
}
var js []byte
if requestData != nil {
js, err = json.Marshal(requestData)
} else {
js = []byte("")
}
if err != nil {
return err
}
// Create a new http.Request object, and set the necessary headers to
// authorize the request, and specify the content type.
url := fmt.Sprintf("%s/%s", DynAPIPrefix, endpoint)
var req *http.Request
req, err = http.NewRequest(method, url, bytes.NewReader(js))
if err != nil {
return err
}
req.Header.Set("Auth-Token", c.Token)
req.Header.Set("Content-Type", "application/json")
if c.verbose {
log.Printf("Making %s request to %q", method, url)
}
var resp *http.Response
resp, err = c.httpclient.Do(req)
if err != nil {
if c.verbose {
respBody, _ := ioutil.ReadAll(resp.Body)
log.Printf("%s", string(respBody))
}
return err
} else if resp.StatusCode != 200 {
if c.verbose {
// Print out the response body.
respBody, _ := ioutil.ReadAll(resp.Body)
log.Printf("%s", string(respBody))
}
return errors.New(fmt.Sprintf("Bad response, got %q", resp.Status))
}
// Unmarshal the response data into the provided struct.
if c.verbose {
log.Println("Reading in response data")
}
var respBody []byte
respBody, err = ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if c.verbose {
log.Println("Unmarshaling response data")
}
err = json.Unmarshal(respBody, &responseData)
if err != nil {
respBody, _ := ioutil.ReadAll(resp.Body)
if resp.ContentLength == 0 || resp.ContentLength == -1 {
log.Println("Zero-length content body")
} else {
log.Printf("%s", string(respBody))
}
}
return err
}