upstream sync
This commit is contained in:
@@ -23,9 +23,10 @@ func Load() error {
|
||||
|
||||
Service: Service{
|
||||
// 9000 DEFAULT FOR DEV ENVIRONMENT
|
||||
Port: getEnv("NOVATECH_SERVICE_PORT", "9000"),
|
||||
Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"),
|
||||
BlockchainSecret: getEnv("NOVATECH_SERVICE_BLOCKCHAIN_SECRET", "novatech_service_blockchain_secret"),
|
||||
Port: getEnv("NOVATECH_SERVICE_PORT", "9000"),
|
||||
Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"),
|
||||
BlockchainSecret: getEnv("NOVATECH_SERVICE_BLOCKCHAIN_SECRET", "novatech_service_blockchain_secret"),
|
||||
MapboxAccessToken: getEnv("NOVATECH_SERVICE_MAPBOX_ACCESS_TOKEN", ""),
|
||||
},
|
||||
AdminService: Service{
|
||||
// 8080 DEFAULT FOR DEV ENVIRONMENT
|
||||
|
||||
@@ -10,10 +10,11 @@ type Config struct {
|
||||
|
||||
// Service contains configuration for service
|
||||
type Service struct {
|
||||
Port string
|
||||
Environment string
|
||||
WebPageURL string
|
||||
BlockchainSecret string
|
||||
Port string
|
||||
Environment string
|
||||
WebPageURL string
|
||||
BlockchainSecret string
|
||||
MapboxAccessToken string
|
||||
}
|
||||
|
||||
// Blockchain contains configuration for blockchain
|
||||
|
||||
@@ -150,9 +150,6 @@ func GetContractStatuses(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"data": models.GetContractStatuses()})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func CreateContract(c *gin.Context) {
|
||||
|
||||
var payload models.CreateContractRequestPayload
|
||||
|
||||
32
controllers/locations_controller.go
Normal file
32
controllers/locations_controller.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/services/location"
|
||||
)
|
||||
|
||||
func SearchPlace(c *gin.Context) {
|
||||
query := c.Query("q")
|
||||
|
||||
if query == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "query is empty"})
|
||||
return
|
||||
}
|
||||
|
||||
mapboxAccessToken := config.AppConfig.Service.MapboxAccessToken
|
||||
locationClient := location.NewService(mapboxAccessToken)
|
||||
|
||||
places, err := locationClient.SearchPlace(c, query)
|
||||
if err != nil {
|
||||
log.Printf("SearchPlace Error: Service error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Service error"})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the buyers and the total count
|
||||
c.JSON(http.StatusOK, gin.H{"data": places})
|
||||
}
|
||||
@@ -11,4 +11,5 @@ NOVATECH_SERVICE_BLOCKCHAIN_SECRET="abc&1*~#^2^#s0^=)^^7%b34"
|
||||
NOVATECH_BLOCKCHAIN_NETWORK_ENDPOINT="https://polygon-mumbai.infura.io/v3/4458cf4d1689497b9a38b1d6bbf05e78"
|
||||
NOVATECH_BLOCKCHAIN_CONTRACT_ADDRESS=0x121Cb4bFEeDb55d598D8F5e9EeDF8bB14c421d96
|
||||
NOVATECH_BLOCKCHAIN_WALLET_ADDRESS=0x20eff5decaed29bd64f0c6385956363eeaaf4d3e
|
||||
NOVATECH_BLOCKCHAIN_WALLET_PRIVATE_KEY=PRIVATE_KEY
|
||||
NOVATECH_BLOCKCHAIN_WALLET_PRIVATE_KEY=PRIVATE_KEY
|
||||
NOVATECH_SERVICE_MAPBOX_ACCESS_TOKEN=pk.ey
|
||||
6
go.mod
6
go.mod
@@ -9,8 +9,11 @@ require (
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/lib/pq v1.8.0
|
||||
github.com/mailru/easyjson v0.7.7
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/qor/admin v1.2.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/valyala/fasthttp v1.40.0
|
||||
)
|
||||
|
||||
replace gitlab.com/pactual1/backend => ./
|
||||
@@ -19,6 +22,7 @@ require (
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
||||
@@ -62,6 +66,7 @@ require (
|
||||
github.com/holiman/uint256 v1.2.3 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
@@ -98,6 +103,7 @@ require (
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
golang.org/x/arch v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
|
||||
26
go.sum
26
go.sum
@@ -7,6 +7,9 @@ github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBK
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
||||
@@ -168,8 +171,11 @@ github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
@@ -191,6 +197,8 @@ github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNa
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
@@ -326,6 +334,11 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc=
|
||||
github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yosssi/gohtml v0.0.0-20200519115854-476f5b4b8047 h1:YWaOkupKL+BRRJSWRq/uhSkWXc1K0QVIYVG36XUBGOc=
|
||||
@@ -338,6 +351,7 @@ golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
@@ -351,6 +365,8 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
@@ -361,6 +377,11 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -369,11 +390,16 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -9,60 +9,60 @@ import (
|
||||
|
||||
type Contract struct {
|
||||
gorm.Model
|
||||
Name string `json:"name"`
|
||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||
BuyerID uint `json:"buyerId"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
Description string `json:"description"`
|
||||
StartLat float64 `json:"startLat"`
|
||||
StartLon float64 `json:"startLon"`
|
||||
EndLat float64 `json:"endLat"`
|
||||
EndLon float64 `json:"endLon"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Status string `json:"status"`
|
||||
BlockchainID string `json:"blockchainId"`
|
||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||
ProductID uint `json:"productId"`
|
||||
MaxTemp float64 `json:"maxTemp"`
|
||||
MinTemp float64 `json:"minTemp"`
|
||||
ArrivalDate time.Time `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
BuyerName string `json:"buyerName" gorm:"-"`
|
||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||
Name string `json:"name"`
|
||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||
BuyerID uint `json:"buyerId"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
Description string `json:"description"`
|
||||
StartPlaceName string `json:"startPlaceName"`
|
||||
StartLat float64 `json:"startLat"`
|
||||
StartLon float64 `json:"startLon"`
|
||||
EndPlaceName string `json:"endPlaceName"`
|
||||
EndLat float64 `json:"endLat"`
|
||||
EndLon float64 `json:"endLon"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Status string `json:"status"`
|
||||
BlockchainID string `json:"blockchainId"`
|
||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||
ProductID uint `json:"productId"`
|
||||
MaxTemp float64 `json:"maxTemp"`
|
||||
MinTemp float64 `json:"minTemp"`
|
||||
ArrivalDate time.Time `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
BuyerName string `json:"buyerName" gorm:"-"`
|
||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||
}
|
||||
|
||||
type ContractResponse struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||
BuyerID uint `json:"buyerId"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
Description string `json:"description"`
|
||||
StartLat float64 `json:"startLat"`
|
||||
StartLon float64 `json:"startLon"`
|
||||
EndLat float64 `json:"endLat"`
|
||||
EndLon float64 `json:"endLon"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Status string `json:"status"`
|
||||
BlockchainID string `json:"blockchainId"`
|
||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||
ProductID uint `json:"productId"`
|
||||
MaxTemp float64 `json:"maxTemp"`
|
||||
MinTemp float64 `json:"minTemp"`
|
||||
ArrivalDate time.Time `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
BuyerName string `json:"buyerName" gorm:"-"`
|
||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||
Name string `json:"name"`
|
||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||
BuyerID uint `json:"buyerId"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
Description string `json:"description"`
|
||||
StartLat float64 `json:"startLat"`
|
||||
StartLon float64 `json:"startLon"`
|
||||
EndLat float64 `json:"endLat"`
|
||||
EndLon float64 `json:"endLon"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Status string `json:"status"`
|
||||
BlockchainID string `json:"blockchainId"`
|
||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||
ProductID uint `json:"productId"`
|
||||
MaxTemp float64 `json:"maxTemp"`
|
||||
MinTemp float64 `json:"minTemp"`
|
||||
ArrivalDate time.Time `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
BuyerName string `json:"buyerName" gorm:"-"`
|
||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||
}
|
||||
|
||||
|
||||
|
||||
func ConvertContractToResponse(contracts []Contract) []ContractResponse {
|
||||
var contractResponses []ContractResponse
|
||||
for _, contract := range contracts {
|
||||
@@ -119,17 +119,18 @@ func ConvertContractToResponseModel(contracts []Contract) []ListContractResponse
|
||||
}
|
||||
|
||||
listInvoiceResponse := ListContractResponse{
|
||||
Status: KeyValue{Key: status.Key, Value: status.Value},
|
||||
Buyer: CompanyShortResponse{ID: int(contract.BuyerID), Name: contract.BuyerName},
|
||||
ContractID: int(contract.ID),
|
||||
DateCreated: contract.CreatedAt,
|
||||
NumberOfDevices: contract.NumberOfDevices,
|
||||
Status: KeyValue{Key: status.Key, Value: status.Value},
|
||||
Buyer: CompanyShortResponse{ID: int(contract.BuyerID), Name: contract.BuyerName},
|
||||
ContractID: int(contract.ID),
|
||||
DateCreated: contract.CreatedAt,
|
||||
NumberOfDevices: contract.NumberOfDevices,
|
||||
}
|
||||
listInvoiceResponses = append(listInvoiceResponses, listInvoiceResponse)
|
||||
}
|
||||
return listInvoiceResponses
|
||||
|
||||
}
|
||||
|
||||
const ContractStatusActive = "active"
|
||||
const ContractStatusPending = "pending"
|
||||
const ContractStatusDraft = "draft"
|
||||
@@ -138,14 +139,12 @@ const ContractStatusReadyForActivation = "ready_for_activation"
|
||||
const ContractStatusExecuted = "executed"
|
||||
const ContractStatusRevoked = "revoked"
|
||||
|
||||
|
||||
const PenaltyTypeAmount = "amount"
|
||||
const PenaltyTypePercentage = "percentage"
|
||||
|
||||
const PenaltyRecDaily = "daily"
|
||||
const PenaltyRecMonthly = "monthly"
|
||||
|
||||
|
||||
type Status struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
@@ -164,25 +163,24 @@ func GetContractStatuses() []Status {
|
||||
}
|
||||
|
||||
type ListContractResponse struct {
|
||||
Status KeyValue `json:"status"`
|
||||
Buyer CompanyShortResponse `json:"buyer"`
|
||||
ContractID int `json:"contractID"`
|
||||
NumberOfDevices int `json:"numberOfDevices"`
|
||||
DateCreated time.Time `json:"dateCreated"`
|
||||
|
||||
Status KeyValue `json:"status"`
|
||||
Buyer CompanyShortResponse `json:"buyer"`
|
||||
ContractID int `json:"contractID"`
|
||||
NumberOfDevices int `json:"numberOfDevices"`
|
||||
DateCreated time.Time `json:"dateCreated"`
|
||||
}
|
||||
|
||||
type CreateContractRequestPayload struct {
|
||||
SellerID uint `json:"sellerId" binding:"required"`
|
||||
BuyerID uint `json:"buyerId" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
ProductID uint `json:"productId"`
|
||||
MinTemp float64 `json:"minTemp" binding:"required"`
|
||||
MaxTemp float64 `json:"maxTemp" binding:"required"`
|
||||
ArrivalDate int64 `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
SellerID uint `json:"sellerId" binding:"required"`
|
||||
BuyerID uint `json:"buyerId" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
ProductID uint `json:"productId"`
|
||||
MinTemp float64 `json:"minTemp" binding:"required"`
|
||||
MaxTemp float64 `json:"maxTemp" binding:"required"`
|
||||
ArrivalDate int64 `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
}
|
||||
|
||||
func (Contract) Update() (bool, error) {
|
||||
@@ -194,5 +192,3 @@ func (Contract) Create() (bool, error) {
|
||||
func (Contract) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
6
models/location.go
Normal file
6
models/location.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package models
|
||||
|
||||
type Place struct {
|
||||
Text string `json:"text"`
|
||||
Coordinates []float64 `json:"coordinates"`
|
||||
}
|
||||
@@ -28,7 +28,10 @@ func RegisterPublicRoutes(r *gin.Engine) {
|
||||
r.GET("/contracts/statuses", controllers.GetContractStatuses)
|
||||
r.GET("/contracts", controllers.GetBuyerContracts)
|
||||
r.POST("/contracts/create", controllers.CreateContract)
|
||||
|
||||
|
||||
r.GET("/contracts/:contract_id", controllers.GetContractByID)
|
||||
r.PATCH("/contracts/:contract_id", controllers.UpdateContract)
|
||||
|
||||
// Locations
|
||||
r.GET("/locations", controllers.SearchPlace)
|
||||
}
|
||||
|
||||
33
services/location/location_service.go
Normal file
33
services/location/location_service.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package location
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/services/location/mapbox_lib"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
accessToken string
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
SearchPlace(context.Context, string) ([]*models.Place, error)
|
||||
}
|
||||
|
||||
func NewService(accessToken string) Service {
|
||||
return service{accessToken: accessToken}
|
||||
}
|
||||
|
||||
func (s service) SearchPlace(ctx context.Context, query string) ([]*models.Place, error) {
|
||||
geocoder := mapbox.NewFastHttpGeocoder(mapbox.AccessToken(s.accessToken))
|
||||
resp, err := geocoder.ForwardGeocode(ctx, &mapbox.ForwardGeocodeRequest{SearchText: query})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var places []*models.Place
|
||||
for _, feature := range resp.Features {
|
||||
places = append(places, &models.Place{Text: feature.Text, Coordinates: feature.Geometry.Coordinates})
|
||||
}
|
||||
return places, nil
|
||||
}
|
||||
7
services/location/mapbox_lib/client.go
Normal file
7
services/location/mapbox_lib/client.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package mapbox
|
||||
|
||||
// Client covers all Mabpox API
|
||||
type Client interface {
|
||||
// Geocoder covers forward and reverse geocoding mapbox API
|
||||
Geocoder
|
||||
}
|
||||
103
services/location/mapbox_lib/config.go
Normal file
103
services/location/mapbox_lib/config.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAPI = "https://api.mapbox.com"
|
||||
)
|
||||
|
||||
// Option allows gradually modify config
|
||||
type Option func(c config) config
|
||||
|
||||
type config struct {
|
||||
accessToken string
|
||||
rootAPI string
|
||||
client FastHttpClient
|
||||
logger Logger
|
||||
// requestLogger will be called instead of testLogger if set.
|
||||
requestLogger func(ctx context.Context) Logger
|
||||
|
||||
accessTokenGetValue []byte
|
||||
geocodeEndpoint string
|
||||
}
|
||||
|
||||
// withEnv overwrites config values with env is not empty
|
||||
func (c config) withEnv() config {
|
||||
at := os.Getenv("MAPBOX_ACCESS_TOKEN")
|
||||
if at != "" {
|
||||
c.accessToken = at
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// prepare prebuilds some reused api parts like access token http get value
|
||||
func (c config) prepare() config {
|
||||
c.accessTokenGetValue = []byte(questionMark + access_token + string(equalMark) + c.accessToken)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func newConfig() config {
|
||||
return config{
|
||||
rootAPI: defaultAPI,
|
||||
client: &fasthttp.Client{},
|
||||
geocodeEndpoint: "mapbox.places",
|
||||
}
|
||||
}
|
||||
|
||||
// Log used to debug traces and to log errors.
|
||||
func Log(l Logger) Option {
|
||||
return func(c config) config {
|
||||
c.logger = l
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
// RequestLogger sets the way testLogger could be extracted from request context.
|
||||
// If set will be used instead of Log.
|
||||
func RequestLogger(extract func(ctx context.Context) Logger) Option {
|
||||
return func(c config) config {
|
||||
c.requestLogger = extract
|
||||
return c
|
||||
}
|
||||
}
|
||||
// AccessToken sets access_token get param.
|
||||
// Could be set with MAPBOX_ACCESS_TOKEN too.
|
||||
func AccessToken(at string) Option {
|
||||
return func(c config) config {
|
||||
c.accessToken = at
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
// RootAPI allows to change root api address.
|
||||
// default to https://api.mapbox.com
|
||||
func RootAPI(rootAPI string) Option {
|
||||
return func(c config) config {
|
||||
c.rootAPI = rootAPI
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
// HttpClient allows to change default fast http client
|
||||
func HttpClient(c FastHttpClient) Option {
|
||||
return func(fhc config) config {
|
||||
fhc.client = c
|
||||
return fhc
|
||||
}
|
||||
}
|
||||
|
||||
// GeocodeEndpoint sets geocode endpoint.
|
||||
// could be set to mapbox.places-permanent, defualt to mapbox.places
|
||||
func GeocodeEndpoint(endpoint string) Option {
|
||||
return func(c config) config {
|
||||
c.geocodeEndpoint = endpoint
|
||||
return c
|
||||
}
|
||||
}
|
||||
35
services/location/mapbox_lib/entities.go
Normal file
35
services/location/mapbox_lib/entities.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package mapbox
|
||||
|
||||
type (
|
||||
Feature struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
PlaceType []string `json:"place_type"`
|
||||
Relevance float64 `json:"relevance"`
|
||||
Properties Properties `json:"properties"`
|
||||
Text string `json:"text"`
|
||||
PlaceName string `json:"place_name"`
|
||||
Center []float64 `json:"center"`
|
||||
Geometry Geometry `json:"geometry"`
|
||||
Address string `json:"address"`
|
||||
Context []Context `json:"context"`
|
||||
BoundingBox []float64 `json:"bbox"`
|
||||
}
|
||||
|
||||
Properties struct {
|
||||
Accuracy string `json:"accuracy"`
|
||||
ShortCode string `json:"short_code"`
|
||||
}
|
||||
|
||||
Geometry struct {
|
||||
Type string `json:"type"`
|
||||
Coordinates []float64 `json:"coordinates"`
|
||||
}
|
||||
|
||||
Context struct {
|
||||
ID string `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Wikidata string `json:"wikidata"`
|
||||
ShortCode string `json:"short_code"`
|
||||
}
|
||||
)
|
||||
555
services/location/mapbox_lib/entities_easyjson.go
Normal file
555
services/location/mapbox_lib/entities_easyjson.go
Normal file
@@ -0,0 +1,555 @@
|
||||
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
|
||||
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
easyjson "github.com/mailru/easyjson"
|
||||
jlexer "github.com/mailru/easyjson/jlexer"
|
||||
jwriter "github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
// suppress unused package warning
|
||||
var (
|
||||
_ *json.RawMessage
|
||||
_ *jlexer.Lexer
|
||||
_ *jwriter.Writer
|
||||
_ easyjson.Marshaler
|
||||
)
|
||||
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox(in *jlexer.Lexer, out *Properties) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "accuracy":
|
||||
out.Accuracy = string(in.String())
|
||||
case "short_code":
|
||||
out.ShortCode = string(in.String())
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox(out *jwriter.Writer, in Properties) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"accuracy\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.Accuracy))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"short_code\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.ShortCode))
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Properties) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Properties) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Properties) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Properties) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox(l, v)
|
||||
}
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox1(in *jlexer.Lexer, out *Geometry) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "type":
|
||||
out.Type = string(in.String())
|
||||
case "coordinates":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Coordinates = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Coordinates == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Coordinates = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.Coordinates = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.Coordinates = (out.Coordinates)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v1 float64
|
||||
v1 = float64(in.Float64())
|
||||
out.Coordinates = append(out.Coordinates, v1)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox1(out *jwriter.Writer, in Geometry) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"type\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.Type))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"coordinates\":"
|
||||
out.RawString(prefix)
|
||||
if in.Coordinates == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v2, v3 := range in.Coordinates {
|
||||
if v2 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v3))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Geometry) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox1(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Geometry) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox1(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Geometry) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox1(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Geometry) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox1(l, v)
|
||||
}
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox2(in *jlexer.Lexer, out *Feature) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "id":
|
||||
out.ID = string(in.String())
|
||||
case "type":
|
||||
out.Type = string(in.String())
|
||||
case "place_type":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.PlaceType = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.PlaceType == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.PlaceType = make([]string, 0, 4)
|
||||
} else {
|
||||
out.PlaceType = []string{}
|
||||
}
|
||||
} else {
|
||||
out.PlaceType = (out.PlaceType)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v4 string
|
||||
v4 = string(in.String())
|
||||
out.PlaceType = append(out.PlaceType, v4)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "relevance":
|
||||
out.Relevance = float64(in.Float64())
|
||||
case "properties":
|
||||
(out.Properties).UnmarshalEasyJSON(in)
|
||||
case "text":
|
||||
out.Text = string(in.String())
|
||||
case "place_name":
|
||||
out.PlaceName = string(in.String())
|
||||
case "center":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Center = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Center == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Center = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.Center = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.Center = (out.Center)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v5 float64
|
||||
v5 = float64(in.Float64())
|
||||
out.Center = append(out.Center, v5)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "geometry":
|
||||
(out.Geometry).UnmarshalEasyJSON(in)
|
||||
case "address":
|
||||
out.Address = string(in.String())
|
||||
case "context":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Context = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Context == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Context = make([]Context, 0, 1)
|
||||
} else {
|
||||
out.Context = []Context{}
|
||||
}
|
||||
} else {
|
||||
out.Context = (out.Context)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v6 Context
|
||||
(v6).UnmarshalEasyJSON(in)
|
||||
out.Context = append(out.Context, v6)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "bbox":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.BoundingBox = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.BoundingBox == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.BoundingBox = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.BoundingBox = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.BoundingBox = (out.BoundingBox)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v7 float64
|
||||
v7 = float64(in.Float64())
|
||||
out.BoundingBox = append(out.BoundingBox, v7)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox2(out *jwriter.Writer, in Feature) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"id\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.ID))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"type\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Type))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"place_type\":"
|
||||
out.RawString(prefix)
|
||||
if in.PlaceType == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v8, v9 := range in.PlaceType {
|
||||
if v8 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v9))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"relevance\":"
|
||||
out.RawString(prefix)
|
||||
out.Float64(float64(in.Relevance))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"properties\":"
|
||||
out.RawString(prefix)
|
||||
(in.Properties).MarshalEasyJSON(out)
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"text\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Text))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"place_name\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.PlaceName))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"center\":"
|
||||
out.RawString(prefix)
|
||||
if in.Center == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v10, v11 := range in.Center {
|
||||
if v10 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v11))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"geometry\":"
|
||||
out.RawString(prefix)
|
||||
(in.Geometry).MarshalEasyJSON(out)
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"address\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Address))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"context\":"
|
||||
out.RawString(prefix)
|
||||
if in.Context == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v12, v13 := range in.Context {
|
||||
if v12 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v13).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"bbox\":"
|
||||
out.RawString(prefix)
|
||||
if in.BoundingBox == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v14, v15 := range in.BoundingBox {
|
||||
if v14 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v15))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Feature) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox2(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Feature) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox2(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Feature) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox2(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Feature) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox2(l, v)
|
||||
}
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox3(in *jlexer.Lexer, out *Context) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "id":
|
||||
out.ID = string(in.String())
|
||||
case "text":
|
||||
out.Text = string(in.String())
|
||||
case "wikidata":
|
||||
out.Wikidata = string(in.String())
|
||||
case "short_code":
|
||||
out.ShortCode = string(in.String())
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox3(out *jwriter.Writer, in Context) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"id\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.ID))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"text\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Text))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"wikidata\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Wikidata))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"short_code\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.ShortCode))
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Context) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox3(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Context) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox3(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Context) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox3(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Context) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox3(l, v)
|
||||
}
|
||||
421
services/location/mapbox_lib/geocode.go
Normal file
421
services/location/mapbox_lib/geocode.go
Normal file
@@ -0,0 +1,421 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
const (
|
||||
limit = "limit"
|
||||
types = "types"
|
||||
country = "country"
|
||||
language = "language"
|
||||
reverseMode = "reverseMode"
|
||||
autocomplete = "autocomplete"
|
||||
fuzzymatch = "fuzzymatch"
|
||||
bbox = "bbox"
|
||||
proximity = "proximity"
|
||||
routing = "routing"
|
||||
trueStr = "true"
|
||||
oneStr = "1"
|
||||
|
||||
access_token = "access_token"
|
||||
|
||||
floatFormatNoExponent = 'f'
|
||||
|
||||
respHeaderRateLimitInterval = "X-Rate-Limit-Interval"
|
||||
respHeaderRateLimitLimit = "X-Rate-Limit-Limit"
|
||||
respHeaderRateLimitReset = "X-Rate-Limit-Reset"
|
||||
)
|
||||
|
||||
var (
|
||||
responseFormatJSON = []byte(".json")
|
||||
getMethod = []byte("GET")
|
||||
)
|
||||
|
||||
type GeoPoint struct {
|
||||
Lon float64
|
||||
Lat float64
|
||||
}
|
||||
|
||||
type ReverseGeocodeRequest struct {
|
||||
GeoPoint GeoPoint
|
||||
// Limit results to one or more countries.
|
||||
Limit int
|
||||
// Filter results to include only a subset (one or more) of the available feature types.
|
||||
// Options are country, region, postcode, district, place, locality, neighborhood, address, and poi.
|
||||
// Multiple options can be comma-separated. Note that poi.landmark is a deprecated type that, while still supported,
|
||||
// returns the same data as is returned using the poi type.
|
||||
Types []string
|
||||
// Permitted values are ISO 3166 alpha 2(https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country codes separated by commas.
|
||||
Country string
|
||||
// Specify the user’s language. This parameter controls the language of the text supplied in responses.
|
||||
// Options are IETF language tags comprised of a mandatory ISO 639-1 language code and, optionally,
|
||||
// one or more IETF subtags for country or script.
|
||||
// More than one value can also be specified, separated by commas,
|
||||
// for applications that need to display labels in multiple languages.
|
||||
// For more information on which specific languages are supported, see https://docs.mapbox.com/api/search/#language-coverage
|
||||
Language string
|
||||
// Decides how results are sorted in a reverse geocoding query
|
||||
// if multiple results are requested using a limit other than 1.
|
||||
// Options are distance (default), which causes the closest feature
|
||||
// to always be returned first, and score, which allows high-prominence features
|
||||
// to be sorted higher than nearer, lower-prominence features.
|
||||
ReverseMode int
|
||||
// Specify whether to request additional metadata about the recommended navigation destination corresponding
|
||||
// to the feature (true) or not (false, default). Only applicable for address features.
|
||||
// For example, if routing=true the response could include data about a point on the road the feature fronts.
|
||||
// Response features may include an array containing one or more routable points.
|
||||
// Routable points cannot always be determined.
|
||||
// Consuming applications should fall back to using the feature’s normal geometry for routing
|
||||
// if a separate routable point is not returned.
|
||||
Routing bool
|
||||
}
|
||||
|
||||
// RateLimit wraps mapbox API rate limit resp headers
|
||||
type RateLimit struct {
|
||||
Interval []byte
|
||||
Limit []byte
|
||||
Reset []byte
|
||||
}
|
||||
|
||||
// easyjson:json
|
||||
type rawReverseGeoResp struct {
|
||||
Features []Feature `json:"features"`
|
||||
Query []float64 `json:"query"`
|
||||
}
|
||||
|
||||
// easyjson:json
|
||||
type rawForwardGeoResp struct {
|
||||
Features []Feature `json:"features"`
|
||||
Query []string `json:"query"`
|
||||
}
|
||||
|
||||
// GeocodeResponse
|
||||
type GeocodeResponse struct {
|
||||
RateLimit RateLimit
|
||||
// Raw mapbox API response
|
||||
RawResp []byte
|
||||
// passed query to mapbox
|
||||
ReverseQuery GeoPoint
|
||||
ForwardQuery []string
|
||||
// response result type
|
||||
Type string
|
||||
// response data
|
||||
Features []Feature
|
||||
}
|
||||
|
||||
type ForwardGeocodeRequest struct {
|
||||
//The feature you’re trying to look up.
|
||||
//This could be an address, a point of interest name, a city name, etc.
|
||||
//When searching for points of interest, it can also be a category name (for example, “coffee shop”).
|
||||
//For information on categories, see the Point of interest category coverage section.
|
||||
//The search text should be expressed as a URL-encoded UTF-8 string,
|
||||
//and must not contain the semicolon character (either raw or URL-encoded).
|
||||
//Your search text, once decoded, must consist of at most 20 words and numbers separated by spacing and punctuation,
|
||||
//and at most 256 characters.
|
||||
//
|
||||
//The accuracy of coordinates returned by a forward geocoding request can be impacted
|
||||
//by how the addresses in the query are formatted. Learn more about address formatting
|
||||
//best practices in the https://docs.mapbox.com/help/troubleshooting/address-geocoding-format-guide.
|
||||
SearchText string
|
||||
|
||||
//Specify whether to return autocomplete results (true, default) or not (false).
|
||||
//When autocomplete is enabled, results will be included that start with the requested string,
|
||||
//rather than just responses that match it exactly.
|
||||
//For example, a query for India might return both India and Indiana with autocomplete enabled,
|
||||
//but only India if it’s disabled.
|
||||
//
|
||||
//When autocomplete is enabled, each user keystroke counts as one request to the Geocoding API.
|
||||
//For example, a search for "coff" would be reflected as four separate Geocoding API requests.
|
||||
//To reduce the total requests sent, you can configure your application
|
||||
//to only call the Geocoding API after a specific number of characters are typed.
|
||||
Autocomplete *bool // default true
|
||||
|
||||
//Limit results to only those contained within the supplied bounding box
|
||||
//Bounding boxes should be supplied as four numbers separated by commas,
|
||||
//in minLon,minLat,maxLon,maxLat order.
|
||||
//The bounding box cannot cross the 180th meridian.
|
||||
Bbox []float64
|
||||
|
||||
//Limit results to one or more countries.
|
||||
//Permitted values are ISO 3166 alpha 2 country codes separated by commas.
|
||||
Country string
|
||||
|
||||
//Specify whether the Geocoding API should attempt approximate,
|
||||
//as well as exact, matching when performing searches (true, default),
|
||||
//or whether it should opt out of this behavior and only attempt exact matching (false).
|
||||
//For example, the default setting might return Washington, DC for a query of wahsington,
|
||||
//even though the query was misspelled.
|
||||
FuzzyMatch *bool // default true
|
||||
|
||||
//Specify the user’s language.
|
||||
//This parameter controls the language of the text supplied in responses, and also affects result scoring,
|
||||
//with results matching the user’s query in the requested language being preferred over results
|
||||
//that match in another language. For example, an autocomplete query for things
|
||||
//that start with Frank might return Frankfurt as the first result with an English (en) language parameter,
|
||||
//but Frankreich (“France”) with a German (de) language parameter.
|
||||
//
|
||||
//Options are IETF language tags comprised of a mandatory ISO 639-1 language code and, optionally,
|
||||
//one or more IETF subtags for country or script.
|
||||
//
|
||||
//More than one value can also be specified, separated by commas,
|
||||
//for applications that need to display labels in multiple languages.
|
||||
//
|
||||
//For more information on which specific languages are supported, see the https://docs.mapbox.com/api/search/#language-coverage.
|
||||
Language string
|
||||
|
||||
//Specify the maximum number of results to return. The default is 5 and the maximum supported is 10.
|
||||
Limit int // default 5
|
||||
|
||||
//Bias the response to favor results that are closer to this location
|
||||
Proximity *GeoPoint
|
||||
|
||||
//Specify whether to request additional metadata about the recommended navigation destination
|
||||
//corresponding to the feature (true) or not (false, default). Only applicable for address features.
|
||||
//
|
||||
//For example, if routing=true the response could include data about a point on the road the feature fronts.
|
||||
//Response features may include an array containing one or more routable points.
|
||||
//Routable points cannot always be determined.
|
||||
//Consuming applications should fall back to using the feature’s normal geometry for routing
|
||||
//if a separate routable point is not returned.
|
||||
Routing bool //default false
|
||||
|
||||
//Filter results to include only a subset (one or more) of the available feature types.
|
||||
//Options are country, region, postcode, district, place, locality, neighborhood, address, and poi.
|
||||
//Multiple options can be comma-separated. Note that poi.landmark is a deprecated type that,
|
||||
//while still supported, returns the same data as is returned using the poi type.
|
||||
//
|
||||
//For more information on the available types, see the https://docs.mapbox.com/api/search/#data-types.
|
||||
Types []string
|
||||
}
|
||||
|
||||
// Geocoder encapsulates forward and reverse geocode calls.
|
||||
type Geocoder interface {
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API
|
||||
ReverseGeocode(ctx context.Context, req *ReverseGeocodeRequest) (*GeocodeResponse, error)
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API
|
||||
ForwardGeocode(ctx context.Context, req *ForwardGeocodeRequest) (*GeocodeResponse, error)
|
||||
}
|
||||
|
||||
// FastHttpGeocoder is a fasthttp Geocoder implementation
|
||||
type FastHttpGeocoder struct {
|
||||
config
|
||||
|
||||
geocodeAPIURL []byte
|
||||
|
||||
stringBufPull *stringsBufferPool
|
||||
}
|
||||
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API thought fasthttp client.
|
||||
func (c *FastHttpGeocoder) ReverseGeocode(ctx context.Context, req *ReverseGeocodeRequest) (*GeocodeResponse, error) {
|
||||
freq := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(freq)
|
||||
|
||||
fresp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(fresp)
|
||||
|
||||
// split multivalues to limit memory consumption
|
||||
values := make(map[string]string, 5)
|
||||
|
||||
if req.Country != "" {
|
||||
values[country] = req.Country
|
||||
}
|
||||
if req.Limit != 0 {
|
||||
values[limit] = strconv.Itoa(req.Limit)
|
||||
}
|
||||
if req.Language != "" {
|
||||
values[language] = req.Language
|
||||
}
|
||||
if req.Routing {
|
||||
values[routing] = trueStr
|
||||
}
|
||||
if req.ReverseMode == 1 {
|
||||
values[reverseMode] = oneStr
|
||||
}
|
||||
if len(req.Types) > 0 {
|
||||
values[types] = strings.Join(req.Types, ",")
|
||||
}
|
||||
|
||||
buf := c.stringBufPull.acquireStringsBuilder()
|
||||
defer c.stringBufPull.releaseStringsBuilder(buf)
|
||||
|
||||
buf.Write(c.geocodeAPIURL)
|
||||
buf.WriteString(strconv.FormatFloat(req.GeoPoint.Lon, floatFormatNoExponent, 6, 64))
|
||||
buf.WriteByte(comma)
|
||||
buf.WriteString(strconv.FormatFloat(req.GeoPoint.Lat, floatFormatNoExponent, 6, 64))
|
||||
buf.Write(responseFormatJSON)
|
||||
buf.Write(c.accessTokenGetValue)
|
||||
|
||||
encodeValues(buf, values)
|
||||
|
||||
reqURI := buf.Bytes()
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: reverse geocode request %s", buf.String())
|
||||
})
|
||||
|
||||
freq.Header.SetMethodBytes(getMethod)
|
||||
freq.SetRequestURIBytes(reqURI)
|
||||
|
||||
if err := c.client.Do(freq, fresp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respBytes := make([]byte, len(fresp.Body()))
|
||||
copy(respBytes, fresp.Body())
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: reverse geocode response %s", string(respBytes))
|
||||
})
|
||||
|
||||
if fresp.Header.StatusCode() != http.StatusOK {
|
||||
return nil, errors.Errorf("failed to reverse geocode URI %s statusCode %d resp %s",
|
||||
reqURI, fresp.Header.StatusCode(), string(respBytes))
|
||||
}
|
||||
|
||||
respRaw := rawReverseGeoResp{}
|
||||
if err := respRaw.UnmarshalJSON(respBytes); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshall raw reverse geocode resp %s", string(respBytes))
|
||||
}
|
||||
|
||||
if len(respRaw.Query) != 2 {
|
||||
return nil, errors.Errorf("unexpected len of query coordinates in resp %s", string(respBytes))
|
||||
}
|
||||
|
||||
return &GeocodeResponse{
|
||||
RateLimit: readRespRateLimit(fresp),
|
||||
RawResp: respBytes,
|
||||
ReverseQuery: GeoPoint{
|
||||
Lon: respRaw.Query[0],
|
||||
Lat: respRaw.Query[1],
|
||||
},
|
||||
Features: respRaw.Features,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API thought fasthttp client.
|
||||
func (c *FastHttpGeocoder) ForwardGeocode(ctx context.Context, req *ForwardGeocodeRequest) (*GeocodeResponse, error) {
|
||||
freq := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(freq)
|
||||
|
||||
fresp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(fresp)
|
||||
|
||||
// split multivalues to limit memory consumption
|
||||
values := make(map[string]string, 9)
|
||||
|
||||
if req.Country != "" {
|
||||
values[country] = req.Country
|
||||
}
|
||||
if req.Limit != 0 {
|
||||
values[limit] = strconv.Itoa(req.Limit)
|
||||
}
|
||||
if req.Language != "" {
|
||||
values[language] = req.Language
|
||||
}
|
||||
if req.Routing {
|
||||
values[routing] = trueStr
|
||||
}
|
||||
if req.Autocomplete != nil {
|
||||
values[autocomplete] = fmt.Sprint(*req.Autocomplete)
|
||||
} else {
|
||||
values[autocomplete] = trueStr
|
||||
}
|
||||
if req.FuzzyMatch != nil {
|
||||
values[fuzzymatch] = fmt.Sprint(*req.FuzzyMatch)
|
||||
} else {
|
||||
values[fuzzymatch] = trueStr
|
||||
}
|
||||
if len(req.Bbox) == 4 {
|
||||
values[bbox] = fmt.Sprintf("%f,%f,%f,%f", req.Bbox[0], req.Bbox[1], req.Bbox[2], req.Bbox[3])
|
||||
}
|
||||
if req.Proximity != nil {
|
||||
values[proximity] = fmt.Sprintf("%f,%f", req.Proximity.Lon, req.Proximity.Lat)
|
||||
}
|
||||
values[routing] = fmt.Sprint(req.Routing)
|
||||
if len(req.Types) > 0 {
|
||||
values[types] = strings.Join(req.Types, ",")
|
||||
}
|
||||
|
||||
buf := c.stringBufPull.acquireStringsBuilder()
|
||||
defer c.stringBufPull.releaseStringsBuilder(buf)
|
||||
|
||||
buf.Write(c.geocodeAPIURL)
|
||||
buf.WriteString(req.SearchText)
|
||||
buf.Write(responseFormatJSON)
|
||||
buf.Write(c.accessTokenGetValue)
|
||||
|
||||
encodeValues(buf, values)
|
||||
|
||||
reqURI := buf.Bytes()
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: forward geocode request %s", buf.String())
|
||||
})
|
||||
|
||||
freq.Header.SetMethodBytes(getMethod)
|
||||
freq.SetRequestURIBytes(reqURI)
|
||||
|
||||
if err := c.client.Do(freq, fresp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respBytes := make([]byte, len(fresp.Body()))
|
||||
copy(respBytes, fresp.Body())
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: forward geocode response %s", string(respBytes))
|
||||
})
|
||||
|
||||
if fresp.Header.StatusCode() != http.StatusOK {
|
||||
return nil, errors.Errorf("failed to reverse geocode URI %s statusCode %d resp %s",
|
||||
reqURI, fresp.Header.StatusCode(), string(respBytes))
|
||||
}
|
||||
|
||||
respRaw := rawForwardGeoResp{}
|
||||
if err := respRaw.UnmarshalJSON(respBytes); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshall raw reverse geocode resp %s", string(respBytes))
|
||||
}
|
||||
|
||||
return &GeocodeResponse{
|
||||
RateLimit: readRespRateLimit(fresp),
|
||||
RawResp: respBytes,
|
||||
Features: respRaw.Features,
|
||||
ForwardQuery: respRaw.Query,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewFastHttpGeocoder(opts ...Option) *FastHttpGeocoder {
|
||||
c := FastHttpGeocoder{
|
||||
config: newConfig(),
|
||||
stringBufPull: newStringsBufferPool(),
|
||||
geocodeAPIURL: []byte("/geocoding/v5/"),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
c.config = o(c.config)
|
||||
}
|
||||
|
||||
c.config = c.config.withEnv()
|
||||
c.config = c.config.prepare()
|
||||
|
||||
c.geocodeAPIURL = []byte(c.rootAPI + string(c.geocodeAPIURL) + c.geocodeEndpoint + slash)
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func readRespRateLimit(resp *fasthttp.Response) RateLimit {
|
||||
return RateLimit{
|
||||
Interval: resp.Header.Peek(respHeaderRateLimitInterval),
|
||||
Limit: resp.Header.Peek(respHeaderRateLimitLimit),
|
||||
Reset: resp.Header.Peek(respHeaderRateLimitReset),
|
||||
}
|
||||
}
|
||||
293
services/location/mapbox_lib/geocode_easyjson.go
Normal file
293
services/location/mapbox_lib/geocode_easyjson.go
Normal file
@@ -0,0 +1,293 @@
|
||||
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
|
||||
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
easyjson "github.com/mailru/easyjson"
|
||||
jlexer "github.com/mailru/easyjson/jlexer"
|
||||
jwriter "github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
// suppress unused package warning
|
||||
var (
|
||||
_ *json.RawMessage
|
||||
_ *jlexer.Lexer
|
||||
_ *jwriter.Writer
|
||||
_ easyjson.Marshaler
|
||||
)
|
||||
|
||||
func easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox(in *jlexer.Lexer, out *rawReverseGeoResp) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "features":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Features = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Features == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Features = make([]Feature, 0, 1)
|
||||
} else {
|
||||
out.Features = []Feature{}
|
||||
}
|
||||
} else {
|
||||
out.Features = (out.Features)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v1 Feature
|
||||
(v1).UnmarshalEasyJSON(in)
|
||||
out.Features = append(out.Features, v1)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "query":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Query = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Query == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Query = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.Query = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.Query = (out.Query)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v2 float64
|
||||
v2 = float64(in.Float64())
|
||||
out.Query = append(out.Query, v2)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox(out *jwriter.Writer, in rawReverseGeoResp) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"features\":"
|
||||
out.RawString(prefix[1:])
|
||||
if in.Features == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v3, v4 := range in.Features {
|
||||
if v3 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v4).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"query\":"
|
||||
out.RawString(prefix)
|
||||
if in.Query == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v5, v6 := range in.Query {
|
||||
if v5 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v6))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v rawReverseGeoResp) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v rawReverseGeoResp) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *rawReverseGeoResp) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *rawReverseGeoResp) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox(l, v)
|
||||
}
|
||||
func easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox1(in *jlexer.Lexer, out *rawForwardGeoResp) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "features":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Features = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Features == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Features = make([]Feature, 0, 1)
|
||||
} else {
|
||||
out.Features = []Feature{}
|
||||
}
|
||||
} else {
|
||||
out.Features = (out.Features)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v7 Feature
|
||||
(v7).UnmarshalEasyJSON(in)
|
||||
out.Features = append(out.Features, v7)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "query":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Query = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Query == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Query = make([]string, 0, 4)
|
||||
} else {
|
||||
out.Query = []string{}
|
||||
}
|
||||
} else {
|
||||
out.Query = (out.Query)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v8 string
|
||||
v8 = string(in.String())
|
||||
out.Query = append(out.Query, v8)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox1(out *jwriter.Writer, in rawForwardGeoResp) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"features\":"
|
||||
out.RawString(prefix[1:])
|
||||
if in.Features == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v9, v10 := range in.Features {
|
||||
if v9 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v10).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"query\":"
|
||||
out.RawString(prefix)
|
||||
if in.Query == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v11, v12 := range in.Query {
|
||||
if v11 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v12))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v rawForwardGeoResp) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox1(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v rawForwardGeoResp) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox1(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *rawForwardGeoResp) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox1(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *rawForwardGeoResp) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox1(l, v)
|
||||
}
|
||||
9
services/location/mapbox_lib/http.go
Normal file
9
services/location/mapbox_lib/http.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
type FastHttpClient interface {
|
||||
Do(req *fasthttp.Request, resp *fasthttp.Response) error
|
||||
}
|
||||
22
services/location/mapbox_lib/logger.go
Normal file
22
services/location/mapbox_lib/logger.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Logger interface {
|
||||
Debugf(msg string, params ...interface{})
|
||||
Errorf(msg string, params ...interface{})
|
||||
}
|
||||
|
||||
// withLogger helps to reduce unnecessary allocations
|
||||
func (c *config) withLogger(ctx context.Context, do func(Logger)) {
|
||||
if c.requestLogger != nil {
|
||||
do(c.requestLogger(ctx))
|
||||
return
|
||||
}
|
||||
|
||||
if c.logger != nil {
|
||||
do(c.logger)
|
||||
}
|
||||
}
|
||||
31
services/location/mapbox_lib/pools.go
Normal file
31
services/location/mapbox_lib/pools.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type noCopy struct{}
|
||||
|
||||
func (*noCopy) Lock() {}
|
||||
func (*noCopy) Unlock() {}
|
||||
|
||||
type stringsBufferPool struct {
|
||||
noCopy noCopy
|
||||
p sync.Pool
|
||||
}
|
||||
|
||||
func newStringsBufferPool() *stringsBufferPool {
|
||||
return &stringsBufferPool{p: sync.Pool{New: func() interface{} {
|
||||
return &bytes.Buffer{}
|
||||
}}}
|
||||
}
|
||||
|
||||
func (pool *stringsBufferPool) acquireStringsBuilder() *bytes.Buffer {
|
||||
return pool.p.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func (pool *stringsBufferPool) releaseStringsBuilder(b *bytes.Buffer) {
|
||||
b.Reset()
|
||||
pool.p.Put(b)
|
||||
}
|
||||
23
services/location/mapbox_lib/values.go
Normal file
23
services/location/mapbox_lib/values.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
const (
|
||||
slash = "/"
|
||||
comma = ','
|
||||
questionMark = "?"
|
||||
equalMark = '='
|
||||
ampersandMark = '&'
|
||||
)
|
||||
|
||||
// encodeValues do almost the same as url.Values.Encode() but faster and reuses *strings.Builder
|
||||
func encodeValues(buf *bytes.Buffer, values map[string]string) {
|
||||
for k, v := range values {
|
||||
buf.WriteByte(ampersandMark)
|
||||
buf.WriteString(k)
|
||||
buf.WriteByte(equalMark)
|
||||
buf.WriteString(v)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user