2017-12-08 09:13:09 +01:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
|
|
|
"errors"
|
2018-04-16 06:12:11 +02:00
|
|
|
"fmt"
|
2017-12-08 09:13:09 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2017-12-15 06:19:03 +01:00
|
|
|
"net/url"
|
2017-12-08 09:13:09 +01:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
httpHeaderJSON = "application/json"
|
|
|
|
httpHeaderContentType = "Content-Type"
|
|
|
|
httpHeaderAccept = "Accept"
|
|
|
|
)
|
|
|
|
|
|
|
|
//APIClientConfig : Keep config options for APIClient
|
|
|
|
type APIClientConfig struct {
|
|
|
|
Username string
|
|
|
|
Password string
|
|
|
|
CaFile string
|
|
|
|
CertFile string
|
|
|
|
KeyFile string
|
2017-12-15 06:19:03 +01:00
|
|
|
Proxy string
|
2017-12-08 09:13:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//APIClient provided the http client for trigger http requests
|
|
|
|
type APIClient struct {
|
|
|
|
//http client
|
|
|
|
client *http.Client
|
|
|
|
|
|
|
|
//Configuration
|
|
|
|
config APIClientConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
//NewAPIClient is constructor of APIClient
|
|
|
|
func NewAPIClient(config APIClientConfig) (*APIClient, error) {
|
|
|
|
//Load client cert
|
|
|
|
cert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
//Add ca
|
|
|
|
caCert, err := ioutil.ReadFile(config.CaFile)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
caCertPool := x509.NewCertPool()
|
|
|
|
caCertPool.AppendCertsFromPEM(caCert)
|
|
|
|
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
RootCAs: caCertPool,
|
|
|
|
}
|
|
|
|
|
|
|
|
tlsConfig.BuildNameToCertificate()
|
|
|
|
transport := &http.Transport{
|
|
|
|
TLSClientConfig: tlsConfig,
|
|
|
|
}
|
|
|
|
|
2017-12-15 06:19:03 +01:00
|
|
|
//If proxy should be set
|
|
|
|
if len(strings.TrimSpace(config.Proxy)) > 0 {
|
|
|
|
if proxyURL, err := url.Parse(config.Proxy); err == nil {
|
|
|
|
transport.Proxy = http.ProxyURL(proxyURL)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-08 09:13:09 +01:00
|
|
|
client := &http.Client{
|
|
|
|
Transport: transport,
|
|
|
|
}
|
|
|
|
|
|
|
|
return &APIClient{
|
|
|
|
client: client,
|
|
|
|
config: config,
|
|
|
|
}, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//Get data
|
|
|
|
func (ac *APIClient) Get(url string) ([]byte, error) {
|
|
|
|
if strings.TrimSpace(url) == "" {
|
|
|
|
return nil, errors.New("empty url")
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set(httpHeaderAccept, httpHeaderJSON)
|
|
|
|
req.SetBasicAuth(ac.config.Username, ac.config.Password)
|
|
|
|
|
|
|
|
resp, err := ac.client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if resp.Body != nil {
|
|
|
|
resp.Body.Close()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return nil, errors.New(resp.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//Post data
|
|
|
|
func (ac *APIClient) Post(url string, data []byte) error {
|
|
|
|
if strings.TrimSpace(url) == "" {
|
|
|
|
return errors.New("Empty url")
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", url, strings.NewReader(string(data)))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set(httpHeaderContentType, httpHeaderJSON)
|
|
|
|
req.SetBasicAuth(ac.config.Username, ac.config.Password)
|
|
|
|
resp, err := ac.client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusCreated &&
|
|
|
|
resp.StatusCode != http.StatusOK {
|
2018-04-16 06:12:11 +02:00
|
|
|
if err := getErrorMessage(resp); err != nil {
|
|
|
|
return fmt.Errorf("%s:%s", resp.Status, err.Error())
|
|
|
|
}
|
|
|
|
|
2017-12-08 09:13:09 +01:00
|
|
|
return errors.New(resp.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//Delete data
|
|
|
|
func (ac *APIClient) Delete(url string) error {
|
|
|
|
if strings.TrimSpace(url) == "" {
|
|
|
|
return errors.New("Empty url")
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("DELETE", url, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set(httpHeaderAccept, httpHeaderJSON)
|
|
|
|
req.SetBasicAuth(ac.config.Username, ac.config.Password)
|
|
|
|
|
|
|
|
resp, err := ac.client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
2018-04-16 06:12:11 +02:00
|
|
|
if err := getErrorMessage(resp); err != nil {
|
|
|
|
return fmt.Errorf("%s:%s", resp.Status, err.Error())
|
|
|
|
}
|
|
|
|
|
2017-12-08 09:13:09 +01:00
|
|
|
return errors.New(resp.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//SwitchAccount : Switch account
|
|
|
|
func (ac *APIClient) SwitchAccount(username, password string) {
|
|
|
|
if len(strings.TrimSpace(username)) == 0 ||
|
|
|
|
len(strings.TrimSpace(password)) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ac.config.Username = username
|
|
|
|
ac.config.Password = password
|
|
|
|
}
|
2018-04-16 06:12:11 +02:00
|
|
|
|
|
|
|
//Read error message from response body
|
|
|
|
func getErrorMessage(resp *http.Response) error {
|
|
|
|
if resp == nil {
|
|
|
|
return errors.New("nil response")
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.Body == nil || resp.ContentLength == 0 {
|
|
|
|
//nothing to read
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
//abandon to read deatiled error message
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Errorf("%s", data)
|
|
|
|
}
|