160 lines
4.1 KiB
Go
160 lines
4.1 KiB
Go
package elmapi
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.rosy.net.cn/baseapi/platform/common"
|
|
"git.rosy.net.cn/baseapi/utils"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const (
|
|
clientTimeout = time.Second * 10
|
|
sleepSecondWhenLimited = 6 * time.Second
|
|
maxRetryCountWhenNetworkException = 3
|
|
maxRetryCountWhenReachLimited = 10
|
|
)
|
|
|
|
const (
|
|
ELM_API_URL_SANDBOX = "https://open-api-sandbox.shop.ele.me/api/v1/"
|
|
ELM_API_URL_PROD = "https://open-api.shop.ele.me/api/v1/"
|
|
)
|
|
|
|
type ELMResult struct {
|
|
Id string
|
|
Result interface{}
|
|
Error map[string]interface{}
|
|
}
|
|
|
|
type ELMAPI struct {
|
|
token string
|
|
appKey string
|
|
secret string
|
|
sugarLogger *zap.SugaredLogger
|
|
url *url.URL
|
|
client *http.Client
|
|
}
|
|
|
|
type ELMPayload struct {
|
|
Token string `json:"token"`
|
|
Nop string `json:"nop"`
|
|
Metas map[string]interface{} `json:"metas"`
|
|
Params map[string]interface{} `json:"params"`
|
|
Action string `json:"action"`
|
|
Id string `json:"id"`
|
|
Signature string `json:"signature"`
|
|
}
|
|
|
|
func NewELMAPI(token, appKey, secret string, sugarLogger *zap.SugaredLogger, isProd bool) *ELMAPI {
|
|
api := &ELMAPI{
|
|
token: token,
|
|
appKey: appKey,
|
|
secret: secret,
|
|
sugarLogger: sugarLogger,
|
|
client: &http.Client{Timeout: clientTimeout},
|
|
}
|
|
|
|
if isProd {
|
|
api.url, _ = url.Parse(ELM_API_URL_PROD)
|
|
} else {
|
|
api.url, _ = url.Parse(ELM_API_URL_SANDBOX)
|
|
}
|
|
return api
|
|
}
|
|
|
|
func (e *ELMAPI) signParams(action string, payload *ELMPayload) string {
|
|
keyValues := make([]string, 0)
|
|
allData := []map[string]interface{}{
|
|
payload.Metas,
|
|
payload.Params,
|
|
}
|
|
for _, data := range allData {
|
|
for k, v := range data {
|
|
vBytes := utils.MustMarshal(v)
|
|
keyValues = append(keyValues, k+"="+string(vBytes))
|
|
}
|
|
}
|
|
|
|
sort.Strings(keyValues)
|
|
finalStr := action + e.token + strings.Join(keyValues, "") + e.secret
|
|
// e.sugarLogger.Debugf("sign str:%v", finalStr)
|
|
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
|
}
|
|
|
|
func (e *ELMAPI) AccessELM(action string, params map[string]interface{}) (retVal *ELMResult, err error) {
|
|
if params == nil {
|
|
params = make(map[string]interface{}, 0)
|
|
}
|
|
metas := map[string]interface{}{
|
|
"app_key": e.appKey,
|
|
"timestamp": utils.GetCurTimestamp(),
|
|
}
|
|
|
|
payload := &ELMPayload{
|
|
Token: e.token,
|
|
Nop: "1.0.0",
|
|
Metas: metas,
|
|
Params: params,
|
|
Action: action,
|
|
Id: utils.GetUUID(),
|
|
}
|
|
|
|
payload.Signature = e.signParams(action, payload)
|
|
|
|
apiAccess := &common.AccessPlatformAPIWithRetryParams{
|
|
MaxExceedLimitRetryCount: maxRetryCountWhenReachLimited,
|
|
MaxRecoverableRetryCount: maxRetryCountWhenNetworkException,
|
|
SleepSecondWhenExceedLimit: sleepSecondWhenLimited,
|
|
Client: e.client,
|
|
Request: &http.Request{
|
|
Method: "POST",
|
|
URL: e.url,
|
|
Header: http.Header{
|
|
"Content-Type": []string{"application/json; charset=utf-8"},
|
|
"Content-Encoding": []string{"gzip, deflate"},
|
|
"User-Agent": []string{"eleme-golang-api"},
|
|
// "x-eleme-requestid": []string{payload.Id},
|
|
},
|
|
|
|
Body: ioutil.NopCloser(strings.NewReader(string(utils.MustMarshal(payload)))),
|
|
},
|
|
SugarLogger: e.sugarLogger,
|
|
}
|
|
|
|
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result int, err error) {
|
|
jsonResult1, err := utils.HttpResponse2Json(response)
|
|
if err != nil {
|
|
e.sugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
|
return 0, err
|
|
}
|
|
resultError, _ := jsonResult1["error"].(map[string]interface{})
|
|
retVal = &ELMResult{
|
|
Id: jsonResult1["id"].(string),
|
|
Error: resultError,
|
|
Result: jsonResult1["result"],
|
|
}
|
|
errinfoMap := retVal.Error
|
|
if errinfoMap == nil {
|
|
return common.PAErrorLevelSuccess, nil
|
|
}
|
|
errCode := errinfoMap["code"].(string)
|
|
|
|
if errCode == "EXCEED_LIMIT" {
|
|
return common.PAErrorLevelExceedLimit, nil
|
|
} else if errCode == "SERVER_ERROR" || errCode == "BIZ_SYSTEM_ERROR" || errCode == "BIZ_1006" || errCode == "BUSINESS_ERROR" {
|
|
return common.PAErrorLevelRecoverable, nil
|
|
} else {
|
|
return common.PAErrorLevelFailed, nil
|
|
}
|
|
})
|
|
|
|
return retVal, err
|
|
}
|