Files
baseapi/platformapi/baidunavi/baidunavi.go
邹宗楠 8ecfd93781 1
2024-07-31 13:14:24 +08:00

247 lines
6.4 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"
"errors"
"fmt"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
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 // 当前并发量已经超过约定并发配额,并且服务总并发量也已经超过设定的总并发配额,限制访问
)
//bd09ll表示百度经纬度坐标
//bd09mc表示百度墨卡托坐标
//gcj02表示经过国测局加密的坐标
//wgs84表示gps获取的坐标
const (
CoordSysWGS84 = 1 // GPS设备获取的角度坐标WGS84坐标
CoordSysGCJ02 = 3 // google地图、soso地图、aliyun地图、mapabc地图和amap地图所用坐标国测局GCJ02坐标
CoordSysBaiDu = 5 // 百度地图采用的经纬度坐标
CoordSysGaoDe2Baidu = "1" // 高德坐标转百度坐标
CoordSysBaidu2Gaode = "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) AccessAPI2(apiStr string, param url.Values) (retVal map[string]interface{}, err error) {
for _, v := range BaiduAKList {
param.Add("ak", v)
param.Add("output", "json")
params2 := map[string]interface{}{}
for i, j := range param {
params2[i] = j
}
params2[signKey] = a.signParams(apiStr, params2)
param.Add("timestamp", utils.Int64ToStr(time.Now().Unix()))
// 发起请求
request, err := url.Parse(prodURL2 + "/" + apiStr + "?" + param.Encode())
if err != nil {
continue
}
resp, err1 := http.Get(request.String())
body, err2 := ioutil.ReadAll(resp.Body)
if err1 != nil || err2 != nil {
continue
}
err = json.Unmarshal(body, &retVal)
if err == nil {
return retVal, nil
}
}
return nil, errors.New("所有百度应用额度均用完")
}
// BatchCoordinateConvert 坐标转换
func (a *API) BatchCoordinateConvert(coords []*Coordinate, changeType string) (outCoords []*Coordinate, err error) {
var coordsStrList []string
for _, v := range coords {
coordsStrList = append(coordsStrList, fmt.Sprintf("%.6f,%.6f", v.Lng, v.Lat))
}
params := url.Values{
"coords": []string{strings.Join(coordsStrList, ";")},
"model": []string{changeType}, // 1:高德转百度 5:百度转高德
//"from": []string{utils.Int2Str(fromCoordSys)},
//"to": []string{utils.Int2Str(toCoordSys)},
}
result, err := a.AccessAPI2("geoconv/v2/", params)
if err == nil {
err = utils.Map2StructByJson(result[resultKey], &outCoords, false)
}
return outCoords, err
}
// DirectionLiteRide 获取骑行距离
func (a *API) DirectionLiteRide(coords []*Coordinate) (retVal interface{}, err error) {
var (
sCoords string
uCoords string
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 := url.Values{
"origin": []string{sCoords},
"destination": []string{uCoords},
}
resp, err := a.AccessAPI2(apiStr, param)
if err == nil {
return resp[resultKey], nil
}
return nil, nil
}