package routing import ( "bytes" "errors" "io/ioutil" "net/http" "time" "git.coopgo.io/coopgo-platform/routing-service/encoding/polylines" "git.coopgo.io/coopgo-platform/routing-service/proto/valhalla" "github.com/paulmach/orb" "github.com/rs/zerolog/log" "google.golang.org/protobuf/proto" ) type ValhallaRouting struct { BaseURL string } func NewValhallaRouting(baseURL string) (*ValhallaRouting, error) { return &ValhallaRouting{ BaseURL: baseURL, }, nil } func (v *ValhallaRouting) Route(locations []orb.Point) (route *Route, err error) { valhalla_locations := []*valhalla.Location{} for _, loc := range locations { valhalla_locations = append(valhalla_locations, &valhalla.Location{ Ll: &valhalla.LatLng{ HasLat: &valhalla.LatLng_Lat{Lat: loc.Lat()}, HasLng: &valhalla.LatLng_Lng{Lng: loc.Lon()}, }, }) } request := &valhalla.Api{ Options: &valhalla.Options{ Action: valhalla.Options_route, Locations: valhalla_locations, CostingType: valhalla.Costing_auto_, Format: valhalla.Options_pbf, }, } resp, err := v.protocolBufferRequest(request, "route") if err != nil { log.Error().Err(err).Msg("pb request to valhalla error") return nil, err } if resp.Directions == nil || resp.Directions.Routes == nil || len(resp.Directions.Routes) < 1 { return nil, errors.New("no routes returned by valhalla") } decodedLinestring := orb.LineString{} legs := []RouteLeg{} for _, leg := range resp.Directions.Routes[0].Legs { shape := leg.Shape decodedShape := polylines.Decode(&shape, 6) decodedLinestring = append(decodedLinestring, decodedShape...) routeLeg := RouteLeg{ Distance: float64(leg.Summary.Length), Duration: time.Duration(leg.Summary.Time) * time.Second, Polyline: polylines.Encode(decodedShape, 5), } legs = append(legs, routeLeg) } return &Route{ Summary: RouteSummary{ Polyline: polylines.Encode(decodedLinestring, 5), }, Legs: legs, }, nil } func (v *ValhallaRouting) protocolBufferRequest(api *valhalla.Api, path string) (*valhalla.Api, error) { data, err := proto.Marshal(api) if err != nil { return nil, err } req, err := http.NewRequest(http.MethodGet, v.BaseURL+path, bytes.NewBuffer(data)) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/x-protobuf") client := http.Client{} resp, err := client.Do(req) //resp, err := http.Post(v.BaseURL+path, "application/x-protobuf", bytes.NewBuffer(data)) if err != nil { return nil, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } response := valhalla.Api{} err = proto.Unmarshal(body, &response) if err != nil { return nil, err } return &response, nil }