Files
baseapi/platform/elmapi/elmapi.go
2018-06-14 14:45:19 +08:00

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
}