@@ -25,6 +25,7 @@ type Location struct {
2525 Cached bool `json:"-"`
2626}
2727
28+ // ApiName is the backend API name.
2829const ApiName = "places"
2930
3031var Key = "f60f5b25d59c397989e3cd374f81cdd7710a4fca"
@@ -36,18 +37,30 @@ var Retries = 3
3637var RetryDelay = 33 * time .Millisecond
3738var client = & http.Client {Timeout : 60 * time .Second }
3839
40+ // FindLocation retrieves location details from the backend API.
3941func FindLocation (id string ) (result Location , err error ) {
40- if len (id ) > 16 || len (id ) == 0 {
41- return result , fmt .Errorf ("invalid cell %s (%s)" , id , ApiName )
42+ // Normalize S2 Cell ID.
43+ id = s2 .NormalizeToken (id )
44+
45+ // Valid?
46+ if len (id ) == 0 {
47+ return result , fmt .Errorf ("empty cell id" )
48+ } else if n := len (id ); n < 4 || n > 16 {
49+ return result , fmt .Errorf ("invalid cell id %s" , txt .Quote (id ))
4250 }
4351
52+ // Remember start time.
4453 start := time .Now ()
54+
55+ // Convert S2 Cell ID to latitude and longitude.
4556 lat , lng := s2 .LatLng (id )
4657
58+ // Return if latitude and longitude are null.
4759 if lat == 0.0 || lng == 0.0 {
48- return result , fmt .Errorf ("skipping lat %f, lng %f (%s) " , lat , lng , ApiName )
60+ return result , fmt .Errorf ("skipping lat %f, lng %f" , lat , lng )
4961 }
5062
63+ // Location details cached?
5164 if hit , ok := cache .Get (id ); ok {
5265 log .Tracef ("places: cache hit for lat %f, lng %f" , lat , lng )
5366 cached := hit .(Location )
@@ -58,11 +71,13 @@ func FindLocation(id string) (result Location, err error) {
5871 // Compose request URL.
5972 url := fmt .Sprintf (ReverseLookupURL , id )
6073
74+ // Log request URL.
6175 log .Tracef ("places: sending request to %s" , url )
6276
6377 // Create GET request instance.
6478 req , err := http .NewRequest (http .MethodGet , url , nil )
6579
80+ // Ok?
6681 if err != nil {
6782 log .Errorf ("places: %s" , err .Error ())
6883 return result , err
@@ -98,89 +113,104 @@ func FindLocation(id string) (result Location, err error) {
98113
99114 // Failed?
100115 if err != nil {
101- log .Errorf ("places: %s (http request)" , err .Error ())
116+ log .Errorf ("places: %s (http request failed )" , err .Error ())
102117 return result , err
103118 } else if r .StatusCode >= 400 {
104- err = fmt .Errorf ("request failed with code %d (%s) " , r .StatusCode , ApiName )
119+ err = fmt .Errorf ("request failed with code %d" , r .StatusCode )
105120 return result , err
106121 }
107122
108123 // Decode JSON response body.
109124 err = json .NewDecoder (r .Body ).Decode (& result )
110125
111126 if err != nil {
112- log .Errorf ("places: %s (decode json)" , err .Error ())
127+ log .Errorf ("places: %s (decode json failed )" , err .Error ())
113128 return result , err
114129 }
115130
116131 if result .ID == "" {
117- return result , fmt .Errorf ("no result for %s (%s) " , id , ApiName )
132+ return result , fmt .Errorf ("no result for %s" , id )
118133 }
119134
120135 cache .SetDefault (id , result )
121- log .Tracef ("places: cached cell %s [%s]" , id , time .Since (start ))
136+ log .Tracef ("places: cached cell %s [%s]" , txt . Quote ( id ) , time .Since (start ))
122137
123138 result .Cached = false
124139
125140 return result , nil
126141}
127142
143+ // CellID returns the S2 cell identifier string.
128144func (l Location ) CellID () string {
129145 return l .ID
130146}
131147
148+ // PlaceID returns the place identifier string.
132149func (l Location ) PlaceID () string {
133150 return l .Place .PlaceID
134151}
135152
153+ // Name returns the location name if any.
136154func (l Location ) Name () (result string ) {
137155 return strings .SplitN (l .LocName , "/" , 2 )[0 ]
138156}
139157
158+ // Street returns the location street if any.
140159func (l Location ) Street () (result string ) {
141160 return strings .SplitN (l .LocStreet , "/" , 2 )[0 ]
142161}
143162
163+ // Postcode returns the location postcode if any.
144164func (l Location ) Postcode () (result string ) {
145165 return strings .SplitN (l .LocPostcode , "/" , 2 )[0 ]
146166}
147167
168+ // Category returns the location category if any.
148169func (l Location ) Category () (result string ) {
149170 return l .LocCategory
150171}
151172
173+ // Label returns the location label.
152174func (l Location ) Label () (result string ) {
153175 return l .Place .LocLabel
154176}
155177
178+ // City returns the location address city name.
156179func (l Location ) City () (result string ) {
157180 return l .Place .LocCity
158181}
159182
183+ // District returns the location address district name.
160184func (l Location ) District () (result string ) {
161185 return l .Place .LocDistrict
162186}
163187
188+ // CountryCode returns the location address country code.
164189func (l Location ) CountryCode () (result string ) {
165190 return l .Place .LocCountry
166191}
167192
193+ // State returns the location address state name.
168194func (l Location ) State () (result string ) {
169195 return txt .NormalizeState (l .Place .LocState , l .CountryCode ())
170196}
171197
198+ // Latitude returns the location position latitude.
172199func (l Location ) Latitude () (result float64 ) {
173200 return l .LocLat
174201}
175202
203+ // Longitude returns the location position longitude.
176204func (l Location ) Longitude () (result float64 ) {
177205 return l .LocLng
178206}
179207
208+ // Keywords returns location keywords if any.
180209func (l Location ) Keywords () (result []string ) {
181210 return txt .UniqueWords (txt .Words (l .Place .LocKeywords ))
182211}
183212
213+ // Source returns the backend API name.
184214func (l Location ) Source () string {
185215 return "places"
186216}
0 commit comments