123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- package common
- import (
- "bytes"
- "encoding/json"
- "io/ioutil"
- "log"
- "net/http"
- "net/url"
- "strings"
- "time"
- "github.com/denverdino/aliyungo/util"
- )
- // RemovalPolicy.N add index to array item
- // RemovalPolicy=["a", "b"] => RemovalPolicy.1="a" RemovalPolicy.2="b"
- type FlattenArray []string
- // string contains underline which will be replaced with dot
- // SystemDisk_Category => SystemDisk.Category
- type UnderlineString string
- // 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
- serviceCode string
- regionID Region
- businessInfo string
- userAgent 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
- }
- func (client *Client) NewInit(endpoint, version, accessKeyId, accessKeySecret, serviceCode string, regionID Region) {
- client.Init(endpoint, version, accessKeyId, accessKeySecret)
- client.serviceCode = serviceCode
- client.regionID = regionID
- client.setEndpointByLocation(regionID, serviceCode, accessKeyId, accessKeySecret)
- }
- //NewClient using location service
- func (client *Client) setEndpointByLocation(region Region, serviceCode, accessKeyId, accessKeySecret string) {
- locationClient := NewLocationClient(accessKeyId, accessKeySecret)
- ep := locationClient.DescribeOpenAPIEndpoint(region, serviceCode)
- if ep == "" {
- ep = loadEndpointFromFile(region, serviceCode)
- }
- if ep != "" {
- client.endpoint = ep
- }
- }
- // 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
- }
- func (client *Client) SetRegionID(regionID Region) {
- client.regionID = regionID
- }
- //SetServiceCode sets serviceCode
- func (client *Client) SetServiceCode(serviceCode string) {
- client.serviceCode = serviceCode
- }
- // 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
- }
- // SetBusinessInfo sets business info to log the request/response message
- func (client *Client) SetBusinessInfo(businessInfo string) {
- if strings.HasPrefix(businessInfo, "/") {
- client.businessInfo = businessInfo
- } else if businessInfo != "" {
- client.businessInfo = "/" + businessInfo
- }
- }
- // SetUserAgent sets user agent to the request/response message
- func (client *Client) SetUserAgent(userAgent string) {
- client.userAgent = userAgent
- }
- // 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)
- if err != nil {
- return GetClientError(err)
- }
- // TODO move to util and add build val flag
- httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
- httpReq.Header.Set("User-Agent", httpReq.UserAgent()+ " " +client.userAgent)
- 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
- }
- // Invoke sends the raw HTTP request for ECS services
- func (client *Client) InvokeByFlattenMethod(action string, args interface{}, response interface{}) error {
- request := Request{}
- request.init(client.version, action, client.AccessKeyId)
- query := util.ConvertToQueryValues(request)
- util.SetQueryValueByFlattenMethod(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)
- if err != nil {
- return GetClientError(err)
- }
- // TODO move to util and add build val flag
- httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
- httpReq.Header.Set("User-Agent", httpReq.UserAgent()+ " " +client.userAgent)
- 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
- }
- // Invoke sends the raw HTTP request for ECS services
- //改进了一下上面那个方法,可以使用各种Http方法
- //2017.1.30 增加了一个path参数,用来拓展访问的地址
- func (client *Client) InvokeByAnyMethod(method, action, path string, args interface{}, response interface{}) error {
- request := Request{}
- request.init(client.version, action, client.AccessKeyId)
- data := util.ConvertToQueryValues(request)
- util.SetQueryValues(args, &data)
- // Sign request
- signature := util.CreateSignatureForRequest(method, &data, client.AccessKeySecret)
- data.Add("Signature", signature)
- // Generate the request URL
- var (
- httpReq *http.Request
- err error
- )
- if method == http.MethodGet {
- requestURL := client.endpoint + path + "?" + data.Encode()
- //fmt.Println(requestURL)
- httpReq, err = http.NewRequest(method, requestURL, nil)
- } else {
- //fmt.Println(client.endpoint + path)
- httpReq, err = http.NewRequest(method, client.endpoint+path, strings.NewReader(data.Encode()))
- httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- }
- if err != nil {
- return GetClientError(err)
- }
- // TODO move to util and add build val flag
- httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
- httpReq.Header.Set("User-Agent", httpReq.Header.Get("User-Agent")+ " " +client.userAgent)
- 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) %v", ECSRequestMethod, client.endpoint, statusCode, t1.Sub(t0), data.Encode())
- }
- 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())
- }
|