package autonavi import ( "crypto/md5" "fmt" "net/http" "sort" "strings" "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) request, _ := http.NewRequest(http.MethodGet, utils.GenerateGetURL(prodURL, apiStr, params2), nil) 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 } 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 lng, lat, err }