Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinmichaelchen committed May 28, 2022
1 parent f32e0df commit b18cf13
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 73 deletions.
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,15 @@ and [h3](https://h3geo.org/) (a hexagonal hierarchical geospatial indexing syste

## Project structure

| Directory | Description |
|-----------------------------------------------------|-------------------------------------------|
| [`./cmd`](./cmd) | CLI for making gRPC requests |
| [`./idl`](./idl/coop/drivers/dispatch/v1beta1) | Protobufs (Interface Definition Language) |
| [`./internal/app`](./internal/app) | App dependency injection / initialization |
| [`./internal/distance`](internal/service/distance) | Google Maps Distance Matrix logic |
| [`./internal/idl`](./internal/idl) | Auto-generated protobufs |
| [`./internal/models`](./internal/models) | Auto-generated ORM / models |
| [`./internal/service`](./internal/service) | Service layer / Business logic |
| [`./schema`](./schema) | SQL migration scripts |
| Directory | Description |
|--------------------------------------------------|-------------------------------------------|
| [`./cmd`](./cmd) | CLI for making gRPC requests |
| [`./idl`](./idl/coop/drivers/dispatch/v1beta1) | Protobufs (Interface Definition Language) |
| [`./internal/app`](./internal/app) | App dependency injection / initialization |
| [`./internal/idl`](./internal/idl) | Auto-generated protobufs |
| [`./internal/models`](./internal/models) | Auto-generated ORM / models |
| [`./internal/service`](./internal/service) | Service layer / Business logic |
| [`./schema`](./schema) | SQL migration scripts |

## How does it work

Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ go 1.18
require (
github.com/XSAM/otelsql v0.14.1
github.com/envoyproxy/protoc-gen-validate v0.1.0
github.com/codingsince1985/geo-golang v1.8.1
github.com/friendsofgo/errors v0.9.2
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/gojuno/go.osrm v0.1.0
github.com/google/go-cmp v0.5.8
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/kat-co/vala v0.0.0-20170210184112-42e1d8b61f12
github.com/kr/pretty v0.2.0
github.com/lib/pq v1.10.5
github.com/paulmach/go.geo v0.0.0-20180829195134-22b514266d33
github.com/rs/xid v1.4.0
Expand Down Expand Up @@ -55,6 +57,7 @@ require (
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/kr/text v0.1.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/codingsince1985/geo-golang v1.8.1 h1:6B+Ce5QkbSglCtesiNRkSYMRDDQsYrv4XKM3jJVdyTw=
github.com/codingsince1985/geo-golang v1.8.1/go.mod h1:Ue7HAjKwwCAbqB5Q0YskqqnIX8XjMHL5Jq2fsSrI2T8=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
Expand Down Expand Up @@ -337,6 +339,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/paulmach/go.geo v0.0.0-20180829195134-22b514266d33 h1:doG/0aLlWE6E4ndyQlkAQrPwaojghwz1IlmH0kjTdyk=
github.com/paulmach/go.geo v0.0.0-20180829195134-22b514266d33/go.mod h1:btFYk/ltlMU7ZKguHS7zQrwHYCtLoXGTaa44OsPbEVw=
github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY=
Expand Down
18 changes: 9 additions & 9 deletions internal/app/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
"github.com/friendsofgo/errors"
"github.com/kevinmichaelchen/api-dispatch/internal/service"
"github.com/kevinmichaelchen/api-dispatch/internal/service/db"
"github.com/kevinmichaelchen/api-dispatch/internal/service/distance"
"github.com/kevinmichaelchen/api-dispatch/internal/service/maps"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.uber.org/fx"
"go.uber.org/zap"
"googlemaps.github.io/maps"
gmaps "googlemaps.github.io/maps"
"os"
)

Expand All @@ -26,7 +26,7 @@ var Module = fx.Module("service",
type Params struct {
fx.In
DataStore *db.Store
DistanceService *distance.Service `optional:"true"`
DistanceService *maps.Service `optional:"true"`
}

func NewService(p Params) *service.Service {
Expand All @@ -37,24 +37,24 @@ func NewDataStore(sqlDB *sql.DB) *db.Store {
return db.NewStore(sqlDB)
}

func NewMapsClient() (*maps.Client, error) {
func NewMapsClient() (*gmaps.Client, error) {
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
return nil, errors.New("missing API_KEY for Google Maps")
}
c, err := maps.NewClient(
maps.WithAPIKey(apiKey),
maps.WithHTTPClient(otelhttp.DefaultClient),
c, err := gmaps.NewClient(
gmaps.WithAPIKey(apiKey),
gmaps.WithHTTPClient(otelhttp.DefaultClient),
)
if err != nil {
return nil, fmt.Errorf("failed to build Google Maps client: %w", err)
}
return c, nil
}

func NewDistanceService(logger *zap.Logger, client *maps.Client) (*distance.Service, error) {
func NewDistanceService(logger *zap.Logger, client *gmaps.Client) (*maps.Service, error) {
if client == nil {
return nil, errors.New("no maps client")
}
return distance.NewService(client), nil
return maps.NewService(client), nil
}
16 changes: 9 additions & 7 deletions internal/service/dispatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
"github.com/kevinmichaelchen/api-dispatch/internal/idl/coop/drivers/dispatch/v1beta1"
"github.com/kevinmichaelchen/api-dispatch/internal/service/distance"
"github.com/kevinmichaelchen/api-dispatch/internal/service/maps"
"github.com/kevinmichaelchen/api-dispatch/internal/service/money"
"github.com/kevinmichaelchen/api-dispatch/internal/service/ranking"
"go.uber.org/zap"
Expand Down Expand Up @@ -66,9 +66,10 @@ func (s *Service) GetNearestDrivers(
}
var pickupAddress string
if trafficAware {
out, err := s.distanceSvc.BetweenPoints(ctx, distance.BetweenPointsInput{
PickupLocations: []*v1beta1.LatLng{req.GetPickupLocation()},
DriverLocations: driverLocations,
out, err := s.distanceSvc.BetweenPoints(ctx, maps.BetweenPointsInput{
// the driver location(s) is/are always the origin(s)
Origins: driverLocations,
Destinations: []*v1beta1.LatLng{req.GetPickupLocation()},
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -144,9 +145,10 @@ func (s *Service) GetNearestTrips(
locations = append(locations, result.GetLocation())
}
if trafficAware {
out, err := s.distanceSvc.BetweenPoints(ctx, distance.BetweenPointsInput{
PickupLocations: locations,
DriverLocations: []*v1beta1.LatLng{req.GetDriverLocation()},
out, err := s.distanceSvc.BetweenPoints(ctx, maps.BetweenPointsInput{
// the driver location(s) is/are always the origin(s)
Origins: []*v1beta1.LatLng{req.GetDriverLocation()},
Destinations: locations,
})
if err != nil {
return nil, err
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package distance
package maps

import (
"context"
Expand All @@ -18,8 +18,8 @@ func NewService(client *maps.Client) *Service {
}

type BetweenPointsInput struct {
PickupLocations []*v1beta1.LatLng
DriverLocations []*v1beta1.LatLng
Destinations []*v1beta1.LatLng
Origins []*v1beta1.LatLng
}

type BetweenPointsOutput struct {
Expand All @@ -34,19 +34,21 @@ type Info struct {
}

func (s *Service) BetweenPoints(ctx context.Context, in BetweenPointsInput) (*BetweenPointsOutput, error) {
driverPlaceIDs, err := locationsToPlaceIDs(ctx, s.client, in.DriverLocations)
origins, err := locationsToPlaceIDs(ctx, s.client, in.Origins)
if err != nil {
return nil, err
}

pickupPlaceIDs, err := locationsToPlaceIDs(ctx, s.client, in.PickupLocations)
destinations, err := locationsToPlaceIDs(ctx, s.client, in.Destinations)
if err != nil {
return nil, err
}

// TODO if len(origins) > 25 || len(destinations) > 25, we need to partition/batch

res, err := betweenPlaces(ctx, s.client, betweenPlacesInput{
originPlaceIDs: driverPlaceIDs,
destinationPlaceIDs: pickupPlaceIDs,
originPlaceIDs: origins,
destinationPlaceIDs: destinations,
})
if err != nil {
return nil, err
Expand Down
31 changes: 31 additions & 0 deletions internal/service/maps/google/reverse_geocode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package google

import (
"context"
"errors"
"github.com/kevinmichaelchen/api-dispatch/internal/idl/coop/drivers/dispatch/v1beta1"
"googlemaps.github.io/maps"
)

var errNoResults = errors.New("no results found for coordinates")

func ReverseGeocode(ctx context.Context, c *maps.Client, location *v1beta1.LatLng) ([]maps.GeocodingResult, error) {
results, err := c.ReverseGeocode(ctx, &maps.GeocodingRequest{
LatLng: &maps.LatLng{
Lat: location.GetLatitude(),
Lng: location.GetLongitude(),
},
ResultType: nil,
LocationType: nil,
PlaceID: "",
Language: "",
Custom: nil,
})
if err != nil {
return nil, err
}
if len(results) == 0 {
return nil, errNoResults
}
return results, err
}
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions internal/service/maps/osrm/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
Package osrm provides functions over the Open Source Routing Machine project.
We use OSRM's Table service when we want to quickly determine the duration
and/or distance between two points (without traffic awareness). This could be
useful for saving money/requests to Google Maps API every time an anonymous end
user sees an estimate quote for a potential trip.
https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#table-service
We use OpenStreetMap's /reverse endpoint for reverse geocoding.
https://nominatim.org/release-docs/develop/api/Reverse/
*/
package osrm
34 changes: 34 additions & 0 deletions internal/service/maps/osrm/reverse_geocode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package osrm

import (
"fmt"
"github.com/codingsince1985/geo-golang"
"github.com/codingsince1985/geo-golang/openstreetmap"
"github.com/kr/pretty"
)

const (
addr = "Melbourne VIC"
lat, lng = -37.813611, 144.963056
)

func ReverseGeocode() {
try(openstreetmap.Geocoder())
}

func try(geocoder geo.Geocoder) {
location, _ := geocoder.Geocode(addr)
if location != nil {
fmt.Printf("%s location is (%.6f, %.6f)\n", addr, location.Lat, location.Lng)
} else {
fmt.Println("got <nil> location")
}
address, _ := geocoder.ReverseGeocode(lat, lng)
if address != nil {
fmt.Printf("Address of (%.6f,%.6f) is %s\n", lat, lng, address.FormattedAddress)
pretty.Println(address)
} else {
fmt.Println("got <nil> address")
}
fmt.Print("\n")
}
7 changes: 7 additions & 0 deletions internal/service/maps/osrm/reverse_geocode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package osrm

import "testing"

func TestReverseGeocode(t *testing.T) {
ReverseGeocode()
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package distance
package maps

import (
"context"
"errors"
"fmt"
"github.com/kevinmichaelchen/api-dispatch/internal/idl/coop/drivers/dispatch/v1beta1"
"github.com/kevinmichaelchen/api-dispatch/internal/service/maps/google"
"golang.org/x/sync/errgroup"
"googlemaps.github.io/maps"
"strconv"
Expand All @@ -16,8 +17,6 @@ const (
parallelizationFactor = 10
)

var errNoResults = errors.New("no results found for coordinates")

type Place struct {
ID string
Address string
Expand Down Expand Up @@ -72,7 +71,7 @@ func locationsToPlaceIDs(ctx context.Context, c *maps.Client, locations []*v1bet
}()

for location := range locationsChan {
geocodingResults, err := reverseGeocode(ctx, c, location)
geocodingResults, err := google.ReverseGeocode(ctx, c, location)
if err != nil {
return fmt.Errorf("failed to reverse geocode location: %w", err)
} else {
Expand Down Expand Up @@ -140,24 +139,3 @@ func locationsToPlaceIDs(ctx context.Context, c *maps.Client, locations []*v1bet
}
return out, nil
}

func reverseGeocode(ctx context.Context, c *maps.Client, location *v1beta1.LatLng) ([]maps.GeocodingResult, error) {
results, err := c.ReverseGeocode(ctx, &maps.GeocodingRequest{
LatLng: &maps.LatLng{
Lat: location.GetLatitude(),
Lng: location.GetLongitude(),
},
ResultType: nil,
LocationType: nil,
PlaceID: "",
Language: "",
Custom: nil,
})
if err != nil {
return nil, err
}
if len(results) == 0 {
return nil, errNoResults
}
return results, err
}
12 changes: 0 additions & 12 deletions internal/service/osrm/doc.go

This file was deleted.

6 changes: 3 additions & 3 deletions internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"context"
"github.com/kevinmichaelchen/api-dispatch/internal/idl/coop/drivers/dispatch/v1beta1"
"github.com/kevinmichaelchen/api-dispatch/internal/service/db"
"github.com/kevinmichaelchen/api-dispatch/internal/service/distance"
"github.com/kevinmichaelchen/api-dispatch/internal/service/health"
"github.com/kevinmichaelchen/api-dispatch/internal/service/maps"
"google.golang.org/grpc/codes"
healthV1 "google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/status"
Expand All @@ -14,10 +14,10 @@ import (

type Service struct {
dataStore *db.Store
distanceSvc *distance.Service
distanceSvc *maps.Service
}

func NewService(dataStore *db.Store, distanceSvc *distance.Service) *Service {
func NewService(dataStore *db.Store, distanceSvc *maps.Service) *Service {
return &Service{dataStore: dataStore, distanceSvc: distanceSvc}
}

Expand Down

0 comments on commit b18cf13

Please sign in to comment.