refactor: update dependencies and improve distance matrix handling
Updates Go module dependencies to the latest compatible versions, including the integration of Cloud Maps routing API. Refactors the distance matrix handling to utilize the new routing client, ensuring proper request formation and error handling for lat/lng parsing. This enhances functionality and maintains compatibility with updated libraries.
This commit is contained in:
@@ -4,12 +4,18 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cloud.google.com/go/maps/routing/apiv2"
|
||||
"cloud.google.com/go/maps/routing/apiv2/routingpb"
|
||||
"github.com/caarlos0/env"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/genproto/googleapis/type/latlng"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"googlemaps.github.io/maps"
|
||||
)
|
||||
|
||||
@@ -60,15 +66,25 @@ func main() {
|
||||
}
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
|
||||
client, err := maps.NewClient(maps.WithAPIKey(cfg.MapsApiKey))
|
||||
mapsClient, err := maps.NewClient(maps.WithAPIKey(cfg.MapsApiKey))
|
||||
if err != nil {
|
||||
log.Fatalf("fatal error: %s", err)
|
||||
slog.With("error", err).Error("new maps client")
|
||||
return
|
||||
}
|
||||
routesClient, err := routing.NewRoutesClient(context.Background(), option.WithAPIKey(cfg.MapsApiKey))
|
||||
if err != nil {
|
||||
slog.With("error", err).Error("new routes client")
|
||||
return
|
||||
}
|
||||
|
||||
http.HandleFunc("/latlong/", makeHandler(handleLatLongRequest, client))
|
||||
http.HandleFunc("/address/", makeHandler(handleAddressRequest, client))
|
||||
http.HandleFunc("/distance/", makeHandler(handleDistanceMatrixRequest, client))
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), nil))
|
||||
http.HandleFunc("/latlong/", makeHandler(handleLatLongRequest, mapsClient))
|
||||
http.HandleFunc("/address/", makeHandler(handleAddressRequest, mapsClient))
|
||||
http.HandleFunc("/distance/", func(w http.ResponseWriter, r *http.Request) {
|
||||
handleDistanceMatrixRequest(w, r, routesClient)
|
||||
})
|
||||
if err := http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), nil); err != nil {
|
||||
slog.With("error", err).Error("listen and serve")
|
||||
}
|
||||
}
|
||||
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request, *maps.Client), client *maps.Client) http.HandlerFunc {
|
||||
@@ -77,57 +93,98 @@ func makeHandler(fn func(http.ResponseWriter, *http.Request, *maps.Client), clie
|
||||
}
|
||||
}
|
||||
|
||||
func handleDistanceMatrixRequest(w http.ResponseWriter, r *http.Request, client *maps.Client) {
|
||||
origins := strings.Split(r.URL.Query().Get("origins"), "|")
|
||||
func handleDistanceMatrixRequest(w http.ResponseWriter, r *http.Request, client *routing.RoutesClient) {
|
||||
ctx := context.Background()
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, "X-Goog-Fieldmask", "originIndex,destinationIndex,duration,distanceMeters,status")
|
||||
origins := make([]*routingpb.RouteMatrixOrigin, 0)
|
||||
destinations := make([]*routingpb.RouteMatrixDestination, 0)
|
||||
for _, origin := range strings.Split(r.URL.Query().Get("origins"), "|") {
|
||||
origins = append(origins, &routingpb.RouteMatrixOrigin{
|
||||
Waypoint: &routingpb.Waypoint{
|
||||
LocationType: &routingpb.Waypoint_Address{Address: origin},
|
||||
},
|
||||
})
|
||||
}
|
||||
destinationsString := r.URL.Query().Get("destinations")
|
||||
if destinationsString == "" {
|
||||
x := make([]origin, len(origins))
|
||||
for i, o := range origins {
|
||||
x[i] = origin{Origin: o}
|
||||
x[i] = origin{Origin: o.Waypoint.GetAddress()}
|
||||
}
|
||||
writeResponse(distanceResponse{Origins: x}, w)
|
||||
return
|
||||
}
|
||||
destinations := strings.Split(destinationsString, "|")
|
||||
|
||||
req := &maps.DistanceMatrixRequest{
|
||||
for _, destination := range strings.Split(destinationsString, "|") {
|
||||
parts := strings.Split(destination, ",")
|
||||
lat, err := strconv.ParseFloat(parts[0], 64)
|
||||
if err != nil {
|
||||
slog.With("error", err, "part", "handleDistanceMatrixRequest", "latlng", destination).Error("unable to parse latitude")
|
||||
w.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
lng, err := strconv.ParseFloat(parts[1], 64)
|
||||
if err != nil {
|
||||
slog.With("error", err, "part", "handleDistanceMatrixRequest", "latlng", destination).Error("unable to parse longitude")
|
||||
w.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
destinations = append(destinations, &routingpb.RouteMatrixDestination{
|
||||
Waypoint: &routingpb.Waypoint{
|
||||
LocationType: &routingpb.Waypoint_Location{Location: &routingpb.Location{LatLng: &latlng.LatLng{
|
||||
Latitude: lat,
|
||||
Longitude: lng,
|
||||
}}},
|
||||
},
|
||||
})
|
||||
}
|
||||
matrixRequest := &routingpb.ComputeRouteMatrixRequest{
|
||||
Origins: origins,
|
||||
Destinations: destinations,
|
||||
Language: "sv",
|
||||
Units: maps.UnitsMetric,
|
||||
Units: routingpb.Units_METRIC,
|
||||
}
|
||||
|
||||
if result, err := client.DistanceMatrix(context.Background(), req); err != nil {
|
||||
log.Fatalf("matrix fatal error: %s", err)
|
||||
response, err := client.ComputeRouteMatrix(ctx, matrixRequest)
|
||||
if err != nil {
|
||||
slog.With("error", err, "part", "handleDistanceMatrixRequest").Error("compute matrix")
|
||||
w.WriteHeader(400)
|
||||
} else {
|
||||
res := distanceResponse{}
|
||||
|
||||
for i, r := range result.Rows {
|
||||
var dests []destination
|
||||
for j, e := range r.Elements {
|
||||
dests = append(dests, destination{
|
||||
destinations[j],
|
||||
distance{
|
||||
Text: e.Distance.HumanReadable,
|
||||
Value: e.Distance.Meters,
|
||||
},
|
||||
duration{
|
||||
e.Duration.String(),
|
||||
e.Duration.Minutes(),
|
||||
},
|
||||
})
|
||||
}
|
||||
res.Origins = append(res.Origins, origin{origins[i], dests})
|
||||
}
|
||||
|
||||
writeResponse(res, w)
|
||||
return
|
||||
}
|
||||
|
||||
res := distanceResponse{}
|
||||
dests := make([][]destination, len(origins))
|
||||
|
||||
for {
|
||||
elem, err := response.Recv()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
slog.With("error", err, "part", "handleDistanceMatrixRequest").Error("fetch result")
|
||||
w.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
ll := destinations[*elem.DestinationIndex].Waypoint.GetLocation().LatLng
|
||||
|
||||
dests[*elem.OriginIndex] = append(dests[*elem.OriginIndex], destination{
|
||||
Destination: fmt.Sprintf("%f,%f", ll.Latitude, ll.Longitude),
|
||||
Distance: distance{
|
||||
Text: string(elem.DistanceMeters),
|
||||
Value: int(elem.DistanceMeters),
|
||||
},
|
||||
Duration: duration{
|
||||
elem.Duration.AsDuration().String(),
|
||||
elem.Duration.AsDuration().Minutes(),
|
||||
},
|
||||
})
|
||||
}
|
||||
for i, dest := range dests {
|
||||
res.Origins = append(res.Origins, origin{origins[i].Waypoint.GetAddress(), dest})
|
||||
}
|
||||
writeResponse(res, w)
|
||||
}
|
||||
|
||||
func writeResponse(res distanceResponse, w http.ResponseWriter) {
|
||||
if response, err := json.Marshal(res); err != nil {
|
||||
log.Fatalf("fatal error: %s", err)
|
||||
slog.With("error", err, "part", "handleDistanceMatrixRequest").Error("marshal response error")
|
||||
w.WriteHeader(404)
|
||||
} else {
|
||||
_, _ = w.Write(response)
|
||||
@@ -142,7 +199,7 @@ func handleAddressRequest(w http.ResponseWriter, r *http.Request, client *maps.C
|
||||
LatLng: &maps.LatLng{Lat: lat, Lng: lng},
|
||||
}
|
||||
if result, err := client.Geocode(context.Background(), req); err != nil {
|
||||
log.Fatalf("fatal error: %s", err)
|
||||
slog.With("error", err, "part", "handleAddressRequest").Error("geocode")
|
||||
w.WriteHeader(400)
|
||||
} else {
|
||||
if len(result) > 0 {
|
||||
@@ -150,7 +207,7 @@ func handleAddressRequest(w http.ResponseWriter, r *http.Request, client *maps.C
|
||||
Address: result[0].FormattedAddress,
|
||||
}
|
||||
if response, err := json.Marshal(l); err != nil {
|
||||
log.Fatalf("fatal error: %s", err)
|
||||
slog.With("error", err, "part", "handleAddressRequest").Error("marshal response error")
|
||||
w.WriteHeader(404)
|
||||
} else {
|
||||
_, _ = w.Write(response)
|
||||
|
||||
Reference in New Issue
Block a user