Files
baseapi/platformapi/baidunavi/baidunavi.go
邹宗楠 d26e0e5406 1
2023-09-11 14:55:40 +08:00

272 lines
7.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package baidunavi
import (
"crypto/md5"
"encoding/json"
"fmt"
"git.rosy.net.cn/jx-callback/globals"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
const (
signKey = "sn"
resultKey = "result"
prodURL = "http://api.map.baidu.com"
prodURL2 = "https://api.map.baidu.com"
)
const (
StatusCodeSuccess = 0
StatusCodeInternalErr = 1 // 服务器内部错误
StatusCodeParamsErr = 2 //参数无效
StatusCodeNoReturn = 7 //无返回结果
StatusCodeExceedDailyQuota = 301 // 永久配额超限,限制访问
StatusCodeExceedQuota = 302 // 天配额超限,限制访问
StatusCodeExceedDailyConcurrentQuota = 401 // 当前并发量已经超过约定并发配额,限制访问
StatusCodeExceedConcurrentQuota = 402 // 当前并发量已经超过约定并发配额,并且服务总并发量也已经超过设定的总并发配额,限制访问
)
const (
CoordSysWGS84 = 1 // GPS设备获取的角度坐标WGS84坐标
CoordSysGCJ02 = 3 // google地图、soso地图、aliyun地图、mapabc地图和amap地图所用坐标国测局GCJ02坐标
CoordSysBaiDu = 5 // 百度地图采用的经纬度坐标
)
const (
MaxCoordsConvBatchSize = 100
)
var (
exceedLimitCodes = map[int]int{
StatusCodeExceedDailyQuota: 1,
StatusCodeExceedQuota: 1,
StatusCodeExceedDailyConcurrentQuota: 1,
StatusCodeExceedConcurrentQuota: 1,
}
canRetryCodes = map[int]int{
StatusCodeInternalErr: 1,
}
)
type Coordinate struct {
Lng float64 `json:"x"`
Lat float64 `json:"y"`
}
type Coordinate2 struct {
Lng string `json:"lng"`
Lat string `json:"lat"`
}
type RidingResp struct {
Status int `json:"status"` //状态码
Message string `json:"message"` // 状态码对应的信息
Result struct {
Origin struct { //起点
Lng float64 `json:"lng"`
Lat float64 `json:"lat"`
}
Destination struct { //终点
Lng float64 `json:"lng"`
Lat float64 `json:"lat"`
}
Routers struct {
Distance float64 `json:"distance"` //方案距离,单位:米
Duration int `json:"duration"` //线路耗时,单位:秒
Steps []struct {
}
Name string `json:"name"` //道路名称
Instruction string `json:"instruction"` //路段描述
StartLocation struct {
Lng float64 `json:"lng"`
Lat float64 `json:"lat"`
}
EndLocation struct {
Lng float64 `json:"lng"`
Lat float64 `json:"lat"`
}
Path []struct {
Lng float64 `json:"lng"`
Lat float64 `json:"lat"`
}
}
} `json:"result"`
}
type API struct {
client *http.Client
config *platformapi.APIConfig
ak string
sk string
}
func New(ak, sk string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
ak: ak,
sk: sk,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func (a *API) signParams(apiStr string, mapData map[string]interface{}) string {
keys := make([]string, 0)
for k := range mapData {
if k != signKey {
keys = append(keys, k)
}
}
sort.Strings(keys)
strList := []string{}
for _, k := range keys {
strList = append(strList, k+"="+url.QueryEscape(fmt.Sprint(mapData[k])))
}
finalStr := "/" + apiStr + "?" + strings.Join(strList, "&") + a.sk
finalStr = url.QueryEscape(finalStr)
return fmt.Sprintf("%x", md5.Sum([]byte(finalStr)))
}
func genGetURL(baseURL, apiStr string, params map[string]interface{}) string {
keys := make([]string, 0)
for k := range params {
if k != signKey {
keys = append(keys, k)
}
}
sort.Strings(keys)
strList := []string{}
for _, k := range keys {
strList = append(strList, k+"="+url.QueryEscape(fmt.Sprint(params[k])))
}
strList = append(strList, signKey+"="+url.QueryEscape(fmt.Sprint(params[signKey])))
queryString := "?" + strings.Join(strList, "&")
if apiStr != "" {
return baseURL + "/" + apiStr + queryString
}
return baseURL + queryString
}
func (a *API) AccessAPI(apiStr string, params map[string]interface{}) (retVal interface{}, err error) {
apiStr += "/"
params2 := utils.MergeMaps(utils.Params2Map("ak", a.ak, "output", "json"), params)
params2[signKey] = a.signParams(apiStr, params2)
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {
//request, _ := http.NewRequest(http.MethodGet, genGetURL(prodURL, apiStr, params2), nil)
request, _ := http.NewRequest(http.MethodGet, genGetURL(prodURL2, apiStr, params2), nil)
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")
}
status := int(utils.MustInterface2Int64(jsonResult1["status"]))
if status == StatusCodeSuccess {
retVal = jsonResult1[resultKey]
return platformapi.ErrLevelSuccess, nil
}
newErr := utils.NewErrorIntCode(utils.Interface2String(jsonResult1["message"]), status)
if _, ok := exceedLimitCodes[status]; ok {
return platformapi.ErrLevelExceedLimit, newErr
} else if _, ok := canRetryCodes[status]; ok {
return platformapi.ErrLevelRecoverableErr, newErr
} else {
return platformapi.ErrLevelCodeIsNotOK, newErr
}
})
return retVal, err
}
// BatchCoordinateConvert 坐标转换
func (a *API) BatchCoordinateConvert(coords []*Coordinate, fromCoordSys, toCoordSys int) (outCoords []*Coordinate, err error) {
if fromCoordSys == toCoordSys {
return coords, nil
}
var coordsStrList []string
for _, v := range coords {
coordsStrList = append(coordsStrList, fmt.Sprintf("%.6f,%.6f", v.Lng, v.Lat))
}
params := map[string]interface{}{
"coords": strings.Join(coordsStrList, ";"),
"from": fromCoordSys,
"to": toCoordSys,
}
result, err := a.AccessAPI("geoconv/v1", params)
if err == nil {
err = utils.Map2StructByJson(result, &outCoords, false)
}
return outCoords, err
}
// DirectionLiteRide 骑行路线规划
func (a *API) DirectionLiteRide(coords []*Coordinate) (retVal interface{}, err error) {
var (
sCoords string
uCoords string
timestamp = time.Now().Unix()
apiStr = "directionlite/v1/riding"
)
sCoords = utils.Float64ToStr(coords[0].Lat) + "," + utils.Float64ToStr(coords[0].Lng)
uCoords = utils.Float64ToStr(coords[1].Lat) + "," + utils.Float64ToStr(coords[1].Lng)
param := map[string]interface{}{
"origin": sCoords,
"destination": uCoords,
"timestamp": timestamp,
//"steps_info": 2,
}
//生成签名
params2 := utils.MergeMaps(utils.Params2Map("ak", a.ak, "output", "json"), param)
sn := a.signParams(apiStr, params2)
params := url.Values{
"origin": []string{sCoords},
"destination": []string{uCoords},
"ak": []string{a.ak},
"sn": []string{sn},
"timestamp": []string{utils.Int64ToStr(timestamp)},
}
// 发起请求
request, err := url.Parse(prodURL2 + "/" + apiStr + "?" + params.Encode())
if nil != err {
return nil, err
}
resp, err1 := http.Get(request.String())
defer resp.Body.Close()
if err1 != nil {
return nil, err1
}
body, err2 := ioutil.ReadAll(resp.Body)
if err2 != nil {
return nil, err2
}
result := string(body)
path := &RiderPath{}
if err := json.Unmarshal([]byte(result), path); err != nil {
return result, nil
}
globals.SugarLogger.Debugf("=======path := %s", utils.Format4Output(path, false))
return result, nil
}