mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-11 19:04:35 +00:00
133 lines
3.6 KiB
Go
133 lines
3.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"googlemaps.github.io/maps"
|
|
|
|
"github.com/micro/micro/v3/service/errors"
|
|
"github.com/micro/micro/v3/service/logger"
|
|
pb "github.com/micro/services/routing/proto"
|
|
)
|
|
|
|
var (
|
|
ErrDownstream = errors.InternalServerError("ROUTING_ERROR", "Unable to connect to routing provider")
|
|
ErrMissingOrigin = errors.BadRequest("MISSING_ORIGIN", "Missing origin")
|
|
ErrMissingDestination = errors.BadRequest("MISSING_DESTINATION", "Missing destination")
|
|
ErrMissingLatitude = errors.BadRequest("MISSING_LATITUDE", "Missing latitude")
|
|
ErrMissingLongitude = errors.BadRequest("MISSING_LONGITUDE", "Missing longitude")
|
|
ErrNoRoutes = errors.BadRequest("NO_ROUTES", "No routes found")
|
|
ErrUnimplemented = errors.InternalServerError("UNIMPLEMENTED", "endpoint is unimplemented")
|
|
)
|
|
|
|
type Google struct {
|
|
Maps *maps.Client
|
|
}
|
|
|
|
func (r *Google) Directions(ctx context.Context, req *pb.DirectionsRequest, rsp *pb.DirectionsResponse) error {
|
|
// TODO: implement eta
|
|
return ErrUnimplemented
|
|
}
|
|
|
|
// Calculate the ETAs for a route
|
|
func (r *Google) Eta(ctx context.Context, req *pb.EtaRequest, rsp *pb.EtaResponse) error {
|
|
// validate the request
|
|
if req.Origin == nil {
|
|
return ErrMissingOrigin
|
|
}
|
|
if req.Destination == nil {
|
|
return ErrMissingDestination
|
|
}
|
|
if err := validatePoint(req.Origin); err != nil {
|
|
return err
|
|
}
|
|
if err := validatePoint(req.Destination); err != nil {
|
|
return err
|
|
}
|
|
|
|
// construct the request
|
|
resp, err := r.Maps.DistanceMatrix(ctx, &maps.DistanceMatrixRequest{
|
|
Origins: []string{pointToString(req.Origin)},
|
|
Destinations: []string{pointToString(req.Destination)},
|
|
DepartureTime: "now",
|
|
Units: "UnitsMetric",
|
|
Mode: maps.TravelModeDriving,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// check the correct number of elements (route segments) were returned
|
|
// from the Google API
|
|
if len(resp.Rows[0].Elements) != 1 {
|
|
return errors.InternalServerError("routing.eta", "Invalid downstream response. Expected %v segments but got %v", 1, len(resp.Rows[0].Elements))
|
|
}
|
|
|
|
// set the response duration in seconds
|
|
rsp.Duration = float64(resp.Rows[0].Elements[0].Duration.Seconds())
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Google) Route(ctx context.Context, req *pb.RouteRequest, rsp *pb.RouteResponse) error {
|
|
// validate the request
|
|
if req.Origin == nil {
|
|
return ErrMissingOrigin
|
|
}
|
|
if req.Destination == nil {
|
|
return ErrMissingDestination
|
|
}
|
|
if err := validatePoint(req.Origin); err != nil {
|
|
return err
|
|
}
|
|
if err := validatePoint(req.Destination); err != nil {
|
|
return err
|
|
}
|
|
|
|
// query google maps
|
|
routes, _, err := r.Maps.Directions(ctx, &maps.DirectionsRequest{
|
|
Origin: pointToString(req.Origin), Destination: pointToString(req.Destination),
|
|
})
|
|
if err != nil {
|
|
logger.Errorf("Error geocoding: %v. Origin: '%v', Destination: '%v'", err, pointToString(req.Origin), pointToString(req.Destination))
|
|
return ErrDownstream
|
|
}
|
|
if len(routes) == 0 {
|
|
return ErrNoRoutes
|
|
}
|
|
|
|
// decode the points
|
|
points, err := routes[0].OverviewPolyline.Decode()
|
|
if err != nil {
|
|
logger.Errorf("Error decoding polyline: %v", err)
|
|
return ErrDownstream
|
|
}
|
|
|
|
// return the result
|
|
rsp.Waypoints = make([]*pb.Waypoint, len(points))
|
|
for i, p := range points {
|
|
rsp.Waypoints[i] = &pb.Waypoint{
|
|
Location: &pb.Point{
|
|
Latitude: p.Lat,
|
|
Longitude: p.Lng,
|
|
},
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validatePoint(p *pb.Point) error {
|
|
if p.Latitude == 0.0 {
|
|
return ErrMissingLatitude
|
|
}
|
|
if p.Longitude == 0.0 {
|
|
return ErrMissingLongitude
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func pointToString(p *pb.Point) string {
|
|
return fmt.Sprintf("%v,%v", p.Latitude, p.Longitude)
|
|
}
|