package common import ( "bytes" "encoding/json" "io/ioutil" "log" "net/http" "net/url" "time" "github.com/denverdino/aliyungo/util" ) // A Client represents a client of ECS services type Client struct { AccessKeyId string //Access Key Id AccessKeySecret string //Access Key Secret debug bool httpClient *http.Client endpoint string version string } // NewClient creates a new instance of ECS client func (client *Client) Init(endpoint, version, accessKeyId, accessKeySecret string) { client.AccessKeyId = accessKeyId client.AccessKeySecret = accessKeySecret + "&" client.debug = false client.httpClient = &http.Client{} client.endpoint = endpoint client.version = version } // SetEndpoint sets custom endpoint func (client *Client) SetEndpoint(endpoint string) { client.endpoint = endpoint } // SetEndpoint sets custom version func (client *Client) SetVersion(version string) { client.version = version } // SetAccessKeyId sets new AccessKeyId func (client *Client) SetAccessKeyId(id string) { client.AccessKeyId = id } // SetAccessKeySecret sets new AccessKeySecret func (client *Client) SetAccessKeySecret(secret string) { client.AccessKeySecret = secret + "&" } // SetDebug sets debug mode to log the request/response message func (client *Client) SetDebug(debug bool) { client.debug = debug } // Invoke sends the raw HTTP request for ECS services func (client *Client) Invoke(action string, args interface{}, response interface{}) error { request := Request{} request.init(client.version, action, client.AccessKeyId) query := util.ConvertToQueryValues(request) util.SetQueryValues(args, &query) // Sign request signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret) // Generate the request URL requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature) httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil) // TODO move to util and add build val flag httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version) if err != nil { return GetClientError(err) } t0 := time.Now() httpResp, err := client.httpClient.Do(httpReq) t1 := time.Now() if err != nil { return GetClientError(err) } statusCode := httpResp.StatusCode if client.debug { log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0)) } defer httpResp.Body.Close() body, err := ioutil.ReadAll(httpResp.Body) if err != nil { return GetClientError(err) } if client.debug { var prettyJSON bytes.Buffer err = json.Indent(&prettyJSON, body, "", " ") log.Println(string(prettyJSON.Bytes())) } if statusCode >= 400 && statusCode <= 599 { errorResponse := ErrorResponse{} err = json.Unmarshal(body, &errorResponse) ecsError := &Error{ ErrorResponse: errorResponse, StatusCode: statusCode, } return ecsError } err = json.Unmarshal(body, response) //log.Printf("%++v", response) if err != nil { return GetClientError(err) } return nil } // GenerateClientToken generates the Client Token with random string func (client *Client) GenerateClientToken() string { return util.CreateRandomString() } func GetClientErrorFromString(str string) error { return &Error{ ErrorResponse: ErrorResponse{ Code: "AliyunGoClientFailure", Message: str, }, StatusCode: -1, } } func GetClientError(err error) error { return GetClientErrorFromString(err.Error()) }