package cmd import ( "context" "fmt" "os" "golang.org/x/time/rate" "googlemaps.github.io/maps" ) type Maps struct { around Location } func NewMapsOf(ctx context.Context, town string) (*Maps, error) { m := &Maps{} var err error m.around, err = m.textSearchOne(ctx, town) return m, err } var rps = 2 var limit = 200 var mapsLimiter = rate.NewLimiter(rate.Limit(rps), 1) type Location struct { Name string Lat float64 Lng float64 Address string } func (m *Maps) textSearchOne(ctx context.Context, query string) (Location, error) { results, err := m.textSearch(ctx, query) if err != nil { return Location{}, err } else if len(results) < 1 { return Location{}, fmt.Errorf("no results for %q", query) } return results[0], nil } func (m *Maps) textSearch(ctx context.Context, query string) ([]Location, error) { locations := []Location{} nextToken := "" for { results, err := m._textSearch(ctx, query, nextToken) if err != nil { return nil, err } for _, result := range results.Results { locations = append(locations, Location{ Name: result.Name, Lat: result.Geometry.Location.Lat, Lng: result.Geometry.Location.Lng, Address: result.FormattedAddress, }) } nextToken = results.NextPageToken if nextToken == "" { break } } return locations, ctx.Err() } func (m *Maps) _textSearch(ctx context.Context, query string, nextToken string) (maps.PlacesSearchResponse, error) { mapsLimiter.Wait(ctx) var location *maps.LatLng radius := uint(0) if m.around == (Location{}) { radius = 250 } else { location = &maps.LatLng{ Lat: m.around.Lat, Lng: m.around.Lng, } } return m.client().TextSearch(ctx, &maps.TextSearchRequest{ Query: query, Location: location, Radius: radius, PageToken: nextToken, }) } func (*Maps) client() *maps.Client { c, err := maps.NewClient(maps.WithAPIKey(os.Getenv("GOOGLE_PLACES_API_KEY"))) if err != nil { panic(err) } return c }