diff --git a/platformapi/autonavi/autonavi.go b/platformapi/autonavi/autonavi.go new file mode 100644 index 00000000..bc41daef --- /dev/null +++ b/platformapi/autonavi/autonavi.go @@ -0,0 +1,148 @@ +package autonavi + +import ( + "crypto/md5" + "fmt" + "net/http" + "net/url" + "sort" + "strings" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" +) + +const ( + signKey = "sig" + prodURL = "https://restapi.amap.com/v3" +) + +const ( + StatusCodeFailed = "0" + StatusCodeSuccess = "1" +) + +const ( + InfoCode_OK = "10000" + InfoCode_ACCESS_TOO_FREQUENT = "10004" + InfoCode_QPS_HAS_EXCEEDED_THE_LIMIT = "10014" + InfoCode_SERVER_IS_BUSY = "10016" + InfoCode_RESOURCE_UNAVAILABLE = "10017" + InfoCode_CQPS_HAS_EXCEEDED_THE_LIMIT = "10019" + InfoCode_CKQPS_HAS_EXCEEDED_THE_LIMIT = "10020" + InfoCode_CIQPS_HAS_EXCEEDED_THE_LIMIT = "10021" + InfoCode_CIKQPS_HAS_EXCEEDED_THE_LIMIT = "10022" + InfoCode_KQPS_HAS_EXCEEDED_THE_LIMIT = "10023" +) + +const ( + CoordSysAutonavi = "autonavi" + CoordSysGPS = "gps" + CoordSysMapbar = "mapbar" + CoordSysBaidu = "baidu" +) + +var ( + exceedLimitCodes = map[string]int{ + InfoCode_ACCESS_TOO_FREQUENT: 1, + InfoCode_QPS_HAS_EXCEEDED_THE_LIMIT: 1, + InfoCode_CQPS_HAS_EXCEEDED_THE_LIMIT: 1, + InfoCode_CKQPS_HAS_EXCEEDED_THE_LIMIT: 1, + InfoCode_CIQPS_HAS_EXCEEDED_THE_LIMIT: 1, + InfoCode_CIKQPS_HAS_EXCEEDED_THE_LIMIT: 1, + InfoCode_KQPS_HAS_EXCEEDED_THE_LIMIT: 1, + } + + canRetryCodes = map[string]int{ + InfoCode_SERVER_IS_BUSY: 1, + } +) + +type ResponseResult map[string]interface{} + +type API struct { + client *http.Client + config *platformapi.APIConfig + key string +} + +func New(key string, config ...*platformapi.APIConfig) *API { + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + return &API{ + key: key, + client: &http.Client{Timeout: curConfig.ClientTimeout}, + config: &curConfig, + } +} + +func (a *API) signParams(mapData map[string]interface{}) string { + keys := make([]string, 0) + for k := range mapData { + if k != signKey { + keys = append(keys, k) + } + } + sort.Strings(keys) + + finalStr := "" + for _, k := range keys { + finalStr += k + "=" + fmt.Sprint(mapData[k]) + } + + // baseapi.SugarLogger.Debugf("sign str:%v", finalStr) + return fmt.Sprintf("%X", md5.Sum([]byte(finalStr))) +} + +func (a *API) AccessAPI(apiStr string, params map[string]interface{}) (retVal ResponseResult, err error) { + params2 := utils.MergeMaps(utils.Params2Map("key", a.key, "output", "json"), params) + params2[signKey] = a.signParams(params2) + + finalURL, _ := url.Parse(utils.GenerateGetURL(prodURL, apiStr, params2)) + request := &http.Request{ + Method: "GET", + URL: finalURL, + } + 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 + } + status := jsonResult1["status"].(string) + if status == StatusCodeSuccess { + retVal = jsonResult1 + return platformapi.ErrLevelSuccess, nil + } + baseapi.SugarLogger.Warnf("response business code is not ok, data:%v, status:%v", jsonResult1, status) + infoCode := jsonResult1["infocode"].(string) + newErr := utils.NewErrorCode(jsonResult1["info"].(string), infoCode) + if _, ok := exceedLimitCodes[infoCode]; ok { + return platformapi.ErrLevelExceedLimit, newErr + } else if _, ok := canRetryCodes[infoCode]; ok { + return platformapi.ErrLevelRecoverableErr, newErr + } else { + return platformapi.ErrLevelCodeIsNotOK, newErr + } + }) + return retVal, err +} + +func (a *API) CoordinateConvert(lng, lat float64, coordsys string) (retLng, retLat float64, err error) { + if coordsys == "" || coordsys == CoordSysAutonavi { + return lng, lat, nil + } + params := map[string]interface{}{ + "locations": fmt.Sprintf("%.6f,%.6f", lng, lat), + "coordsys": coordsys, + } + result, err := a.AccessAPI("assistant/coordinate/convert", params) + if err == nil { + coordinate := result["locations"].(string) + index := strings.Index(coordinate, ",") + return utils.Str2Float64(coordinate[:index]), utils.Str2Float64(coordinate[index+1:]), nil + } + return 0.0, 0.0, err +} diff --git a/platformapi/autonavi/autonavi_test.go b/platformapi/autonavi/autonavi_test.go new file mode 100644 index 00000000..fa6fab8d --- /dev/null +++ b/platformapi/autonavi/autonavi_test.go @@ -0,0 +1,37 @@ +package autonavi + +import ( + "testing" + + "git.rosy.net.cn/baseapi" + + "go.uber.org/zap" +) + +var ( + autonaviAPI *API + sugarLogger *zap.SugaredLogger +) + +func init() { + logger, _ := zap.NewDevelopment() + sugarLogger = logger.Sugar() + baseapi.Init(sugarLogger) + + autonaviAPI = New("4427170f870af2110becb8852d36ab08") +} + +func TestCoordinateConvert(t *testing.T) { + gpsLng := 116.481499 + gpsLat := 39.990475 + desiredLng := 116.487585177952 + desiredLat := 39.991754014757 + lng, lat, err := autonaviAPI.CoordinateConvert(gpsLng, gpsLat, CoordSysGPS) + if err != nil { + t.Fatalf("TestCoordinateConvert failed with error:%v", err) + } else { + if lng != desiredLng || lat != desiredLat { + t.Fatal("CoordinateConvert result is wrong") + } + } +} diff --git a/platformapi/jdapi/jdapi.go b/platformapi/jdapi/jdapi.go index 13c30d97..04773d0d 100644 --- a/platformapi/jdapi/jdapi.go +++ b/platformapi/jdapi/jdapi.go @@ -142,10 +142,10 @@ func (a *API) AccessAPI(apiStr string, jdParams map[string]interface{}) (retVal sign := a.signParams(params) params[signKey] = sign - url, _ := url.Parse(utils.GenerateGetURL(prodURL, apiStr, params)) + finalURL, _ := url.Parse(utils.GenerateGetURL(prodURL, apiStr, params)) request := &http.Request{ Method: "GET", - URL: url, + URL: finalURL, } err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (errLevel string, err error) { jsonResult1, err := utils.HTTPResponse2Json(response) diff --git a/platformapi/jdapi/order.go b/platformapi/jdapi/order.go index d9b04f6e..db0773e9 100644 --- a/platformapi/jdapi/order.go +++ b/platformapi/jdapi/order.go @@ -39,6 +39,16 @@ const ( DeliveryStatusFinished = "40" ) +const ( + PromotionTypeNormal = 1 + PromotionTypeSeckill = 2 + PromotionTypeDirectDown = 3 + PromotionTypeLimitedTime = 4 + PromotionTypeAddMoneyBuy = 1202 + PromotionTypeOverflowGiveGift = 1203 + PromotionTypeBuyGiveGift = 6 +) + func (a API) OrderQuery(jdParams map[string]interface{}) (retVal []interface{}, err error) { retVal, err = a.AccessAPIHavePage("order/es/query", jdParams, nil, nil, nil) return diff --git a/platformapi/mtpsapi/mtpsapi.go b/platformapi/mtpsapi/mtpsapi.go index 00628f62..196ade0f 100644 --- a/platformapi/mtpsapi/mtpsapi.go +++ b/platformapi/mtpsapi/mtpsapi.go @@ -129,6 +129,16 @@ type CreateOrderByShopParam struct { OrderType int `json:"order_type"` } +type GoodsItem struct { + GoodCount int `json:"goodCount"` + GoodName string `json:"goodName"` + GoodPrice float64 `json:"goodPrice"` + GoodUnit string `json:"goodUnit"` +} +type GoodsDetail struct { + Goods []*GoodsItem `json:"goods"` +} + type API struct { appKey string secret string diff --git a/utils/typeconv.go b/utils/typeconv.go index 0d5b0b18..487b7231 100644 --- a/utils/typeconv.go +++ b/utils/typeconv.go @@ -15,6 +15,10 @@ import ( "git.rosy.net.cn/baseapi" ) +var ( + DefaultTimeValue = Str2Time("1970-01-01 00:00:00") +) + func GetConcretValue(value reflect.Value) reflect.Value { for { if value.Kind() == reflect.Interface || value.Kind() == reflect.Ptr { @@ -41,10 +45,55 @@ func MustMarshal(obj interface{}) []byte { if err != nil { panic(fmt.Sprintf("err when Marshal obj:%v", obj)) } - return byteArr } +func MustInterface2Int64(data interface{}) int64 { + dataNumber, ok := data.(json.Number) + if !ok { + panic(fmt.Sprintf("error when cast:%v to int64", data)) + } + retVal, err := dataNumber.Int64() + if err != nil { + panic(err.Error()) + } + return retVal +} + +func Interface2Int64WithDefault(data interface{}, defValue int64) int64 { + if data == nil { + return defValue + } + return MustInterface2Int64(data) +} + +func MustInterface2Float64(data interface{}) float64 { + dataNumber, ok := data.(json.Number) + if !ok { + panic(fmt.Sprintf("error when convert:%v", data)) + } + retVal, err := dataNumber.Float64() + if err != nil { + panic(err.Error()) + } + return retVal +} + +func Interface2FloatWithDefault(data interface{}, defValue float64) (retVal float64) { + if data == nil { + return defValue + } + return MustInterface2Float64(data) +} + +func Interface2String(data interface{}) string { + if data == nil { + return "" + } + return data.(string) +} + +// func Bool2String(value bool) string { if value { return "true" @@ -84,44 +133,6 @@ func Int2Str(value int) string { return strconv.Itoa(value) } -func MustInterface2Int64(data interface{}) int64 { - dataNumber, ok := data.(json.Number) - if !ok { - panic(fmt.Sprintf("error when cast:%v to int64", data)) - } - retVal, err := dataNumber.Int64() - if err != nil { - panic(err.Error()) - } - return retVal -} - -func MustInterface2Float64(data interface{}) float64 { - dataNumber, ok := data.(json.Number) - if !ok { - panic(fmt.Sprintf("error when convert:%v", data)) - } - retVal, err := dataNumber.Float64() - if err != nil { - panic(err.Error()) - } - return retVal -} - -func Interface2Float64(data interface{}) (retVal float64) { - if dataNumber, ok := data.(json.Number); ok { - retVal, _ = dataNumber.Float64() - } - return retVal -} - -func Interface2String(data interface{}) string { - if data == nil { - return "" - } - return data.(string) -} - // timestamp is in second func Timestamp2Str(timestamp int64) string { return Time2Str(time.Unix(timestamp, 0)) @@ -139,7 +150,16 @@ func Str2Time(timeStr string) time.Time { timeStr = strings.Replace(timeStr, "T", " ", 1) retVal, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local) if err != nil { - baseapi.SugarLogger.Errorf("ParseInLocation failed, timeStr:%v, error:%v", timeStr, err) + baseapi.SugarLogger.Errorf("time.ParseInLocation failed, timeStr:%v, error:%v", timeStr, err) + } + return retVal +} + +func Str2TimeWithDefault(timeStr string, defValue time.Time) time.Time { + timeStr = strings.Replace(timeStr, "T", " ", 1) + retVal, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local) + if err != nil { + return defValue } return retVal }