mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-12 11:15:12 +00:00
103 lines
2.6 KiB
Go
103 lines
2.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
pb "etas/proto"
|
|
|
|
"github.com/micro/micro/v3/service/errors"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
"googlemaps.github.io/maps"
|
|
)
|
|
|
|
type ETAs struct {
|
|
Maps *maps.Client
|
|
}
|
|
|
|
// Calculate the ETAs for a route
|
|
func (e *ETAs) Calculate(ctx context.Context, req *pb.Route, rsp *pb.Response) error {
|
|
// validate the request
|
|
if req.Pickup == nil {
|
|
return errors.BadRequest("etas.Calculate", "Missing pickup")
|
|
}
|
|
if len(req.Waypoints) == 0 {
|
|
return errors.BadRequest("etas.Calculate", "One more more waypoints required")
|
|
}
|
|
if err := validatePoint(req.Pickup, "Pickup"); err != nil {
|
|
return err
|
|
}
|
|
for i, p := range req.Waypoints {
|
|
if err := validatePoint(p, fmt.Sprintf("Waypoint %v", i)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// construct the request
|
|
destinations := make([]string, len(req.Waypoints))
|
|
for i, p := range req.Waypoints {
|
|
destinations[i] = pointToCoords(p)
|
|
}
|
|
departureTime := "now"
|
|
if req.StartTime != nil {
|
|
departureTime = req.StartTime.String()
|
|
}
|
|
resp, err := e.Maps.DistanceMatrix(ctx, &maps.DistanceMatrixRequest{
|
|
Origins: []string{pointToCoords(req.Pickup)},
|
|
Destinations: destinations,
|
|
DepartureTime: departureTime,
|
|
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) != len(destinations) {
|
|
return errors.InternalServerError("etas.Calculate", "Invalid downstream response. Expected %v segments but got %v", len(destinations), len(resp.Rows[0].Elements))
|
|
}
|
|
|
|
// calculate the response
|
|
currentTime := time.Now()
|
|
if req.StartTime != nil {
|
|
currentTime = req.StartTime.AsTime()
|
|
}
|
|
rsp.Points = make(map[string]*pb.ETA, len(req.Waypoints)+1)
|
|
for i, p := range append([]*pb.Point{req.Pickup}, req.Waypoints...) {
|
|
at := currentTime
|
|
if i > 0 {
|
|
at = at.Add(resp.Rows[0].Elements[i-1].Duration)
|
|
}
|
|
et := at.Add(time.Minute * time.Duration(p.WaitTime))
|
|
|
|
rsp.Points[p.Id] = &pb.ETA{
|
|
EstimatedArrivalTime: timestamppb.New(at),
|
|
EstimatedDepartureTime: timestamppb.New(et),
|
|
}
|
|
|
|
currentTime = et
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validatePoint(p *pb.Point, desc string) error {
|
|
if len(p.Id) == 0 {
|
|
return errors.BadRequest("etas.Calculate", "%v missing ID", desc)
|
|
}
|
|
if p.Latitude == 0 {
|
|
return errors.BadRequest("etas.Calculate", "%v missing Latitude", desc)
|
|
}
|
|
if p.Longitude == 0 {
|
|
return errors.BadRequest("etas.Calculate", "%v missing Longitude", desc)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func pointToCoords(p *pb.Point) string {
|
|
return fmt.Sprintf("%v,%v", p.Latitude, p.Longitude)
|
|
}
|