From 629aa20fea26bf293165e329f4f329d7191a627d Mon Sep 17 00:00:00 2001 From: gazebo Date: Fri, 18 Oct 2019 12:02:14 +0800 Subject: [PATCH] +autonavi.BatchWalkingDistance --- platformapi/autonavi/autonavi.go | 115 +++++++++++++++++++++++++- platformapi/autonavi/autonavi_test.go | 37 +++++++++ platformapi/platformapi.go | 16 +++- 3 files changed, 162 insertions(+), 6 deletions(-) diff --git a/platformapi/autonavi/autonavi.go b/platformapi/autonavi/autonavi.go index 40f5d7ad..a1e6f89e 100644 --- a/platformapi/autonavi/autonavi.go +++ b/platformapi/autonavi/autonavi.go @@ -1,6 +1,7 @@ package autonavi import ( + "bytes" "crypto/md5" "fmt" "net/http" @@ -12,8 +13,12 @@ import ( ) const ( - signKey = "sig" - prodURL = "https://restapi.amap.com/v3" + signKey = "sig" + prodURL = "https://restapi.amap.com" + prodURLv3 = "/v3" + prodURLFullv3 = prodURL + prodURLv3 + + batchAPIStr = "batch" ) const ( @@ -196,6 +201,16 @@ type RegeoCodeInfo struct { Roads []*RoadInfo `json:"roads"` } +type tBatchAPIParams struct { + APIStr string + APIParams map[string]interface{} +} + +type tBatchAPIResponse struct { + Result ResponseResult + Err error +} + func New(key string, config ...*platformapi.APIConfig) *API { curConfig := platformapi.DefAPIConfig if len(config) > 0 { @@ -236,7 +251,7 @@ func (a *API) AccessAPI(apiStr string, params map[string]interface{}) (retVal Re err = platformapi.AccessPlatformAPIWithRetry(a.client, func() *http.Request { - request, _ := http.NewRequest(http.MethodGet, utils.GenerateGetURL(prodURL, apiStr, params2), nil) + request, _ := http.NewRequest(http.MethodGet, utils.GenerateGetURL(prodURLFullv3, apiStr, params2), nil) return request }, a.config, @@ -262,6 +277,74 @@ func (a *API) AccessAPI(apiStr string, params map[string]interface{}) (retVal Re return retVal, err } +func (a *API) BatchAccessAPI(apiList []*tBatchAPIParams) (retVal []*tBatchAPIResponse, err error) { + if len(apiList) == 0 { + return nil, nil + } + + var ops []map[string]interface{} + for _, v := range apiList { + params2 := utils.MergeMaps(utils.Params2Map("key", a.key, "output", "json"), v.APIParams) + params2[signKey] = a.signParams(params2) + op := make(map[string]interface{}) + op["url"] = utils.GenerateGetURL(prodURLv3, v.APIStr, params2) + ops = append(ops, op) + } + params2 := map[string]interface{}{ + "ops": ops, + } + + err = platformapi.AccessPlatformAPIWithRetry(a.client, + func() *http.Request { + request, _ := http.NewRequest(http.MethodGet, utils.GenerateGetURL(prodURLFullv3, batchAPIStr, utils.Params2Map("key", a.key)), + bytes.NewReader(utils.MustMarshal(params2))) + request.Header.Set("charset", "UTF-8") + request.Header.Set("Content-Type", "application/json") + return request + }, + a.config, + func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) { + if jsonResult1 == nil { + return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil") + } + if resultList, ok := jsonResult1[platformapi.KeyData].([]interface{}); ok { + for _, v := range resultList { + jsonResult1 := v.(map[string]interface{}) + status := int(utils.ForceInterface2Int64(jsonResult1["status"])) + if status == http.StatusOK { + jsonResult1 := v.(map[string]interface{})["body"].(map[string]interface{}) + var retVal2 map[string]interface{} + var err2 error + status := jsonResult1["status"].(string) + if status == StatusCodeSuccess { + retVal2 = jsonResult1 + } else { + infoCode := jsonResult1["infocode"].(string) + err2 = utils.NewErrorCode(jsonResult1["info"].(string), infoCode) + } + retVal = append(retVal, &tBatchAPIResponse{ + Result: retVal2, + Err: err2, + }) + } + } + errLevel = platformapi.ErrLevelSuccess + } else { + infoCode := jsonResult1["infocode"].(string) + err = utils.NewErrorCode(jsonResult1["info"].(string), infoCode) + if _, ok := exceedLimitCodes[infoCode]; ok { + errLevel = platformapi.ErrLevelExceedLimit + } else if _, ok := canRetryCodes[infoCode]; ok { + errLevel = platformapi.ErrLevelRecoverableErr + } else { + errLevel = platformapi.ErrLevelCodeIsNotOK + } + } + return errLevel, err + }) + return retVal, err +} + // 为了方便调用者编码,如果失败,也会返回未转换的原始值 func (a *API) CoordinateConvert(lng, lat float64, coordsys string) (retLng, retLat float64, err error) { // outCoords, err := a.BatchCoordinateConvert([]*Coordinate{ @@ -484,3 +567,29 @@ func (a *API) WalkingDistance(lng1, lat1, lng2, lat2 float64) (distance float64) } return distance } + +func (a *API) BatchWalkingDistance(srcLng, srcLat float64, destCoords []*Coordinate) (distanceList []float64, err error) { + var reqList []*tBatchAPIParams + for _, v := range destCoords { + reqList = append(reqList, &tBatchAPIParams{ + APIStr: "direction/walking", + APIParams: map[string]interface{}{ + "origin": coordinate2String(srcLng, srcLat), + "destination": coordinate2String(v.Lng, v.Lat), + }, + }) + } + resultList, err := a.BatchAccessAPI(reqList) + if err == nil { + for _, v := range resultList { + distance := float64(9527123) + if v.Err == nil { + if paths, _ := v.Result["route"].(map[string]interface{})["paths"].([]interface{}); len(paths) > 0 { + distance = utils.Interface2Float64WithDefault(paths[0].(map[string]interface{})["distance"], 0) + } + } + distanceList = append(distanceList, distance) + } + } + return distanceList, err +} diff --git a/platformapi/autonavi/autonavi_test.go b/platformapi/autonavi/autonavi_test.go index 2ac13aae..cac5cc94 100644 --- a/platformapi/autonavi/autonavi_test.go +++ b/platformapi/autonavi/autonavi_test.go @@ -112,3 +112,40 @@ func TestGeoCodeRegeo(t *testing.T) { } t.Log(utils.Format4Output(result, false)) } + +func TestBatchWalkingDistance(t *testing.T) { + result, err := autonaviAPI.BatchWalkingDistance(104.052756, 30.685203, []*Coordinate{ + &Coordinate{ + Lng: 104.052756, + Lat: 30.687203, + }, + &Coordinate{ + Lng: 104.032756, + Lat: 30.685203, + }, + &Coordinate{ + Lng: 104.032756, + Lat: 30.685203, + }, + &Coordinate{ + Lng: 104.032756, + Lat: 30.685203, + }, + &Coordinate{ + Lng: 104.032756, + Lat: 30.685203, + }, + &Coordinate{ + Lng: 104.032756, + Lat: 30.685203, + }, + &Coordinate{ + Lng: 104.032756, + Lat: 30.685203, + }, + }) + if err != nil { + t.Fatal(err) + } + t.Log(utils.Format4Output(result, false)) +} diff --git a/platformapi/platformapi.go b/platformapi/platformapi.go index 7b313a73..5d4b761a 100644 --- a/platformapi/platformapi.go +++ b/platformapi/platformapi.go @@ -24,6 +24,7 @@ const ( DefMaxRecoverableRetryCount = 1 // 可恢复类错误(一般指网络错),最大重试次数 KeyTrackInfo = "TrackInfo" + KeyData = "fakeData" ) type APIRetryConfig struct { @@ -147,6 +148,7 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http. } var ( errLevel string + bodyGeneral interface{} bodyMap map[string]interface{} parseJSONErr error ) @@ -155,15 +157,23 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http. baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s ioutil.ReadAll failed, url:%v, request:%v, error:%v", trackInfo, request.URL, getClonedData(request.URL, savedBuf), err) errLevel = ErrLevelRecoverableErr // 读取数据错误,或数据格式错误认为是偶发情况,重试 } else { - if err = utils.TryUnmarshalUseNumber(bodyData, &bodyMap); err != nil { + if err = utils.TryUnmarshalUseNumber(bodyData, &bodyGeneral); err != nil { parseJSONErr = err err = nil // 尝试忽略解析成json错 } else { - baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry:%s url:%v, response:%s", trackInfo, request.URL, utils.Format4Output(bodyMap, true)) + baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry:%s url:%v, response:%s", trackInfo, request.URL, utils.Format4Output(bodyGeneral, true)) + } + // 临时处理返回值居然不是map的情况 + if bodyMap2, ok := bodyGeneral.(map[string]interface{}); ok { + bodyMap = bodyMap2 + } else { + bodyMap = map[string]interface{}{ + KeyData: bodyGeneral, + } } errLevel, err = handleResponse(response, string(bodyData), bodyMap) if err != nil && parseJSONErr != nil { - const maxOutputLen = 200 + const maxOutputLen = 2000 bodyDataLen := len(bodyData) bodyData2 := bodyData if bodyDataLen > maxOutputLen {