2018-07-06 14:53:13 +02:00
|
|
|
package chartserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2018-08-30 05:26:46 +02:00
|
|
|
"io"
|
2018-07-06 14:53:13 +02:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2018-07-14 09:49:38 +02:00
|
|
|
"net/url"
|
2018-07-06 14:53:13 +02:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
clientTimeout = 10 * time.Second
|
|
|
|
maxIdleConnections = 10
|
|
|
|
idleConnectionTimeout = 30 * time.Second
|
|
|
|
)
|
|
|
|
|
2018-09-05 10:16:31 +02:00
|
|
|
// ChartClient is a http client to get the content from the external http server
|
2018-07-06 14:53:13 +02:00
|
|
|
type ChartClient struct {
|
2018-09-05 10:16:31 +02:00
|
|
|
// HTTP client
|
2018-07-06 14:53:13 +02:00
|
|
|
httpClient *http.Client
|
2018-07-11 11:31:34 +02:00
|
|
|
|
2018-09-05 10:16:31 +02:00
|
|
|
// Auth info
|
2018-07-11 11:31:34 +02:00
|
|
|
credentail *Credential
|
2018-07-06 14:53:13 +02:00
|
|
|
}
|
|
|
|
|
2018-09-05 10:16:31 +02:00
|
|
|
// NewChartClient is constructor of ChartClient
|
|
|
|
// credentail can be nil
|
|
|
|
func NewChartClient(credentail *Credential) *ChartClient { // Create http client with customized timeouts
|
2018-07-06 14:53:13 +02:00
|
|
|
client := &http.Client{
|
|
|
|
Timeout: clientTimeout,
|
|
|
|
Transport: &http.Transport{
|
|
|
|
MaxIdleConns: maxIdleConnections,
|
|
|
|
IdleConnTimeout: idleConnectionTimeout,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-07-11 11:31:34 +02:00
|
|
|
return &ChartClient{
|
|
|
|
httpClient: client,
|
|
|
|
credentail: credentail,
|
|
|
|
}
|
2018-07-06 14:53:13 +02:00
|
|
|
}
|
|
|
|
|
2018-09-05 10:16:31 +02:00
|
|
|
// GetContent get the bytes from the specified url
|
2018-07-14 09:49:38 +02:00
|
|
|
func (cc *ChartClient) GetContent(addr string) ([]byte, error) {
|
2018-08-30 05:26:46 +02:00
|
|
|
response, err := cc.sendRequest(addr, http.MethodGet, nil, []int{http.StatusOK})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
content, err := ioutil.ReadAll(response.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer response.Body.Close()
|
|
|
|
|
|
|
|
return content, nil
|
|
|
|
}
|
|
|
|
|
2018-09-05 10:16:31 +02:00
|
|
|
// DeleteContent sends deleting request to the addr to delete content
|
2018-08-30 05:26:46 +02:00
|
|
|
func (cc *ChartClient) DeleteContent(addr string) error {
|
|
|
|
_, err := cc.sendRequest(addr, http.MethodDelete, nil, []int{http.StatusOK})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-09-05 10:16:31 +02:00
|
|
|
// sendRequest sends requests to the addr with the specified spec
|
2018-08-30 05:26:46 +02:00
|
|
|
func (cc *ChartClient) sendRequest(addr string, method string, body io.Reader, expectedCodes []int) (*http.Response, error) {
|
2018-07-14 09:49:38 +02:00
|
|
|
if len(strings.TrimSpace(addr)) == 0 {
|
2018-07-06 14:53:13 +02:00
|
|
|
return nil, errors.New("empty url is not allowed")
|
|
|
|
}
|
|
|
|
|
2018-07-14 09:49:38 +02:00
|
|
|
fullURI, err := url.Parse(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid url: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
2018-08-30 05:26:46 +02:00
|
|
|
request, err := http.NewRequest(method, addr, body)
|
2018-07-06 14:53:13 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-09-05 10:16:31 +02:00
|
|
|
// Set basic auth
|
2018-07-11 11:31:34 +02:00
|
|
|
if cc.credentail != nil {
|
|
|
|
request.SetBasicAuth(cc.credentail.Username, cc.credentail.Password)
|
|
|
|
}
|
2018-07-06 14:53:13 +02:00
|
|
|
|
|
|
|
response, err := cc.httpClient.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-30 05:26:46 +02:00
|
|
|
isExpectedStatusCode := false
|
|
|
|
for _, eCode := range expectedCodes {
|
|
|
|
if eCode == response.StatusCode {
|
|
|
|
isExpectedStatusCode = true
|
|
|
|
break
|
|
|
|
}
|
2018-07-06 14:53:13 +02:00
|
|
|
}
|
|
|
|
|
2018-08-30 05:26:46 +02:00
|
|
|
if !isExpectedStatusCode {
|
|
|
|
content, err := ioutil.ReadAll(response.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer response.Body.Close()
|
|
|
|
|
2018-07-23 11:41:40 +02:00
|
|
|
if err := extractError(content); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-30 05:26:46 +02:00
|
|
|
return nil, fmt.Errorf("%s '%s' failed with error: %s", method, fullURI.Path, content)
|
2018-07-10 16:28:22 +02:00
|
|
|
}
|
|
|
|
|
2018-08-30 05:26:46 +02:00
|
|
|
return response, nil
|
2018-07-06 14:53:13 +02:00
|
|
|
}
|