- dadaapi added.

- refactor.
This commit is contained in:
gazebo
2018-06-21 14:23:01 +08:00
parent e1b377086e
commit 851b2c1eeb
10 changed files with 424 additions and 70 deletions

View File

@@ -0,0 +1,83 @@
package dadaapi
import (
"crypto/md5"
"fmt"
"sort"
"strings"
"github.com/fatih/structs"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
)
const (
DadaResponseHttpCodeSuccess = 200
DadaResponseHttpCodeGeneralErr = 555
)
type DadaCallbackMsg struct {
ClientId string `json:"client_id"`
OrderId string `json:"order_id"`
OrderStatus int `json:"order_status"`
CancelReason string `json:"cancel_reason"`
CancelFrom int `json:"cancel_from"`
UpdateTime int `json:"update_time"`
Signature string `json:"signature"`
DmId int `json:"dm_id"`
DmName string `json:"dm_name"`
DmMobile string `json:"dm_mobile"`
}
type DadaCallbackResponse struct {
Code int
Dummy string `json:"dummy"`
}
var (
SuccessResponse = &DadaCallbackResponse{Code: DadaResponseHttpCodeSuccess}
FailedResponse = &DadaCallbackResponse{Code: DadaResponseHttpCodeGeneralErr}
)
func (d *DadaAPI) signParamsCallback(mapData map[string]interface{}) string {
values := make([]string, 0)
for k, v := range mapData {
if k != signKey {
values = append(values, fmt.Sprint(v))
}
}
sort.Strings(values)
finalStr := strings.Join(values, "")
// baseapi.SugarLogger.Debugf("sign str:%v", finalStr)
return fmt.Sprintf("%x", md5.Sum([]byte(finalStr)))
}
func (d *DadaAPI) unmarshalData(data []byte, msg interface{}) (callbackResponse *DadaCallbackResponse) {
err := utils.UnmarshalUseNumber(data, msg)
if err != nil {
return FailedResponse
}
return nil
}
func (d *DadaAPI) CheckCallbackValidation(mapData map[string]interface{}) (callbackResponse *DadaCallbackResponse) {
sign := d.signParamsCallback(mapData)
if remoteSign, _ := mapData[signKey].(string); sign != remoteSign {
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, remoteSign)
return FailedResponse
}
return nil
}
func (d *DadaAPI) GetOrderCallbackMsg(data []byte) (orderMsg *DadaCallbackMsg, callbackResponse *DadaCallbackResponse) {
orderMsg = new(DadaCallbackMsg)
if callbackResponse = d.unmarshalData(data, orderMsg); callbackResponse != nil {
return nil, FailedResponse
}
mapData := structs.Map(orderMsg)
callbackResponse = d.CheckCallbackValidation(mapData)
return orderMsg, callbackResponse
}

141
platform/dadaapi/dadaapi.go Normal file
View File

@@ -0,0 +1,141 @@
package dadaapi
import (
"bytes"
"crypto/md5"
"fmt"
"net/http"
"sort"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platform/common"
"git.rosy.net.cn/baseapi/utils"
)
const (
dadaSandboxURL = "http://newopen.qa.imdada.cn/"
dadaProdURL = "http://newopen.imdada.cn/"
signKey = "signature"
)
const (
clientTimeout = time.Second * 10
sleepSecondWhenLimited = 6 * time.Second
maxRetryCountWhenNetworkException = 3
maxRetryCountWhenReachLimited = 10
)
const (
DadaCodeException = -1
DadaCodeSuccess = 0
DadaCodeSignErr = 2003
DadaCodeRetryLater = 2012
DadaCodeNetworkErr = 2455
)
type DadaAPI struct {
appKey string
appSecret string
sourceId string
url string
callbackURL string
client *http.Client
}
type DadaResult struct {
Status string `json:"status"`
Code int `json:"code"`
Msg string `json:"msg"`
Result map[string]interface{} `json:"result"`
ErrorCode int `json:"errorCode"`
}
func NewDadaAPI(appKey, appSecret, sourceId, callbackURL string, isProd bool) *DadaAPI {
api := &DadaAPI{
appKey: appKey,
appSecret: appSecret,
sourceId: sourceId,
callbackURL: callbackURL,
client: &http.Client{Timeout: clientTimeout},
}
if isProd {
api.url = dadaProdURL
} else {
api.url = dadaSandboxURL
}
return api
}
func (d *DadaAPI) signParams(mapData map[string]interface{}) string {
keys := make([]string, 0)
for k := range mapData {
keys = append(keys, k)
}
sort.Strings(keys)
finalStr := d.appSecret
for _, k := range keys {
if k != signKey {
finalStr += k + fmt.Sprint(mapData[k])
}
}
finalStr += d.appSecret
// baseapi.SugarLogger.Debugf("sign str:%v", finalStr)
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
}
func (d *DadaAPI) AccessDada(action string, params map[string]interface{}) (retVal *DadaResult, err error) {
params2 := make(map[string]interface{})
params2["app_key"] = d.appKey
params2["timestamp"] = utils.Int64ToStr(utils.GetCurTimestamp())
params2["format"] = "json"
params2["v"] = "1.0"
params2["source_id"] = d.sourceId
if params == nil {
params2["body"] = ""
} else {
params2["body"] = string(utils.MustMarshal(params))
}
params2[signKey] = d.signParams(params2)
params2Bytes := utils.MustMarshal(params2)
request, _ := http.NewRequest("POST", d.url+action, bytes.NewReader(params2Bytes))
request.Header.Set("Content-Type", "application/json")
apiAccess := &common.AccessPlatformAPIWithRetryParams{
MaxExceedLimitRetryCount: maxRetryCountWhenReachLimited,
MaxRecoverableRetryCount: maxRetryCountWhenNetworkException,
SleepSecondWhenExceedLimit: sleepSecondWhenLimited,
Client: d.client,
Request: request,
}
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result string, err error) {
jsonResult1, err := utils.HttpResponse2Json(response)
if err != nil {
baseapi.SugarLogger.Warnf("HttpResponse2Json return:%v", err)
return common.PAErrorLevelGeneralFail, err
}
code := int(utils.MustInterface2Int64(jsonResult1["code"]))
retVal = &DadaResult{
Code: code,
ErrorCode: code,
Msg: jsonResult1["msg"].(string),
Status: jsonResult1["status"].(string),
}
if code == DadaCodeSuccess {
retVal.Result = jsonResult1["result"].(map[string]interface{})
return common.PAErrorLevelSuccess, nil
}
baseapi.SugarLogger.Debug(jsonResult1)
if code == DadaCodeRetryLater || code == DadaCodeNetworkErr {
return common.PAErrorLevelRecoverable, nil
}
return common.PAErrorLevelGeneralFail, utils.NewErrorIntCode(retVal.Msg, code)
})
return retVal, err
}

