Files
baseapi/platformapi/jdapi/jdapi.go
2018-08-09 16:52:40 +08:00

320 lines
9.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package jdapi
import (
"crypto/md5"
"encoding/json"
"fmt"
"net/http"
"sort"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
const (
paramJson = "jd_param_json"
)
const (
// ResponseCodeSuccess 操作成功
ResponseCodeSuccess = "0"
// ResponseCodeAccessFailed 操作失败请重试如还不能正常提供服务可以提交工单https://opengd.jd.com详细说明一下开放平台跟进回复。
ResponseCodeAccessFailed = "-1"
// ResponseCodeFailedCanAutoRetry 操作失败系统会自动重试如还不能正常提供服务可以提交工单https://opengd.jd.com详细说明一下开放平台跟进回复。
ResponseCodeFailedCanAutoRetry = "-10000"
ResponseCodeFailedAccessDB = "10000"
// ResponseCodeMissingMandatoryParam 请求参数中缺失必填项信息请检查如不清楚请访问到家开放平台https://opendj.jd.comAPI分组有接口详细说明。
ResponseCodeMissingMandatoryParam = "10005"
ResponseCodeInvalidToken = "10013"
ResponseCodeInvalidSign = "10014"
ResponseCodeAbnormalParam = "10015"
ResponseCodeMethodNotExist = "10018"
ResponseCodeExceedLimit = "10032"
ResponseCodeTimeout = "100022"
ResponseCodeTomcateFailed = "100023"
ResponseCodeLoadUnexpected = "100024"
)
const (
ResponseInnerCodeOrderAlreadyPickedUp = "10132"
ResponseInnerCodeOrderCanceled = "10138"
ResponseInnerCodeOrderLocked = "10139"
)
const (
prodURL = "https://openo2o.jd.com/djapi"
signKey = "sign"
AllPage = 0
DefaultPageSize = 50
)
type API struct {
token string
appKey string
appSecret string
client *http.Client
config *platformapi.APIConfig
}
var (
exceedLimitCodes = map[string]int{
ResponseCodeExceedLimit: 1,
}
canRetryCodes = map[string]int{
ResponseCodeFailedCanAutoRetry: 1,
ResponseCodeAccessFailed: 1,
ResponseCodeFailedAccessDB: 1,
ResponseCodeTimeout: 1,
ResponseCodeTomcateFailed: 1,
ResponseCodeLoadUnexpected: 1,
}
innerCodeKeys = []string{"code", "retCode", "errorCode"}
innerCodeOKCodes = map[string]int{
"None": 1,
"0": 1,
"1": 1,
"200": 1,
"190005": 1, // 部分失败
}
noPageInnerDataKeys = []string{"result", "data"}
havePageInner2DataKeys = []string{"result", "resultList"}
havePageTotalCountKeys = []string{"totalCount", "count"}
)
type PageResultParser func(map[string]interface{}, int) ([]interface{}, int, error)
func (a *API) signParams(jdParams map[string]interface{}) string {
var keys []string
for k := range jdParams {
if k != "app_secret" && k != signKey {
keys = append(keys, k)
}
}
sort.Strings(keys)
secretStr := fmt.Sprint(jdParams["app_secret"])
allStr := secretStr
for _, k := range keys {
allStr += k + fmt.Sprint(jdParams[k])
}
allStr = allStr + secretStr
return fmt.Sprintf("%X", md5.Sum([]byte(allStr)))
}
func New(token, appKey, appSecret string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
token: token,
appKey: appKey,
appSecret: appSecret,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func (a *API) AccessAPI(apiStr string, jdParams map[string]interface{}) (retVal map[string]interface{}, err error) {
params := make(map[string]interface{})
params["v"] = "1.0"
params["format"] = "json"
params["app_key"] = a.appKey
params["app_secret"] = a.appSecret
params["token"] = a.token
if jdParams == nil {
jdParams = make(map[string]interface{}, 0)
}
jdParamStr, err := json.Marshal(jdParams)
if err != nil {
baseapi.SugarLogger.Errorf("Error when marshal %v, error:%v", jdParams, err)
return nil, err
}
params["jd_param_json"] = string(jdParamStr)
params["timestamp"] = utils.GetCurTimeStr()
sign := a.signParams(params)
params[signKey] = sign
request, _ := http.NewRequest(http.MethodGet, utils.GenerateGetURL(prodURL, apiStr, params), nil)
request.Close = true //todo 为了避免EOF错误
err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (errLevel string, err error) {
jsonResult1, err := utils.HTTPResponse2Json(response)
if err != nil {
return platformapi.ErrLevelGeneralFail, platformapi.ErrResponseDataFormatWrong
}
code := jsonResult1["code"].(string)
if code == ResponseCodeSuccess {
retVal = jsonResult1
return platformapi.ErrLevelSuccess, nil
}
newErr := utils.NewErrorCode(jsonResult1["msg"].(string), code)
if _, ok := exceedLimitCodes[code]; ok {
return platformapi.ErrLevelExceedLimit, newErr
} else if _, ok := canRetryCodes[code]; ok {
return platformapi.ErrLevelRecoverableErr, newErr
} else {
return platformapi.ErrLevelCodeIsNotOK, newErr
}
})
return retVal, err
}
func (a *API) AccessAPINoPage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string) (interface{}, error) {
jsonResult, err := a.AccessAPI(apiStr, jdParams)
if err != nil {
return nil, err
}
var data map[string]interface{}
if err := utils.UnmarshalUseNumber([]byte(jsonResult["data"].(string)), &data); err != nil {
return nil, platformapi.ErrResponseDataFormatWrong
}
innerCode := ""
for _, innerCodeKey := range innerCodeKeys {
if innerCode2, ok := data[innerCodeKey]; ok {
innerCode = forceInnerCode2Str(innerCode2)
break
}
}
if _, ok := innerCodeOKCodes[innerCode]; ok {
for _, innerDataKey := range noPageInnerDataKeys {
if innerData, ok := data[innerDataKey]; ok {
return utils.DictKeysMan(innerData, keyToRemove, keyToKeep), nil
}
}
baseapi.SugarLogger.Errorf("can not find inner data, data:%v", jsonResult)
return nil, platformapi.ErrResponseDataFormatWrong
} else {
return nil, utils.NewErrorCode(string(utils.MustMarshal(data)), innerCode, 1)
}
}
func NormalHavePageResultParser(data map[string]interface{}, totalCount int) ([]interface{}, int, error) {
var result map[string]interface{}
var retVal []interface{}
tempResult := data["result"]
if resultStr, ok := tempResult.(string); ok {
if err := utils.UnmarshalUseNumber([]byte(resultStr), &tempResult); err != nil {
return nil, 0, platformapi.ErrResponseDataFormatWrong
}
}
result = tempResult.(map[string]interface{})
if totalCount == 0 {
for _, totalCountKey := range havePageTotalCountKeys {
if totalCount2, ok := result[totalCountKey]; ok {
totalCountInt64, _ := totalCount2.(json.Number).Int64()
totalCount = int(totalCountInt64)
if totalCount == 0 {
return make([]interface{}, 0), 0, nil
}
break
}
}
if totalCount == 0 {
baseapi.SugarLogger.Errorf("can not find totalCount key, data:%v", result)
return nil, 0, platformapi.ErrResponseDataFormatWrong
}
}
for _, inner2ResultKey := range havePageInner2DataKeys {
if inner2Result, ok := result[inner2ResultKey]; ok {
if inner2ResultStr, ok := inner2Result.(string); ok {
err := utils.UnmarshalUseNumber([]byte(inner2ResultStr), &retVal)
if err != nil {
return nil, 0, platformapi.ErrResponseDataFormatWrong
}
} else {
retVal = inner2Result.([]interface{})
}
return retVal, totalCount, nil
}
}
baseapi.SugarLogger.Errorf("can not find result key, data:%v", result)
return nil, 0, platformapi.ErrResponseDataFormatWrong
}
func (a *API) AccessAPIHavePage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string, pageResultParser PageResultParser) ([]interface{}, error) {
if pageResultParser == nil {
pageResultParser = NormalHavePageResultParser
}
localJdParams := make(map[string]interface{})
if jdParams != nil && len(jdParams) > 0 {
for k, v := range jdParams {
localJdParams[k] = v
}
}
totalCount := 0
pageNo := AllPage
pageSize := DefaultPageSize
if tempPageNo, ok := localJdParams["pageNo"]; ok {
pageNo = tempPageNo.(int)
}
if tempPageSize, ok := localJdParams["pageSize"]; ok {
pageSize = tempPageSize.(int)
}
curPage := pageNo
if curPage == AllPage {
curPage = 1
}
retVal := make([]interface{}, 0)
for {
localJdParams["pageNo"] = curPage
localJdParams["pageSize"] = pageSize
jsonResult, err := a.AccessAPI(apiStr, localJdParams)
if err != nil {
return nil, err
}
var data map[string]interface{}
if err := utils.UnmarshalUseNumber([]byte(jsonResult["data"].(string)), &data); err != nil {
return nil, platformapi.ErrResponseDataFormatWrong
}
innerCode := forceInnerCode2Str(data["code"])
if innerCode != "0" && innerCode != "200" {
return nil, utils.NewErrorCode(string(utils.MustMarshal(data)), innerCode, 1)
}
inResult, totalCount2, err := pageResultParser(data, totalCount)
if err != nil {
return nil, err
}
totalCount = totalCount2
inResult = utils.DictKeysMan(inResult, keyToRemove, keyToKeep).([]interface{})
retVal = append(retVal, inResult...)
if curPage == pageNo || curPage*pageSize >= totalCount {
break
}
curPage++
}
return retVal, nil
}
func forceInnerCode2Str(innerCode interface{}) string {
if innerCodeStr, ok := innerCode.(string); ok {
return innerCodeStr
}
return utils.Int64ToStr(utils.Interface2Int64WithDefault(innerCode, 0))
}