- add callback sign check.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,17 +20,20 @@ type AccessPlatformAPIWithRetryParams struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PAErrorLevelSuccess = 0
|
PAErrorLevelSuccess = "JXC4_SUCCESS"
|
||||||
PAErrorLevelExceedLimit = 1
|
PAErrorLevelExceedLimit = "JXC4_EXCEED_LIMIT"
|
||||||
PAErrorLevelRecoverable = 2
|
PAErrorLevelRecoverable = "JXC4_RECOVERABLE"
|
||||||
PAErrorLevelFailed = 3
|
PAErrorLevelGeneralFail = "JXC4_GENERAL_FAIL"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrRecoverableErrMaxRetry = errors.New("recoverable error reach max retry count!")
|
ErrRecoverableErrMaxRetry = errors.New("recoverable error reach max retry count!")
|
||||||
ErrLimitReachMaxRetry = errors.New("Reach max retry count!")
|
ErrLimitReachMaxRetry = errors.New("Reach max retry count!")
|
||||||
ErrHttpCode = errors.New("HTTP Code is not 200")
|
)
|
||||||
ErrBusinessCode = errors.New("Business code is not ok")
|
|
||||||
|
var (
|
||||||
|
ErrStrHttpCode = "HTTP Code is not 200"
|
||||||
|
ErrStrBusinessCode = "Business code is not ok"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -37,7 +41,7 @@ var (
|
|||||||
CBErrMsgUnmarshal = "can not unmarshal data:%v, data:%v"
|
CBErrMsgUnmarshal = "can not unmarshal data:%v, data:%v"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AccessPlatformAPIWithRetry(params *AccessPlatformAPIWithRetryParams, handleResponse func(response *http.Response) (int, error)) error {
|
func AccessPlatformAPIWithRetry(params *AccessPlatformAPIWithRetryParams, handleResponse func(response *http.Response) (string, error)) error {
|
||||||
exceedLimitRetryCount := 0
|
exceedLimitRetryCount := 0
|
||||||
recoverableErrorRetryCount := 0
|
recoverableErrorRetryCount := 0
|
||||||
for {
|
for {
|
||||||
@@ -60,29 +64,29 @@ func AccessPlatformAPIWithRetry(params *AccessPlatformAPIWithRetryParams, handle
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrHttpCode
|
return utils.NewErrorIntCode(ErrStrHttpCode, response.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
errLevel, err := handleResponse(response)
|
errCode, err := handleResponse(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if errLevel == PAErrorLevelSuccess {
|
if errCode == PAErrorLevelSuccess {
|
||||||
return nil
|
return nil
|
||||||
} else if errLevel == PAErrorLevelExceedLimit {
|
} else if errCode == PAErrorLevelExceedLimit {
|
||||||
exceedLimitRetryCount++
|
exceedLimitRetryCount++
|
||||||
if exceedLimitRetryCount <= params.MaxExceedLimitRetryCount {
|
if exceedLimitRetryCount <= params.MaxExceedLimitRetryCount {
|
||||||
time.Sleep(params.SleepSecondWhenExceedLimit)
|
time.Sleep(params.SleepSecondWhenExceedLimit)
|
||||||
} else {
|
} else {
|
||||||
return ErrLimitReachMaxRetry
|
return ErrLimitReachMaxRetry
|
||||||
}
|
}
|
||||||
} else if errLevel == PAErrorLevelRecoverable {
|
} else if errCode == PAErrorLevelRecoverable {
|
||||||
if recoverableErrorRetryCount <= params.MaxRecoverableRetryCount {
|
if recoverableErrorRetryCount <= params.MaxRecoverableRetryCount {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return ErrRecoverableErrMaxRetry
|
return ErrRecoverableErrMaxRetry
|
||||||
} else {
|
} else {
|
||||||
return ErrBusinessCode
|
return utils.NewErrorCode(ErrStrBusinessCode, errCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package elmapi
|
package elmapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
"git.rosy.net.cn/baseapi/platform/common"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
"github.com/fatih/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -36,7 +37,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (e *ELMAPI) unmarshalData(data []byte, msg interface{}) (callbackResponse *ELMCallbackResponse) {
|
func (e *ELMAPI) unmarshalData(data []byte, msg interface{}) (callbackResponse *ELMCallbackResponse) {
|
||||||
err := json.Unmarshal(data, msg)
|
err := utils.UnmarshalUseNumber(data, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ELMCallbackResponse{
|
return &ELMCallbackResponse{
|
||||||
Message: fmt.Sprintf(common.CBErrMsgUnmarshal, data, err),
|
Message: fmt.Sprintf(common.CBErrMsgUnmarshal, data, err),
|
||||||
@@ -45,11 +46,22 @@ func (e *ELMAPI) unmarshalData(data []byte, msg interface{}) (callbackResponse *
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *ELMAPI) CheckRequestValidation(mapData map[string]interface{}) (callbackResponse *ELMCallbackResponse) {
|
||||||
|
sign := e.signParamsMap(mapData, "")
|
||||||
|
if sign != mapData[signKey].(string) {
|
||||||
|
return &ELMCallbackResponse{Message: "signature is invalid"}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *ELMAPI) GetMsgFromData(data []byte) (msg *ELMCallbackMsg, callbackResponse *ELMCallbackResponse) {
|
func (e *ELMAPI) GetMsgFromData(data []byte) (msg *ELMCallbackMsg, callbackResponse *ELMCallbackResponse) {
|
||||||
msg = new(ELMCallbackMsg)
|
msg = new(ELMCallbackMsg)
|
||||||
callbackResponse = e.unmarshalData(data, msg)
|
callbackResponse = e.unmarshalData(data, msg)
|
||||||
if callbackResponse != nil {
|
if callbackResponse != nil {
|
||||||
return nil, callbackResponse
|
return nil, callbackResponse
|
||||||
}
|
}
|
||||||
return msg, nil
|
|
||||||
|
mapData := structs.Map(msg)
|
||||||
|
callbackResponse = e.CheckRequestValidation(mapData)
|
||||||
|
return msg, callbackResponse
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const (
|
|||||||
const (
|
const (
|
||||||
ELM_API_URL_SANDBOX = "https://open-api-sandbox.shop.ele.me/api/v1/"
|
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/"
|
ELM_API_URL_PROD = "https://open-api.shop.ele.me/api/v1/"
|
||||||
|
signKey = "signature"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ELMResult struct {
|
type ELMResult struct {
|
||||||
@@ -69,25 +70,26 @@ func NewELMAPI(token, appKey, secret string, sugarLogger *zap.SugaredLogger, isP
|
|||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ELMAPI) signParams(action string, payload *ELMPayload) string {
|
func (e *ELMAPI) signParamsMap(mapData map[string]interface{}, prefix string) string {
|
||||||
keyValues := make([]string, 0)
|
keyValues := make([]string, 0)
|
||||||
allData := []map[string]interface{}{
|
for k, v := range mapData {
|
||||||
payload.Metas,
|
if k != signKey {
|
||||||
payload.Params,
|
|
||||||
}
|
|
||||||
for _, data := range allData {
|
|
||||||
for k, v := range data {
|
|
||||||
vBytes := utils.MustMarshal(v)
|
vBytes := utils.MustMarshal(v)
|
||||||
keyValues = append(keyValues, k+"="+string(vBytes))
|
keyValues = append(keyValues, k+"="+string(vBytes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keyValues)
|
sort.Strings(keyValues)
|
||||||
finalStr := action + e.token + strings.Join(keyValues, "") + e.secret
|
finalStr := prefix + strings.Join(keyValues, "") + e.secret
|
||||||
// e.sugarLogger.Debugf("sign str:%v", finalStr)
|
// e.sugarLogger.Debugf("sign str:%v", finalStr)
|
||||||
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *ELMAPI) signParams(action string, payload *ELMPayload) string {
|
||||||
|
mapData := utils.MergeMaps(payload.Metas, payload.Params)
|
||||||
|
return e.signParamsMap(mapData, action+e.token)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *ELMAPI) AccessELM(action string, params map[string]interface{}) (retVal *ELMResult, err error) {
|
func (e *ELMAPI) AccessELM(action string, params map[string]interface{}) (retVal *ELMResult, err error) {
|
||||||
if params == nil {
|
if params == nil {
|
||||||
params = make(map[string]interface{}, 0)
|
params = make(map[string]interface{}, 0)
|
||||||
@@ -128,11 +130,11 @@ func (e *ELMAPI) AccessELM(action string, params map[string]interface{}) (retVal
|
|||||||
SugarLogger: e.sugarLogger,
|
SugarLogger: e.sugarLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result int, err error) {
|
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result string, err error) {
|
||||||
jsonResult1, err := utils.HttpResponse2Json(response)
|
jsonResult1, err := utils.HttpResponse2Json(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.sugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
e.sugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
||||||
return 0, err
|
return common.PAErrorLevelGeneralFail, err
|
||||||
}
|
}
|
||||||
resultError, _ := jsonResult1["error"].(map[string]interface{})
|
resultError, _ := jsonResult1["error"].(map[string]interface{})
|
||||||
retVal = &ELMResult{
|
retVal = &ELMResult{
|
||||||
@@ -151,7 +153,7 @@ func (e *ELMAPI) AccessELM(action string, params map[string]interface{}) (retVal
|
|||||||
} else if errCode == "SERVER_ERROR" || errCode == "BIZ_SYSTEM_ERROR" || errCode == "BIZ_1006" || errCode == "BUSINESS_ERROR" {
|
} else if errCode == "SERVER_ERROR" || errCode == "BIZ_SYSTEM_ERROR" || errCode == "BIZ_1006" || errCode == "BUSINESS_ERROR" {
|
||||||
return common.PAErrorLevelRecoverable, nil
|
return common.PAErrorLevelRecoverable, nil
|
||||||
} else {
|
} else {
|
||||||
return common.PAErrorLevelFailed, nil
|
return errCode, nil
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package jdapi
|
package jdapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
"git.rosy.net.cn/baseapi/platform/common"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JDCallbackResponse struct {
|
type JDCallbackResponse struct {
|
||||||
@@ -43,7 +43,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (j *JDAPI) unmarshalData(strData string, msg interface{}) (callbackResponse *JDCallbackResponse) {
|
func (j *JDAPI) unmarshalData(strData string, msg interface{}) (callbackResponse *JDCallbackResponse) {
|
||||||
err := json.Unmarshal([]byte(strData), msg)
|
err := utils.UnmarshalUseNumber([]byte(strData), msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &JDCallbackResponse{
|
return &JDCallbackResponse{
|
||||||
Code: JDerrorCodeAbnormalParam,
|
Code: JDerrorCodeAbnormalParam,
|
||||||
@@ -54,7 +54,32 @@ func (j *JDAPI) unmarshalData(strData string, msg interface{}) (callbackResponse
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *JDAPI) CheckRequestValidation(request *http.Request) (callbackResponse *JDCallbackResponse) {
|
||||||
|
mapData := make(map[string]string)
|
||||||
|
mapData["token"] = request.FormValue("token")
|
||||||
|
mapData["app_key"] = request.FormValue("app_key")
|
||||||
|
mapData["timestamp"] = request.FormValue("timestamp")
|
||||||
|
mapData["format"] = request.FormValue("format")
|
||||||
|
mapData["app_secret"] = j.appSecret
|
||||||
|
mapData["v"] = request.FormValue("token")
|
||||||
|
mapData[JD_PARAM_JSON] = request.FormValue(JD_PARAM_JSON)
|
||||||
|
|
||||||
|
sign := j.signParams(mapData)
|
||||||
|
if sign != request.FormValue(signKey) {
|
||||||
|
return &JDCallbackResponse{
|
||||||
|
Code: JDerrorCodeInvalidSign,
|
||||||
|
Msg: "signature is invalid",
|
||||||
|
Data: string(utils.MustMarshal(mapData)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (j *JDAPI) GetOrderMsg(request *http.Request) (msg *JDOrderMsg, callbackResponse *JDCallbackResponse) {
|
func (j *JDAPI) GetOrderMsg(request *http.Request) (msg *JDOrderMsg, callbackResponse *JDCallbackResponse) {
|
||||||
|
if callbackResponse = j.CheckRequestValidation(request); callbackResponse != nil {
|
||||||
|
return nil, callbackResponse
|
||||||
|
}
|
||||||
|
|
||||||
msg = new(JDOrderMsg)
|
msg = new(JDOrderMsg)
|
||||||
jdParamJSON := request.FormValue(JD_PARAM_JSON)
|
jdParamJSON := request.FormValue(JD_PARAM_JSON)
|
||||||
callbackResponse = j.unmarshalData(jdParamJSON, msg)
|
callbackResponse = j.unmarshalData(jdParamJSON, msg)
|
||||||
@@ -65,8 +90,11 @@ func (j *JDAPI) GetOrderMsg(request *http.Request) (msg *JDOrderMsg, callbackRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (j *JDAPI) GetOrderDeliveryMsg(request *http.Request) (msg *JDDeliveryStatusMsg, callbackResponse *JDCallbackResponse) {
|
func (j *JDAPI) GetOrderDeliveryMsg(request *http.Request) (msg *JDDeliveryStatusMsg, callbackResponse *JDCallbackResponse) {
|
||||||
msg = new(JDDeliveryStatusMsg)
|
if callbackResponse = j.CheckRequestValidation(request); callbackResponse != nil {
|
||||||
|
return nil, callbackResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = new(JDDeliveryStatusMsg)
|
||||||
jdParamJSON := request.FormValue(JD_PARAM_JSON)
|
jdParamJSON := request.FormValue(JD_PARAM_JSON)
|
||||||
jdParamJSON2, err := url.QueryUnescape(jdParamJSON)
|
jdParamJSON2, err := url.QueryUnescape(jdParamJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package jdapi
|
|||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -51,6 +50,7 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
jdAPIURL = "https://openo2o.jd.com/djapi/%s"
|
jdAPIURL = "https://openo2o.jd.com/djapi/%s"
|
||||||
|
signKey = "sign"
|
||||||
AllPage = 0
|
AllPage = 0
|
||||||
DefaultPageSize = 50
|
DefaultPageSize = 50
|
||||||
)
|
)
|
||||||
@@ -64,7 +64,7 @@ type JDAPI struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInnerCodeIsNotOk = errors.New("JD result inner code is not ok")
|
ErrStrInnerCodeIsNotOk = "JD result inner code is not ok"
|
||||||
|
|
||||||
exceedLimitCodes = map[string]int{
|
exceedLimitCodes = map[string]int{
|
||||||
JDErrorCodeExceedLimit: 1,
|
JDErrorCodeExceedLimit: 1,
|
||||||
@@ -97,10 +97,10 @@ var (
|
|||||||
|
|
||||||
type PageResultParser func(map[string]interface{}, int) ([]interface{}, int)
|
type PageResultParser func(map[string]interface{}, int) ([]interface{}, int)
|
||||||
|
|
||||||
func signParams(jdParams map[string]string) string {
|
func (j *JDAPI) signParams(jdParams map[string]string) string {
|
||||||
var keys []string
|
var keys []string
|
||||||
for k := range jdParams {
|
for k := range jdParams {
|
||||||
if k != "app_secret" {
|
if k != "app_secret" && k != signKey {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,8 +154,8 @@ func (j *JDAPI) AccessJDQuery(apiStr string, jdParams map[string]string) (retVal
|
|||||||
}
|
}
|
||||||
params["jd_param_json"] = string(jdParamStr)
|
params["jd_param_json"] = string(jdParamStr)
|
||||||
params["timestamp"] = utils.GetCurTimeStr()
|
params["timestamp"] = utils.GetCurTimeStr()
|
||||||
sign := signParams(params)
|
sign := j.signParams(params)
|
||||||
params["sign"] = sign
|
params[signKey] = sign
|
||||||
|
|
||||||
url, _ := url.Parse(genGetURL(jdAPIURL, apiStr, params))
|
url, _ := url.Parse(genGetURL(jdAPIURL, apiStr, params))
|
||||||
|
|
||||||
@@ -171,16 +171,16 @@ func (j *JDAPI) AccessJDQuery(apiStr string, jdParams map[string]string) (retVal
|
|||||||
SugarLogger: j.sugarLogger,
|
SugarLogger: j.sugarLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (errLevel int, err error) {
|
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (errLevel string, err error) {
|
||||||
jsonResult1, err := utils.HttpResponse2Json(response)
|
jsonResult1, err := utils.HttpResponse2Json(response)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
j.sugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
j.sugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
||||||
return 0, err
|
return common.PAErrorLevelGeneralFail, err
|
||||||
}
|
}
|
||||||
|
|
||||||
code := jsonResult1["code"].(string)
|
code := jsonResult1["code"].(string)
|
||||||
if code == "0" {
|
if code == JDErrorCodeSuccess {
|
||||||
retVal = jsonResult1
|
retVal = jsonResult1
|
||||||
return common.PAErrorLevelSuccess, nil
|
return common.PAErrorLevelSuccess, nil
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ func (j *JDAPI) AccessJDQuery(apiStr string, jdParams map[string]string) (retVal
|
|||||||
} else if _, ok := canRetryCodes[code]; ok {
|
} else if _, ok := canRetryCodes[code]; ok {
|
||||||
return common.PAErrorLevelRecoverable, nil
|
return common.PAErrorLevelRecoverable, nil
|
||||||
} else {
|
} else {
|
||||||
return common.PAErrorLevelFailed, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
@@ -227,7 +227,7 @@ func (j *JDAPI) AccessJDQueryNoPage(apiStr string, jdParams map[string]string, k
|
|||||||
}
|
}
|
||||||
panic("Can not find inner data")
|
panic("Can not find inner data")
|
||||||
} else {
|
} else {
|
||||||
return jsonResult, ErrInnerCodeIsNotOk
|
return jsonResult, utils.NewErrorCode(ErrStrInnerCodeIsNotOk, innerCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ func (j *JDAPI) AccessJDQueryHavePage(apiStr string, jdParams map[string]string,
|
|||||||
|
|
||||||
innerCode := forceInnerCode2Str(data["code"])
|
innerCode := forceInnerCode2Str(data["code"])
|
||||||
if innerCode != "0" && innerCode != "200" {
|
if innerCode != "0" && innerCode != "200" {
|
||||||
return nil, ErrInnerCodeIsNotOk
|
return nil, utils.NewErrorCode(ErrStrInnerCodeIsNotOk, innerCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
inResult, totalCount2 := pageResultParser(data, totalCount)
|
inResult, totalCount2 := pageResultParser(data, totalCount)
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package mtpsapi
|
package mtpsapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MtpsCallbackResponse struct {
|
type MtpsCallbackResponse struct {
|
||||||
Code string `json:"code"`
|
Code int `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MtpsCallbackCommon struct {
|
type MtpsCallbackCommon struct {
|
||||||
@@ -35,14 +34,21 @@ type MtpsCallbackOrderExceptionMsg struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
SuccessResponse = &MtpsCallbackResponse{Code: "0"}
|
SuccessResponse = &MtpsCallbackResponse{Code: 0}
|
||||||
|
SignatureIsNotOk = &MtpsCallbackResponse{Code: -1}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *MTPSAPI) CheckRequestValidation(request *http.Request) (callbackResponse *MtpsCallbackResponse) {
|
func (m *MTPSAPI) CheckRequestValidation(request *http.Request) (callbackResponse *MtpsCallbackResponse) {
|
||||||
|
request.ParseForm()
|
||||||
|
sign := m.signParams(request.PostForm)
|
||||||
|
if sign != request.FormValue(signKey) {
|
||||||
|
return SignatureIsNotOk
|
||||||
|
}
|
||||||
|
|
||||||
for _, valueKey := range []string{"delivery_id", "mt_peisong_id", "order_id"} {
|
for _, valueKey := range []string{"delivery_id", "mt_peisong_id", "order_id"} {
|
||||||
if request.FormValue(valueKey) == "" {
|
if request.FormValue(valueKey) == "" {
|
||||||
return &MtpsCallbackResponse{
|
return &MtpsCallbackResponse{
|
||||||
Code: fmt.Sprintf("missing param:%s", valueKey),
|
Code: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,56 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
mtpsAPIURL = "https://peisongopen.meituan.com/api"
|
mtpsAPIURL = "https://peisongopen.meituan.com/api"
|
||||||
|
signKey = "sign"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
mtpsStatusSuccess = 0
|
OrderStatusWaitingForSchedule = 0
|
||||||
mtpsStatusSystemError = 1
|
OrderStatusAccepted = 20
|
||||||
mtpsStatusMissingSystemParams = 2
|
OrderStatusPickedUp = 30
|
||||||
mtpsStatusMissingBusinessParams = 3
|
OrderStatusDeliverred = 50
|
||||||
|
OrderStatusCanceled = 99
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DSCRapid = 4011
|
||||||
|
DSCIntime = 4012
|
||||||
|
DSCTogether = 4013
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PickupTypeClientSendToStation = 1
|
||||||
|
PickupTypeMtPick = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrderTypeASAP = 0
|
||||||
|
OrderTypeBook = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CoordinateTypeMars = 0
|
||||||
|
CoordinateTypeBaidu = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// 错误码
|
||||||
|
const (
|
||||||
|
ResponseCodeSuccess = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// 取消原因
|
||||||
|
const (
|
||||||
|
CancelReasonClientActive = 101
|
||||||
|
CancelReasonClientChangeTimeOrAddress = 102
|
||||||
|
CancelReasonGoodRelated = 103
|
||||||
|
CancelReasonMerchantOther = 199
|
||||||
|
|
||||||
|
CancelReasonMtpsAttitude = 201
|
||||||
|
CancelReasonRidderSendNotIntime = 202
|
||||||
|
CancelReasonRideerGetGoodNotIntime = 203
|
||||||
|
CancelReasonRideerMtpsOther = 299
|
||||||
|
|
||||||
|
CancelReasonRideerOther = 399
|
||||||
)
|
)
|
||||||
|
|
||||||
type MtpsOrderInfoCommon struct {
|
type MtpsOrderInfoCommon struct {
|
||||||
@@ -61,27 +104,6 @@ type MTPSResult struct {
|
|||||||
Data map[string]interface{} `json:"data"`
|
Data map[string]interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
DSCRapid = 4011
|
|
||||||
DSCIntime = 4012
|
|
||||||
DSCTogether = 403
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PickupTypeClientSendToStation = 1
|
|
||||||
PickupTypeMtPick = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
OrderTypeASAP = 0
|
|
||||||
OrderTypeBook = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
CoordinateTypeMars = 0
|
|
||||||
CoordinateTypeBaidu = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
type MtpsCreateOrderByShopInfo struct {
|
type MtpsCreateOrderByShopInfo struct {
|
||||||
DeliveryId int64
|
DeliveryId int64
|
||||||
OrderId string
|
OrderId string
|
||||||
@@ -118,17 +140,23 @@ func NewMTPSAPI(appKey, secret string, sugarLogger *zap.SugaredLogger) *MTPSAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) signParams(params url.Values) string {
|
func (m *MTPSAPI) signParams(params url.Values) string {
|
||||||
keyValues := make([]string, 0)
|
keys := make([]string, 0)
|
||||||
for k, v := range params {
|
for k := range params {
|
||||||
valStr := strings.Join(v, "")
|
if k != signKey {
|
||||||
if valStr != "" {
|
keys = append(keys, k)
|
||||||
keyValues = append(keyValues, k+valStr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keyValues)
|
sort.Strings(keys)
|
||||||
finalStr := m.secret + strings.Join(keyValues, "")
|
finalStr := m.secret
|
||||||
// e.sugarLogger.Debugf("sign str:%v", finalStr)
|
for _, key := range keys {
|
||||||
|
valStr := strings.Join(params[key], "")
|
||||||
|
if valStr != "" {
|
||||||
|
finalStr += key + valStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// m.sugarLogger.Debug(finalStr)
|
||||||
return fmt.Sprintf("%x", sha1.Sum([]byte(finalStr)))
|
return fmt.Sprintf("%x", sha1.Sum([]byte(finalStr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +172,8 @@ func (m *MTPSAPI) AccessMTPS(action string, params map[string]interface{}) (retV
|
|||||||
params2["appkey"] = []string{m.appKey}
|
params2["appkey"] = []string{m.appKey}
|
||||||
params2["timestamp"] = []string{utils.Int64ToStr(utils.GetCurTimestamp())}
|
params2["timestamp"] = []string{utils.Int64ToStr(utils.GetCurTimestamp())}
|
||||||
params2["version"] = []string{"1.0"}
|
params2["version"] = []string{"1.0"}
|
||||||
params2["sign"] = []string{m.signParams(params2)}
|
params2[signKey] = []string{m.signParams(params2)}
|
||||||
|
// m.sugarLogger.Debug(params2.Encode())
|
||||||
request, _ := http.NewRequest("POST", mtpsAPIURL+"/"+action, strings.NewReader(params2.Encode()))
|
request, _ := http.NewRequest("POST", mtpsAPIURL+"/"+action, strings.NewReader(params2.Encode()))
|
||||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
apiAccess := &common.AccessPlatformAPIWithRetryParams{
|
apiAccess := &common.AccessPlatformAPIWithRetryParams{
|
||||||
@@ -157,30 +185,38 @@ func (m *MTPSAPI) AccessMTPS(action string, params map[string]interface{}) (retV
|
|||||||
SugarLogger: m.sugarLogger,
|
SugarLogger: m.sugarLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result int, err error) {
|
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result string, err error) {
|
||||||
jsonResult1, err := utils.HttpResponse2Json(response)
|
jsonResult1, err := utils.HttpResponse2Json(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.sugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
m.sugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
||||||
return 0, err
|
return common.PAErrorLevelGeneralFail, err
|
||||||
}
|
}
|
||||||
code := int(utils.MustInterface2Int64(jsonResult1["code"]))
|
code := int(utils.MustInterface2Int64(jsonResult1["code"]))
|
||||||
retVal = &MTPSResult{
|
retVal = &MTPSResult{
|
||||||
Code: code,
|
Code: code,
|
||||||
}
|
}
|
||||||
m.sugarLogger.Debug(jsonResult1)
|
m.sugarLogger.Debug(jsonResult1)
|
||||||
if code == mtpsStatusSuccess {
|
if code == ResponseCodeSuccess {
|
||||||
if innerData, ok := jsonResult1["data"]; ok {
|
if innerData, ok := jsonResult1["data"]; ok {
|
||||||
retVal.Data, _ = innerData.(map[string]interface{})
|
retVal.Data, _ = innerData.(map[string]interface{})
|
||||||
}
|
}
|
||||||
return common.PAErrorLevelSuccess, nil
|
return common.PAErrorLevelSuccess, nil
|
||||||
}
|
}
|
||||||
retVal.Message = jsonResult1["message"].(string)
|
retVal.Message = jsonResult1["message"].(string)
|
||||||
return common.PAErrorLevelFailed, nil
|
return common.PAErrorLevelGeneralFail, utils.NewErrorIntCode(retVal.Message, code)
|
||||||
})
|
})
|
||||||
|
|
||||||
return retVal, err
|
return retVal, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MTPSAPI) result2OrderResponse(result *MTPSResult) (order *MtpsOrderResponse) {
|
||||||
|
order = new(MtpsOrderResponse)
|
||||||
|
order.MtPeisongId = result.Data["mt_peisong_id"].(string)
|
||||||
|
order.DeliveryId = utils.MustInterface2Int64(result.Data["delivery_id"])
|
||||||
|
order.OrderId = result.Data["order_id"].(string)
|
||||||
|
return order
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) CreateOrderByShop(basicParams *MtpsCreateOrderByShopInfo, addParams map[string]interface{}) (order *MtpsOrderResponse, err error) {
|
func (m *MTPSAPI) CreateOrderByShop(basicParams *MtpsCreateOrderByShopInfo, addParams map[string]interface{}) (order *MtpsOrderResponse, err error) {
|
||||||
params := make(map[string]interface{})
|
params := make(map[string]interface{})
|
||||||
params["delivery_id"] = utils.Int64ToStr(basicParams.DeliveryId)
|
params["delivery_id"] = utils.Int64ToStr(basicParams.DeliveryId)
|
||||||
@@ -207,13 +243,9 @@ func (m *MTPSAPI) CreateOrderByShop(basicParams *MtpsCreateOrderByShopInfo, addP
|
|||||||
}
|
}
|
||||||
if result, err := m.AccessMTPS("order/createByShop", params); err != nil {
|
if result, err := m.AccessMTPS("order/createByShop", params); err != nil {
|
||||||
m.sugarLogger.Debugf("result:%v", result)
|
m.sugarLogger.Debugf("result:%v", result)
|
||||||
return nil, err
|
return nil, utils.NewErrorIntCode(err.Error(), result.Code)
|
||||||
} else {
|
} else {
|
||||||
order = new(MtpsOrderResponse)
|
return m.result2OrderResponse(result), nil
|
||||||
order.MtPeisongId = result.Data["mt_peisong_id"].(string)
|
|
||||||
order.DeliveryId = utils.MustInterface2Int64(result.Data["delivery_id"])
|
|
||||||
order.OrderId = result.Data["order_id"].(string)
|
|
||||||
return order, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +261,22 @@ func (m *MTPSAPI) QueryOrderStatus(deliveryId int64, mtPeiSongId string) (retVal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MTPSAPI) CancelOrder(deliveryId int64, mtPeiSongId string, cancelReasonId int, cancelReason string) (result *MtpsOrderResponse, err error) {
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"delivery_id": deliveryId,
|
||||||
|
"mt_peisong_id": mtPeiSongId,
|
||||||
|
"cancel_reason_id": cancelReasonId,
|
||||||
|
"cancel_reason": cancelReason,
|
||||||
|
}
|
||||||
|
if result, err := m.AccessMTPS("order/delete", params); err != nil {
|
||||||
|
m.sugarLogger.Debugf("result:%v", result)
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return m.result2OrderResponse(result), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) simulateOrderBehavior(action string, deliveryId int64, mtPeiSongId string) (err error) {
|
func (m *MTPSAPI) simulateOrderBehavior(action string, deliveryId int64, mtPeiSongId string) (err error) {
|
||||||
params := map[string]interface{}{
|
params := map[string]interface{}{
|
||||||
"delivery_id": deliveryId,
|
"delivery_id": deliveryId,
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ func init() {
|
|||||||
// mtpsapi = NewMTPSAPI("3c0a05d464c247c19d7ec13accc78605", "b1M}9?:sTbsB[OF2gNORnN(|(iy9rB8(`7]|[wGLnbmt`evfM>E:A90DjHAW:UPE", sugarLogger)
|
// mtpsapi = NewMTPSAPI("3c0a05d464c247c19d7ec13accc78605", "b1M}9?:sTbsB[OF2gNORnN(|(iy9rB8(`7]|[wGLnbmt`evfM>E:A90DjHAW:UPE", sugarLogger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleError(t *testing.T, err error) {
|
||||||
|
if err != nil {
|
||||||
|
sugarLogger.Debug(err)
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestTest(t *testing.T) {
|
func TestTest(t *testing.T) {
|
||||||
sugarLogger.Debug(utils.GetCurTimeStr())
|
sugarLogger.Debug(utils.GetCurTimeStr())
|
||||||
}
|
}
|
||||||
@@ -59,11 +65,39 @@ func TestCreateOrderByShop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
order, err := mtpsapi.CreateOrderByShop(basicParams, nil)
|
order, err := mtpsapi.CreateOrderByShop(basicParams, nil)
|
||||||
|
handleError(t, err)
|
||||||
if order != nil {
|
if order != nil {
|
||||||
sugarLogger.Debugf("order:%v", order)
|
sugarLogger.Debugf("order:%v", order)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
|
||||||
sugarLogger.Debugf("err:%s", err.Error())
|
func TestSimulateArrange(t *testing.T) {
|
||||||
}
|
err := mtpsapi.SimulateArrange(123456789, "1529387562097059")
|
||||||
|
handleError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimulatePickup(t *testing.T) {
|
||||||
|
err := mtpsapi.SimulatePickup(123456789, "1529387562097059")
|
||||||
|
handleError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimulateRearrange(t *testing.T) {
|
||||||
|
err := mtpsapi.SimulateRearrange(123456789, "1529387562097059")
|
||||||
|
handleError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimulateDeliver(t *testing.T) {
|
||||||
|
err := mtpsapi.SimulateDeliver(123456789, "1529387562097059")
|
||||||
|
handleError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimulateReportException(t *testing.T) {
|
||||||
|
err := mtpsapi.SimulateReportException(123456789, "1529387562097059")
|
||||||
|
handleError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCancelOrder(t *testing.T) {
|
||||||
|
result, err := mtpsapi.CancelOrder(123456789, "1529387562097059", CancelReasonMerchantOther, "just a test")
|
||||||
|
handleError(t, err)
|
||||||
|
sugarLogger.Debug(result)
|
||||||
}
|
}
|
||||||
|
|||||||
38
utils/errorwithcode.go
Normal file
38
utils/errorwithcode.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorWithCode struct {
|
||||||
|
str string
|
||||||
|
code string
|
||||||
|
intCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewErrorCode(err, code string) *ErrorWithCode {
|
||||||
|
return &ErrorWithCode{
|
||||||
|
str: err,
|
||||||
|
code: code,
|
||||||
|
intCode: Str2Int(code),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewErrorIntCode(err string, code int) *ErrorWithCode {
|
||||||
|
return &ErrorWithCode{
|
||||||
|
str: err,
|
||||||
|
code: Int2Str(code),
|
||||||
|
intCode: code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (e *ErrorWithCode) Error() string {
|
||||||
|
return fmt.Sprintf("%s, code:%s", e.str, e.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrorWithCode) Code() string {
|
||||||
|
return e.code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrorWithCode) IntCode() int {
|
||||||
|
return e.intCode
|
||||||
|
}
|
||||||
@@ -173,3 +173,15 @@ func MustInterface2Int64(data interface{}) int64 {
|
|||||||
}
|
}
|
||||||
return retVal
|
return retVal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MergeMaps(firstMap map[string]interface{}, otherMaps ...map[string]interface{}) (retVal map[string]interface{}) {
|
||||||
|
retVal = make(map[string]interface{})
|
||||||
|
allMaps := append(otherMaps, firstMap)
|
||||||
|
for _, oneMap := range allMaps {
|
||||||
|
for k, v := range oneMap {
|
||||||
|
retVal[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,3 +30,47 @@ func TestDictKeysMan(t *testing.T) {
|
|||||||
t.Error("Params keysToKeep keep wrong key!")
|
t.Error("Params keysToKeep keep wrong key!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TestModel struct {
|
||||||
|
IntData int
|
||||||
|
Int64Data int64
|
||||||
|
FloatData float64
|
||||||
|
StrData string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestModel2 struct {
|
||||||
|
IntData int
|
||||||
|
Int64Data int64
|
||||||
|
FloatData float64
|
||||||
|
AddData string
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshStr(t *testing.T, jsonStr string, obj interface{}) {
|
||||||
|
|
||||||
|
err := UnmarshalUseNumber([]byte(jsonStr), obj)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJson(t *testing.T) {
|
||||||
|
jsonStr := `
|
||||||
|
{
|
||||||
|
"IntData": 1,
|
||||||
|
"Int64Data": 1234567890123456,
|
||||||
|
"FloatData": 1234.5678,
|
||||||
|
"StrData": "str"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
obj1 := make(map[string]interface{})
|
||||||
|
var obj2 interface{}
|
||||||
|
var obj3 TestModel
|
||||||
|
var obj4 TestModel2
|
||||||
|
|
||||||
|
unmarshStr(t, jsonStr, &obj1)
|
||||||
|
unmarshStr(t, jsonStr, &obj2)
|
||||||
|
unmarshStr(t, jsonStr, &obj3)
|
||||||
|
unmarshStr(t, jsonStr, &obj4)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user