golang/utils/client.go (627 lines of code) (raw):
// This file is auto-generated, don't edit it. Thanks.
package utils
import (
"bytes"
"crypto"
"crypto/hmac"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"hash"
"io"
"io/ioutil"
mathRand "math/rand"
"net/http"
"net/textproto"
"net/url"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
"sync/atomic"
"time"
models "github.com/alibabacloud-go/darabonba-openapi/v2/models"
"github.com/alibabacloud-go/tea/dara"
"github.com/tjfoc/gmsm/sm3"
)
var defaultUserAgent = fmt.Sprintf("AlibabaCloud (%s; %s) Golang/%s Core/%s TeaDSL/2", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), "0.01")
var seqId int64 = 0
var processStartTime int64 = time.Now().UnixNano() / 1e6
const (
PEM_BEGIN = "-----BEGIN RSA PRIVATE KEY-----\n"
PEM_END = "\n-----END RSA PRIVATE KEY-----"
)
type Config = models.Config
type GlobalParameters = models.GlobalParameters
type Params = models.Params
type OpenApiRequest = models.OpenApiRequest
type Sorter struct {
Keys []string
Vals []string
}
func newSorter(m map[string]string) *Sorter {
hs := &Sorter{
Keys: make([]string, 0, len(m)),
Vals: make([]string, 0, len(m)),
}
for k, v := range m {
hs.Keys = append(hs.Keys, k)
hs.Vals = append(hs.Vals, v)
}
return hs
}
// Sort is an additional function for function SignHeader.
func (hs *Sorter) Sort() {
sort.Sort(hs)
}
// Len is an additional function for function SignHeader.
func (hs *Sorter) Len() int {
return len(hs.Vals)
}
// Less is an additional function for function SignHeader.
func (hs *Sorter) Less(i, j int) bool {
return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0
}
// Swap is an additional function for function SignHeader.
func (hs *Sorter) Swap(i, j int) {
hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i]
hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i]
}
// Description:
//
// This is for OpenApi Util
// Description:
//
// # Convert all params of body other than type of readable into content
//
// @param body - source Model
//
// @param content - target Model
//
// @return void
func Convert(body interface{}, content interface{}) {
res := make(map[string]interface{})
val := reflect.ValueOf(body).Elem()
dataType := val.Type()
for i := 0; i < dataType.NumField(); i++ {
field := dataType.Field(i)
name, _ := field.Tag.Lookup("json")
name = strings.Split(name, ",omitempty")[0]
_, ok := val.Field(i).Interface().(io.Reader)
if !ok {
res[name] = val.Field(i).Interface()
}
}
byt, _ := json.Marshal(res)
json.Unmarshal(byt, content)
}
// Description:
//
// # Get throttling param
//
// @param the - response headers
//
// @return time left
func GetThrottlingTimeLeft(headers map[string]*string) (_result *int64) {
rateLimitForUserApi := headers["x-ratelimit-user-api"]
rateLimitForUser := headers["x-ratelimit-user"]
timeLeftForUserApi := getTimeLeft(rateLimitForUserApi)
timeLeftForUser := getTimeLeft(rateLimitForUser)
if dara.Int64Value(timeLeftForUserApi) > dara.Int64Value(timeLeftForUser) {
return timeLeftForUserApi
} else {
return timeLeftForUser
}
}
// Description:
//
// # Hash the raw data with signatureAlgorithm
//
// @param raw - hashing data
//
// @param signatureAlgorithm - the autograph method
//
// @return hashed bytes
func Hash(raw []byte, signatureAlgorithm *string) (_result []byte) {
signType := dara.StringValue(signatureAlgorithm)
if signType == "ACS3-HMAC-SHA256" || signType == "ACS3-RSA-SHA256" {
h := sha256.New()
h.Write(raw)
return h.Sum(nil)
} else if signType == "ACS3-HMAC-SM3" {
h := sm3.New()
h.Write(raw)
return h.Sum(nil)
}
return nil
}
func getGID() uint64 {
// https://blog.sgmansfield.com/2015/12/goroutine-ids/
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return n
}
// Description:
//
// # Generate a nonce string
//
// @return the nonce string
func GetNonce() (_result *string) {
routineId := getGID()
currentTime := time.Now().UnixNano() / 1e6
seq := atomic.AddInt64(&seqId, 1)
randNum := mathRand.Int63()
msg := fmt.Sprintf("%d-%d-%d-%d-%d", processStartTime, routineId, currentTime, seq, randNum)
h := md5.New()
h.Write([]byte(msg))
ret := hex.EncodeToString(h.Sum(nil))
return &ret
}
// Description:
//
// # Get the string to be signed according to request
//
// @param request - which contains signed messages
//
// @return the signed string
func GetStringToSign(request *dara.Request) (_result *string) {
return dara.String(getStringToSign(request))
}
func getStringToSign(request *dara.Request) string {
// sort QueryParams by key
var queryKeys []string
resource := dara.StringValue(request.Pathname)
queryParams := request.Query
for key := range queryParams {
queryKeys = append(queryKeys, key)
}
sort.Strings(queryKeys)
tmp := ""
for i := 0; i < len(queryKeys); i++ {
queryKey := queryKeys[i]
v := dara.StringValue(queryParams[queryKey])
if v != "" {
tmp = tmp + "&" + queryKey + "=" + v
} else {
tmp = tmp + "&" + queryKey
}
}
if tmp != "" {
tmp = strings.TrimLeft(tmp, "&")
resource = resource + "?" + tmp
}
return getSignedStr(request, resource)
}
func getSignedStr(req *dara.Request, canonicalizedResource string) string {
temp := make(map[string]string)
for k, v := range req.Headers {
if strings.HasPrefix(strings.ToLower(k), "x-acs-") {
temp[strings.ToLower(k)] = dara.StringValue(v)
}
}
hs := newSorter(temp)
// Sort the temp by the ascending order
hs.Sort()
// Get the canonicalizedOSSHeaders
canonicalizedOSSHeaders := ""
for i := range hs.Keys {
canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
}
// Give other parameters values
// when sign URL, date is expires
date := dara.StringValue(req.Headers["date"])
accept := dara.StringValue(req.Headers["accept"])
contentType := dara.StringValue(req.Headers["content-type"])
contentMd5 := dara.StringValue(req.Headers["content-md5"])
signStr := dara.StringValue(req.Method) + "\n" + accept + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
return signStr
}
// Description:
//
// # Get signature according to stringToSign, secret
//
// @param stringToSign - the signed string
//
// @param secret - accesskey secret
//
// @return the signature
func GetROASignature(stringToSign *string, secret *string) (_result *string) {
h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(dara.StringValue(secret)))
io.WriteString(h, dara.StringValue(stringToSign))
signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
return dara.String(signedStr)
}
// Description:
//
// # Parse filter into a form string
//
// @param filter - object
//
// @return the string
func ToForm(filter map[string]interface{}) (_result *string) {
tmp := make(map[string]interface{})
byt, _ := json.Marshal(filter)
d := json.NewDecoder(bytes.NewReader(byt))
d.UseNumber()
_ = d.Decode(&tmp)
result := make(map[string]*string)
for key, value := range tmp {
filterValue := reflect.ValueOf(value)
flatRepeatedList(filterValue, result, key)
}
m := make(map[string]interface{})
for key, value := range result {
m[key] = dara.StringValue(value)
}
return dara.String(dara.ToFormString(m))
}
func flatRepeatedList(dataValue reflect.Value, result map[string]*string, prefix string) {
if !dataValue.IsValid() {
return
}
dataType := dataValue.Type()
if dataType.Kind().String() == "slice" {
handleRepeatedParams(dataValue, result, prefix)
} else if dataType.Kind().String() == "map" {
handleMap(dataValue, result, prefix)
} else {
result[prefix] = dara.String(fmt.Sprintf("%v", dataValue.Interface()))
}
}
func handleRepeatedParams(repeatedFieldValue reflect.Value, result map[string]*string, prefix string) {
if repeatedFieldValue.IsValid() && !repeatedFieldValue.IsNil() {
for m := 0; m < repeatedFieldValue.Len(); m++ {
elementValue := repeatedFieldValue.Index(m)
key := prefix + "." + strconv.Itoa(m+1)
fieldValue := reflect.ValueOf(elementValue.Interface())
if fieldValue.Kind().String() == "map" {
handleMap(fieldValue, result, key)
} else {
result[key] = dara.String(fmt.Sprintf("%v", fieldValue.Interface()))
}
}
}
}
func handleMap(valueField reflect.Value, result map[string]*string, prefix string) {
var byt []byte
if valueField.IsValid() && valueField.String() != "" {
valueFieldType := valueField.Type()
if valueFieldType.Kind().String() == "map" {
byt, _ = json.Marshal(valueField.Interface())
cache := make(map[string]interface{})
d := json.NewDecoder(bytes.NewReader(byt))
d.UseNumber()
_ = d.Decode(&cache)
for key, value := range cache {
pre := ""
if prefix != "" {
pre = prefix + "." + key
} else {
pre = key
}
fieldValue := reflect.ValueOf(value)
flatRepeatedList(fieldValue, result, pre)
}
}
}
}
// Description:
//
// # Get timestamp
//
// @return the timestamp string
func GetTimestamp() (_result *string) {
gmt := time.FixedZone("GMT", 0)
return dara.String(time.Now().In(gmt).Format("2006-01-02T15:04:05Z"))
}
// Description:
//
// # Get UTC string
//
// @return the UTC string
func GetDateUTCString() (_result *string) {
return dara.String(time.Now().UTC().Format(http.TimeFormat))
}
// Description:
//
// Parse filter into a object which's type is map[string]string
//
// @param filter - query param
//
// @return the object
func Query(filter interface{}) (_result map[string]*string) {
tmp := make(map[string]interface{})
byt, _ := json.Marshal(filter)
d := json.NewDecoder(bytes.NewReader(byt))
d.UseNumber()
_ = d.Decode(&tmp)
result := make(map[string]*string)
for key, value := range tmp {
filterValue := reflect.ValueOf(value)
flatRepeatedList(filterValue, result, key)
}
return result
}
// Description:
//
// # Get signature according to signedParams, method and secret
//
// @param signedParams - params which need to be signed
//
// @param method - http method e.g. GET
//
// @param secret - AccessKeySecret
//
// @return the signature
func GetRPCSignature(signedParams map[string]*string, method *string, secret *string) (_result *string) {
stringToSign := buildRpcStringToSign(signedParams, dara.StringValue(method))
signature := sign(stringToSign, dara.StringValue(secret), "&")
return dara.String(signature)
}
// Description:
//
// # Parse array into a string with specified style
//
// @param array - the array
//
// @param prefix - the prefix string
//
// @return the string
func ArrayToStringWithSpecifiedStyle(array interface{}, prefix *string, style *string) (_result *string) {
if dara.IsNil(array) {
return dara.String("")
}
sty := dara.StringValue(style)
if sty == "repeatList" {
tmp := map[string]interface{}{
dara.StringValue(prefix): array,
}
return flatRepeatList(tmp)
} else if sty == "simple" || sty == "spaceDelimited" || sty == "pipeDelimited" {
return flatArray(array, sty)
} else if sty == "json" {
return dara.String(dara.Stringify(array))
}
return dara.String("")
}
// Description:
//
// # Get the authorization
//
// @param request - request params
//
// @param signatureAlgorithm - the autograph method
//
// @param payload - the hashed request
//
// @param accessKey - the accessKey string
//
// @param accessKeySecret - the accessKeySecret string
//
// @return authorization string
func GetAuthorization(request *dara.Request, signatureAlgorithm *string, payload *string, accessKey *string, accessKeySecret *string) (_result *string) {
canonicalURI := dara.StringValue(request.Pathname)
if canonicalURI == "" {
canonicalURI = "/"
}
canonicalURI = strings.Replace(canonicalURI, "+", "%20", -1)
canonicalURI = strings.Replace(canonicalURI, "*", "%2A", -1)
canonicalURI = strings.Replace(canonicalURI, "%7E", "~", -1)
method := dara.StringValue(request.Method)
canonicalQueryString := getCanonicalQueryString(request.Query)
canonicalheaders, signedHeaders := getCanonicalHeaders(request.Headers)
canonicalRequest := method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalheaders + "\n" +
strings.Join(signedHeaders, ";") + "\n" + dara.StringValue(payload)
signType := dara.StringValue(signatureAlgorithm)
StringToSign := signType + "\n" + hex.EncodeToString(Hash([]byte(canonicalRequest), signatureAlgorithm))
signature := hex.EncodeToString(SignatureMethod(dara.StringValue(accessKeySecret), StringToSign, signType))
auth := signType + " Credential=" + dara.StringValue(accessKey) + ",SignedHeaders=" +
strings.Join(signedHeaders, ";") + ",Signature=" + signature
return dara.String(auth)
}
func GetUserAgent(userAgent *string) (_result *string) {
if userAgent != nil && dara.StringValue(userAgent) != "" {
return dara.String(defaultUserAgent + " " + dara.StringValue(userAgent))
}
return dara.String(defaultUserAgent)
}
func SignatureMethod(secret, source, signatureAlgorithm string) []byte {
if signatureAlgorithm == "ACS3-HMAC-SHA256" {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(source))
return h.Sum(nil)
} else if signatureAlgorithm == "ACS3-HMAC-SM3" {
h := hmac.New(sm3.New, []byte(secret))
h.Write([]byte(source))
return h.Sum(nil)
} else if signatureAlgorithm == "ACS3-RSA-SHA256" {
return rsaSign(source, secret)
}
return nil
}
func flatRepeatList(filter map[string]interface{}) (_result *string) {
tmp := make(map[string]interface{})
byt, _ := json.Marshal(filter)
d := json.NewDecoder(bytes.NewReader(byt))
d.UseNumber()
_ = d.Decode(&tmp)
result := make(map[string]*string)
for key, value := range tmp {
filterValue := reflect.ValueOf(value)
flatRepeatedList(filterValue, result, key)
}
res := make(map[string]string)
for k, v := range result {
res[k] = dara.StringValue(v)
}
hs := newSorter(res)
hs.Sort()
// Get the canonicalizedOSSHeaders
t := ""
for i := range hs.Keys {
if i == len(hs.Keys)-1 {
t += hs.Keys[i] + "=" + hs.Vals[i]
} else {
t += hs.Keys[i] + "=" + hs.Vals[i] + "&&"
}
}
return dara.String(t)
}
func flatArray(array interface{}, sty string) *string {
t := reflect.ValueOf(array)
strs := make([]string, 0)
for i := 0; i < t.Len(); i++ {
tmp := t.Index(i)
if tmp.Kind() == reflect.Ptr || tmp.Kind() == reflect.Interface {
tmp = tmp.Elem()
}
if tmp.Kind() == reflect.Ptr {
tmp = tmp.Elem()
}
if tmp.Kind() == reflect.String {
strs = append(strs, tmp.String())
} else {
inter := tmp.Interface()
byt, _ := json.Marshal(inter)
strs = append(strs, string(byt))
}
}
str := ""
if sty == "simple" {
str = strings.Join(strs, ",")
} else if sty == "spaceDelimited" {
str = strings.Join(strs, " ")
} else if sty == "pipeDelimited" {
str = strings.Join(strs, "|")
}
return dara.String(str)
}
func buildRpcStringToSign(signedParam map[string]*string, method string) (stringToSign string) {
signParams := make(map[string]string)
for key, value := range signedParam {
signParams[key] = dara.StringValue(value)
}
stringToSign = getUrlFormedMap(signParams)
stringToSign = strings.Replace(stringToSign, "+", "%20", -1)
stringToSign = strings.Replace(stringToSign, "*", "%2A", -1)
stringToSign = strings.Replace(stringToSign, "%7E", "~", -1)
stringToSign = url.QueryEscape(stringToSign)
stringToSign = method + "&%2F&" + stringToSign
return
}
func getUrlFormedMap(source map[string]string) (urlEncoded string) {
urlEncoder := url.Values{}
for key, value := range source {
urlEncoder.Add(key, value)
}
urlEncoded = urlEncoder.Encode()
return
}
func sign(stringToSign, accessKeySecret, secretSuffix string) string {
secret := accessKeySecret + secretSuffix
signedBytes := shaHmac1(stringToSign, secret)
signedString := base64.StdEncoding.EncodeToString(signedBytes)
return signedString
}
func shaHmac1(source, secret string) []byte {
key := []byte(secret)
hmac := hmac.New(sha1.New, key)
hmac.Write([]byte(source))
return hmac.Sum(nil)
}
func getTimeLeft(rateLimit *string) (_result *int64) {
if rateLimit != nil {
pairs := strings.Split(dara.StringValue(rateLimit), ",")
for _, pair := range pairs {
kv := strings.Split(pair, ":")
if len(kv) == 2 {
key, value := kv[0], kv[1]
if key == "TimeLeft" {
timeLeftValue, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return nil
}
return dara.Int64(timeLeftValue)
}
}
}
}
return nil
}
func rsaSign(content, secret string) []byte {
h := crypto.SHA256.New()
h.Write([]byte(content))
hashed := h.Sum(nil)
priv, err := parsePrivateKey(secret)
if err != nil {
return nil
}
sign, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed)
if err != nil {
return nil
}
return sign
}
func parsePrivateKey(privateKey string) (*rsa.PrivateKey, error) {
privateKey = formatPrivateKey(privateKey)
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return nil, errors.New("PrivateKey is invalid")
}
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
switch priKey.(type) {
case *rsa.PrivateKey:
return priKey.(*rsa.PrivateKey), nil
default:
return nil, nil
}
}
func formatPrivateKey(privateKey string) string {
if !strings.HasPrefix(privateKey, PEM_BEGIN) {
privateKey = PEM_BEGIN + privateKey
}
if !strings.HasSuffix(privateKey, PEM_END) {
privateKey += PEM_END
}
return privateKey
}
func getCanonicalHeaders(headers map[string]*string) (string, []string) {
tmp := make(map[string]string)
tmpHeader := http.Header{}
for k, v := range headers {
if strings.HasPrefix(strings.ToLower(k), "x-acs-") || strings.ToLower(k) == "host" ||
strings.ToLower(k) == "content-type" {
tmp[strings.ToLower(k)] = strings.TrimSpace(dara.StringValue(v))
tmpHeader.Add(strings.ToLower(k), strings.TrimSpace(dara.StringValue(v)))
}
}
hs := newSorter(tmp)
// Sort the temp by the ascending order
hs.Sort()
canonicalheaders := ""
for _, key := range hs.Keys {
vals := tmpHeader[textproto.CanonicalMIMEHeaderKey(key)]
sort.Strings(vals)
canonicalheaders += key + ":" + strings.Join(vals, ",") + "\n"
}
return canonicalheaders, hs.Keys
}
func getCanonicalQueryString(query map[string]*string) string {
canonicalQueryString := ""
if dara.IsNil(query) {
return canonicalQueryString
}
tmp := make(map[string]string)
for k, v := range query {
tmp[k] = dara.StringValue(v)
}
hs := newSorter(tmp)
// Sort the temp by the ascending order
hs.Sort()
for i := range hs.Keys {
if hs.Vals[i] != "" {
canonicalQueryString += "&" + hs.Keys[i] + "=" + url.QueryEscape(hs.Vals[i])
} else {
canonicalQueryString += "&" + hs.Keys[i] + "="
}
}
canonicalQueryString = strings.Replace(canonicalQueryString, "+", "%20", -1)
canonicalQueryString = strings.Replace(canonicalQueryString, "*", "%2A", -1)
canonicalQueryString = strings.Replace(canonicalQueryString, "%7E", "~", -1)
if canonicalQueryString != "" {
canonicalQueryString = strings.TrimLeft(canonicalQueryString, "&")
}
return canonicalQueryString
}
func ParseToMap(in interface{}) map[string]interface{} {
if dara.IsNil(in) {
return nil
}
tmp := make(map[string]interface{})
byt, _ := json.Marshal(in)
d := json.NewDecoder(bytes.NewReader(byt))
d.UseNumber()
err := d.Decode(&tmp)
if err != nil {
return nil
}
return tmp
}
func GetEndpointRules(product, regionId, endpointType, network, suffix *string) (_result *string, _err error) {
if dara.StringValue(endpointType) == "regional" {
if dara.StringValue(regionId) == "" {
_err = fmt.Errorf("RegionId is empty, please set a valid RegionId")
return dara.String(""), _err
}
_result = dara.String(strings.Replace("<product><suffix><network>.<region_id>.aliyuncs.com",
"<region_id>", dara.StringValue(regionId), 1))
} else {
_result = dara.String("<product><suffix><network>.aliyuncs.com")
}
_result = dara.String(strings.Replace(dara.StringValue(_result),
"<product>", strings.ToLower(dara.StringValue(product)), 1))
if dara.StringValue(network) == "" || dara.StringValue(network) == "public" {
_result = dara.String(strings.Replace(dara.StringValue(_result), "<network>", "", 1))
} else {
_result = dara.String(strings.Replace(dara.StringValue(_result),
"<network>", "-"+dara.StringValue(network), 1))
}
if dara.StringValue(suffix) == "" {
_result = dara.String(strings.Replace(dara.StringValue(_result), "<suffix>", "", 1))
} else {
_result = dara.String(strings.Replace(dara.StringValue(_result),
"<suffix>", "-"+dara.StringValue(suffix), 1))
}
return _result, nil
}
func ToArray(in interface{}) []map[string]interface{} {
tmp := make([]map[string]interface{}, 0)
if dara.IsNil(in) {
return nil
}
byt, _ := json.Marshal(in)
d := json.NewDecoder(bytes.NewReader(byt))
d.UseNumber()
err := d.Decode(&tmp)
if err != nil {
return nil
}
return tmp
}
func GetEndpoint(endpoint *string, server *bool, endpointType *string) *string {
if dara.StringValue(endpointType) == "internal" {
strs := strings.Split(dara.StringValue(endpoint), ".")
strs[0] += "-internal"
endpoint = dara.String(strings.Join(strs, "."))
}
if dara.BoolValue(server) && dara.StringValue(endpointType) == "accelerate" {
return dara.String("oss-accelerate.aliyuncs.com")
}
return endpoint
}
func toJSONString(a interface{}) *string {
switch v := a.(type) {
case *string:
return v
case string:
return dara.String(v)
case []byte:
return dara.String(string(v))
case io.Reader:
byt, err := ioutil.ReadAll(v)
if err != nil {
return nil
}
return dara.String(string(byt))
}
byt := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(byt)
jsonEncoder.SetEscapeHTML(false)
if err := jsonEncoder.Encode(a); err != nil {
return nil
}
return dara.String(string(bytes.TrimSpace(byt.Bytes())))
}
func StringifyMapValue(a map[string]interface{}) map[string]*string {
res := make(map[string]*string)
for key, value := range a {
if value != nil {
res[key] = toJSONString(value)
}
}
return res
}