upstream sync
This commit is contained in:
@@ -23,9 +23,10 @@ func Load() error {
|
|||||||
|
|
||||||
Service: Service{
|
Service: Service{
|
||||||
// 9000 DEFAULT FOR DEV ENVIRONMENT
|
// 9000 DEFAULT FOR DEV ENVIRONMENT
|
||||||
Port: getEnv("NOVATECH_SERVICE_PORT", "9000"),
|
Port: getEnv("NOVATECH_SERVICE_PORT", "9000"),
|
||||||
Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"),
|
Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"),
|
||||||
BlockchainSecret: getEnv("NOVATECH_SERVICE_BLOCKCHAIN_SECRET", "novatech_service_blockchain_secret"),
|
BlockchainSecret: getEnv("NOVATECH_SERVICE_BLOCKCHAIN_SECRET", "novatech_service_blockchain_secret"),
|
||||||
|
MapboxAccessToken: getEnv("NOVATECH_SERVICE_MAPBOX_ACCESS_TOKEN", ""),
|
||||||
},
|
},
|
||||||
AdminService: Service{
|
AdminService: Service{
|
||||||
// 8080 DEFAULT FOR DEV ENVIRONMENT
|
// 8080 DEFAULT FOR DEV ENVIRONMENT
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ type Config struct {
|
|||||||
|
|
||||||
// Service contains configuration for service
|
// Service contains configuration for service
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Port string
|
Port string
|
||||||
Environment string
|
Environment string
|
||||||
WebPageURL string
|
WebPageURL string
|
||||||
BlockchainSecret string
|
BlockchainSecret string
|
||||||
|
MapboxAccessToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blockchain contains configuration for blockchain
|
// Blockchain contains configuration for blockchain
|
||||||
|
|||||||
@@ -150,9 +150,6 @@ func GetContractStatuses(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{"data": models.GetContractStatuses()})
|
c.JSON(http.StatusOK, gin.H{"data": models.GetContractStatuses()})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func CreateContract(c *gin.Context) {
|
func CreateContract(c *gin.Context) {
|
||||||
|
|
||||||
var payload models.CreateContractRequestPayload
|
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_NETWORK_ENDPOINT="https://polygon-mumbai.infura.io/v3/4458cf4d1689497b9a38b1d6bbf05e78"
|
||||||
NOVATECH_BLOCKCHAIN_CONTRACT_ADDRESS=0x121Cb4bFEeDb55d598D8F5e9EeDF8bB14c421d96
|
NOVATECH_BLOCKCHAIN_CONTRACT_ADDRESS=0x121Cb4bFEeDb55d598D8F5e9EeDF8bB14c421d96
|
||||||
NOVATECH_BLOCKCHAIN_WALLET_ADDRESS=0x20eff5decaed29bd64f0c6385956363eeaaf4d3e
|
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/jinzhu/gorm v1.9.16
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/lib/pq v1.8.0
|
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/qor/admin v1.2.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
|
github.com/valyala/fasthttp v1.40.0
|
||||||
)
|
)
|
||||||
|
|
||||||
replace gitlab.com/pactual1/backend => ./
|
replace gitlab.com/pactual1/backend => ./
|
||||||
@@ -19,6 +22,7 @@ require (
|
|||||||
github.com/DataDog/zstd v1.5.5 // indirect
|
github.com/DataDog/zstd v1.5.5 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
github.com/VictoriaMetrics/fastcache v1.12.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/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.8.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/holiman/uint256 v1.2.3 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.1 // 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/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.17.0 // indirect
|
github.com/klauspost/compress v1.17.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5 // 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/tklauser/numcpus v0.6.1 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // 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
|
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||||
golang.org/x/arch v0.5.0 // indirect
|
golang.org/x/arch v0.5.0 // indirect
|
||||||
golang.org/x/crypto v0.13.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 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
|
||||||
github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
|
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/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 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
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/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 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
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 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
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 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
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=
|
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.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
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.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
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/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 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
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 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
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=
|
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-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-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-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 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
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-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-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-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 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
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-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-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-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.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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.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.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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.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 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
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 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
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 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
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=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
@@ -9,60 +9,60 @@ import (
|
|||||||
|
|
||||||
type Contract struct {
|
type Contract struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||||
BuyerID uint `json:"buyerId"`
|
BuyerID uint `json:"buyerId"`
|
||||||
SellerID uint `json:"sellerId"`
|
SellerID uint `json:"sellerId"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
StartLat float64 `json:"startLat"`
|
StartPlaceName string `json:"startPlaceName"`
|
||||||
StartLon float64 `json:"startLon"`
|
StartLat float64 `json:"startLat"`
|
||||||
EndLat float64 `json:"endLat"`
|
StartLon float64 `json:"startLon"`
|
||||||
EndLon float64 `json:"endLon"`
|
EndPlaceName string `json:"endPlaceName"`
|
||||||
StartTime time.Time `json:"startTime"`
|
EndLat float64 `json:"endLat"`
|
||||||
EndTime time.Time `json:"endTime"`
|
EndLon float64 `json:"endLon"`
|
||||||
Status string `json:"status"`
|
StartTime time.Time `json:"startTime"`
|
||||||
BlockchainID string `json:"blockchainId"`
|
EndTime time.Time `json:"endTime"`
|
||||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
Status string `json:"status"`
|
||||||
ProductID uint `json:"productId"`
|
BlockchainID string `json:"blockchainId"`
|
||||||
MaxTemp float64 `json:"maxTemp"`
|
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||||
MinTemp float64 `json:"minTemp"`
|
ProductID uint `json:"productId"`
|
||||||
ArrivalDate time.Time `json:"arrivalDate"`
|
MaxTemp float64 `json:"maxTemp"`
|
||||||
PenaltyType string `json:"penaltyType"`
|
MinTemp float64 `json:"minTemp"`
|
||||||
PenaltyValue int `json:"penaltyValue"`
|
ArrivalDate time.Time `json:"arrivalDate"`
|
||||||
PenaltyRec string `json:"penaltyRec"`
|
PenaltyType string `json:"penaltyType"`
|
||||||
BuyerName string `json:"buyerName" gorm:"-"`
|
PenaltyValue int `json:"penaltyValue"`
|
||||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
PenaltyRec string `json:"penaltyRec"`
|
||||||
|
BuyerName string `json:"buyerName" gorm:"-"`
|
||||||
|
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContractResponse struct {
|
type ContractResponse struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||||
BuyerID uint `json:"buyerId"`
|
BuyerID uint `json:"buyerId"`
|
||||||
SellerID uint `json:"sellerId"`
|
SellerID uint `json:"sellerId"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
StartLat float64 `json:"startLat"`
|
StartLat float64 `json:"startLat"`
|
||||||
StartLon float64 `json:"startLon"`
|
StartLon float64 `json:"startLon"`
|
||||||
EndLat float64 `json:"endLat"`
|
EndLat float64 `json:"endLat"`
|
||||||
EndLon float64 `json:"endLon"`
|
EndLon float64 `json:"endLon"`
|
||||||
StartTime time.Time `json:"startTime"`
|
StartTime time.Time `json:"startTime"`
|
||||||
EndTime time.Time `json:"endTime"`
|
EndTime time.Time `json:"endTime"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
BlockchainID string `json:"blockchainId"`
|
BlockchainID string `json:"blockchainId"`
|
||||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||||
ProductID uint `json:"productId"`
|
ProductID uint `json:"productId"`
|
||||||
MaxTemp float64 `json:"maxTemp"`
|
MaxTemp float64 `json:"maxTemp"`
|
||||||
MinTemp float64 `json:"minTemp"`
|
MinTemp float64 `json:"minTemp"`
|
||||||
ArrivalDate time.Time `json:"arrivalDate"`
|
ArrivalDate time.Time `json:"arrivalDate"`
|
||||||
PenaltyType string `json:"penaltyType"`
|
PenaltyType string `json:"penaltyType"`
|
||||||
PenaltyValue int `json:"penaltyValue"`
|
PenaltyValue int `json:"penaltyValue"`
|
||||||
PenaltyRec string `json:"penaltyRec"`
|
PenaltyRec string `json:"penaltyRec"`
|
||||||
BuyerName string `json:"buyerName" gorm:"-"`
|
BuyerName string `json:"buyerName" gorm:"-"`
|
||||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func ConvertContractToResponse(contracts []Contract) []ContractResponse {
|
func ConvertContractToResponse(contracts []Contract) []ContractResponse {
|
||||||
var contractResponses []ContractResponse
|
var contractResponses []ContractResponse
|
||||||
for _, contract := range contracts {
|
for _, contract := range contracts {
|
||||||
@@ -119,17 +119,18 @@ func ConvertContractToResponseModel(contracts []Contract) []ListContractResponse
|
|||||||
}
|
}
|
||||||
|
|
||||||
listInvoiceResponse := ListContractResponse{
|
listInvoiceResponse := ListContractResponse{
|
||||||
Status: KeyValue{Key: status.Key, Value: status.Value},
|
Status: KeyValue{Key: status.Key, Value: status.Value},
|
||||||
Buyer: CompanyShortResponse{ID: int(contract.BuyerID), Name: contract.BuyerName},
|
Buyer: CompanyShortResponse{ID: int(contract.BuyerID), Name: contract.BuyerName},
|
||||||
ContractID: int(contract.ID),
|
ContractID: int(contract.ID),
|
||||||
DateCreated: contract.CreatedAt,
|
DateCreated: contract.CreatedAt,
|
||||||
NumberOfDevices: contract.NumberOfDevices,
|
NumberOfDevices: contract.NumberOfDevices,
|
||||||
}
|
}
|
||||||
listInvoiceResponses = append(listInvoiceResponses, listInvoiceResponse)
|
listInvoiceResponses = append(listInvoiceResponses, listInvoiceResponse)
|
||||||
}
|
}
|
||||||
return listInvoiceResponses
|
return listInvoiceResponses
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContractStatusActive = "active"
|
const ContractStatusActive = "active"
|
||||||
const ContractStatusPending = "pending"
|
const ContractStatusPending = "pending"
|
||||||
const ContractStatusDraft = "draft"
|
const ContractStatusDraft = "draft"
|
||||||
@@ -138,14 +139,12 @@ const ContractStatusReadyForActivation = "ready_for_activation"
|
|||||||
const ContractStatusExecuted = "executed"
|
const ContractStatusExecuted = "executed"
|
||||||
const ContractStatusRevoked = "revoked"
|
const ContractStatusRevoked = "revoked"
|
||||||
|
|
||||||
|
|
||||||
const PenaltyTypeAmount = "amount"
|
const PenaltyTypeAmount = "amount"
|
||||||
const PenaltyTypePercentage = "percentage"
|
const PenaltyTypePercentage = "percentage"
|
||||||
|
|
||||||
const PenaltyRecDaily = "daily"
|
const PenaltyRecDaily = "daily"
|
||||||
const PenaltyRecMonthly = "monthly"
|
const PenaltyRecMonthly = "monthly"
|
||||||
|
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
@@ -164,25 +163,24 @@ func GetContractStatuses() []Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ListContractResponse struct {
|
type ListContractResponse struct {
|
||||||
Status KeyValue `json:"status"`
|
Status KeyValue `json:"status"`
|
||||||
Buyer CompanyShortResponse `json:"buyer"`
|
Buyer CompanyShortResponse `json:"buyer"`
|
||||||
ContractID int `json:"contractID"`
|
ContractID int `json:"contractID"`
|
||||||
NumberOfDevices int `json:"numberOfDevices"`
|
NumberOfDevices int `json:"numberOfDevices"`
|
||||||
DateCreated time.Time `json:"dateCreated"`
|
DateCreated time.Time `json:"dateCreated"`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateContractRequestPayload struct {
|
type CreateContractRequestPayload struct {
|
||||||
SellerID uint `json:"sellerId" binding:"required"`
|
SellerID uint `json:"sellerId" binding:"required"`
|
||||||
BuyerID uint `json:"buyerId" binding:"required"`
|
BuyerID uint `json:"buyerId" binding:"required"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
ProductID uint `json:"productId"`
|
ProductID uint `json:"productId"`
|
||||||
MinTemp float64 `json:"minTemp" binding:"required"`
|
MinTemp float64 `json:"minTemp" binding:"required"`
|
||||||
MaxTemp float64 `json:"maxTemp" binding:"required"`
|
MaxTemp float64 `json:"maxTemp" binding:"required"`
|
||||||
ArrivalDate int64 `json:"arrivalDate"`
|
ArrivalDate int64 `json:"arrivalDate"`
|
||||||
PenaltyType string `json:"penaltyType"`
|
PenaltyType string `json:"penaltyType"`
|
||||||
PenaltyValue int `json:"penaltyValue"`
|
PenaltyValue int `json:"penaltyValue"`
|
||||||
PenaltyRec string `json:"penaltyRec"`
|
PenaltyRec string `json:"penaltyRec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Contract) Update() (bool, error) {
|
func (Contract) Update() (bool, error) {
|
||||||
@@ -194,5 +192,3 @@ func (Contract) Create() (bool, error) {
|
|||||||
func (Contract) Delete() (bool, error) {
|
func (Contract) Delete() (bool, error) {
|
||||||
return false, nil
|
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/statuses", controllers.GetContractStatuses)
|
||||||
r.GET("/contracts", controllers.GetBuyerContracts)
|
r.GET("/contracts", controllers.GetBuyerContracts)
|
||||||
r.POST("/contracts/create", controllers.CreateContract)
|
r.POST("/contracts/create", controllers.CreateContract)
|
||||||
|
|
||||||
r.GET("/contracts/:contract_id", controllers.GetContractByID)
|
r.GET("/contracts/:contract_id", controllers.GetContractByID)
|
||||||
r.PATCH("/contracts/:contract_id", controllers.UpdateContract)
|
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