View File

@@ -0,0 +1,51 @@
package dadaapi
import (
"testing"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"go.uber.org/zap"
)
var (
dadaapi *DadaAPI
sugarLogger *zap.SugaredLogger
)
func init() {
logger, _ := zap.NewDevelopment()
sugarLogger = logger.Sugar()
baseapi.Init(sugarLogger)
// sandbox
dadaapi = NewDadaAPI("dada9623324449cd250", "30c2abbfe8a8780ad5aace46300c64b9", "73753", "", false)
// prod
}
func TestTest(t *testing.T) {
sugarLogger.Debug(utils.GetCurTimeStr())
}
func TestAccessDada(t *testing.T) {
body := make(map[string]interface{})
body["order_id"] = "fakeorderid"
result, err := dadaapi.AccessDada("api/order/status/query", body)
failed := true
if err != nil {
if err2, ok := err.(*utils.ErrorWithCode); ok {
if err2.IntCode() != DadaCodeSignErr {
failed = false
}
}
} else {
failed = false
}
if failed {
t.Fatalf("Error when accessing api result:%v, error:%v", result, err)
}
}

85
platform/dadaapi/order.go Normal file
View File

@@ -0,0 +1,85 @@
package dadaapi
import (
"git.rosy.net.cn/baseapi/utils"
"github.com/fatih/structs"
)
type OperateOrderRequiredParams struct {
ShopNo string `json:"shop_no"`
OriginId string `json:"origin_id"`
CityCode string `json:"city_code"`
CargoPrice float64 `json:"cargo_price"`
IsPrepay int `json:"is_prepay"`
ReceiverName string `json:"receiver_name"`
ReceiverAddress string `json:"receiver_address"`
ReceiverLat float64 `json:"receiver_lat"`
ReceiverLng float64 `json:"receiver_lng"`
}
type CreateOrderResponse struct {
Distance float64
Fee float64
DeliverFee float64
CouponFee float64
Tips float64
InsuranceFee float64
}
func (d *DadaAPI) QueryOrderInfo(orderId string) (retVal map[string]interface{}, err error) {
params := make(map[string]interface{})
params["order_id"] = orderId
result, err := d.AccessDada("api/order/status/query", params)
if err != nil {
return nil, err
}
return result.Result, nil
}
func map2CreateOrderResponse(mapData map[string]interface{}) *CreateOrderResponse {
retVal := new(CreateOrderResponse)
retVal.Distance = utils.MustInterface2Float64(mapData["distance"])
retVal.Fee = utils.MustInterface2Float64(mapData["fee"])
retVal.DeliverFee = utils.MustInterface2Float64(mapData["deliverFee"])
if value, ok := mapData["couponFee"]; ok {
retVal.CouponFee = utils.MustInterface2Float64(value)
}
if value, ok := mapData["tips"]; ok {
retVal.CouponFee = utils.MustInterface2Float64(value)
}
if value, ok := mapData["insuranceFee"]; ok {
retVal.CouponFee = utils.MustInterface2Float64(value)
}
return retVal
}
func (d *DadaAPI) operateOrder(action string, orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
params := structs.Map(orderInfo)
params["callback"] = d.callbackURL
allParams := utils.MergeMaps(params, addParams)
result, err := d.AccessDada(action, allParams)
if err != nil {
return nil, err
}
return map2CreateOrderResponse(result.Result), nil
}
func (d *DadaAPI) AddOrder(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
return d.operateOrder("api/order/addOrder", orderInfo, addParams)
}
func (d *DadaAPI) ReaddOrder(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
return d.operateOrder("api/order/reAddOrder", orderInfo, addParams)
}
func (d *DadaAPI) QueryDeliverFee(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
return d.operateOrder("api/order/queryDeliverFee", orderInfo, addParams)
}
func (d *DadaAPI) AddOrderAfterQuery(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
return d.operateOrder("api/order/addAfterQuery", orderInfo, addParams)
}