geocoder 1.1.9 → 1.3.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +157 -0
- data/README.md +467 -70
- data/examples/reverse_geocode_job.rb +40 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +16 -16
- data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +28 -0
- data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +28 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +30 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
- data/lib/geocoder/cache.rb +3 -2
- data/lib/geocoder/calculations.rb +44 -2
- data/lib/geocoder/configuration.rb +17 -10
- data/lib/geocoder/esri_token.rb +38 -0
- data/lib/geocoder/exceptions.rb +19 -0
- data/lib/geocoder/ip_address.rb +13 -0
- data/lib/geocoder/kernel_logger.rb +25 -0
- data/lib/geocoder/logger.rb +47 -0
- data/lib/geocoder/lookup.rb +32 -8
- data/lib/geocoder/lookups/baidu.rb +18 -13
- data/lib/geocoder/lookups/baidu_ip.rb +59 -0
- data/lib/geocoder/lookups/base.rb +81 -19
- data/lib/geocoder/lookups/bing.rb +40 -7
- data/lib/geocoder/lookups/esri.rb +42 -5
- data/lib/geocoder/lookups/freegeoip.rb +9 -1
- data/lib/geocoder/lookups/geocoder_ca.rb +1 -2
- data/lib/geocoder/lookups/geocoder_us.rb +6 -2
- data/lib/geocoder/lookups/geocodio.rb +42 -0
- data/lib/geocoder/lookups/geoip2.rb +45 -0
- data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
- data/lib/geocoder/lookups/google.rb +29 -5
- data/lib/geocoder/lookups/google_places_details.rb +50 -0
- data/lib/geocoder/lookups/google_premier.rb +1 -1
- data/lib/geocoder/lookups/here.rb +62 -0
- data/lib/geocoder/lookups/ipapi_com.rb +86 -0
- data/lib/geocoder/lookups/ipinfo_io.rb +55 -0
- data/lib/geocoder/lookups/latlon.rb +59 -0
- data/lib/geocoder/lookups/mapbox.rb +53 -0
- data/lib/geocoder/lookups/mapquest.rb +6 -6
- data/lib/geocoder/lookups/mapzen.rb +15 -0
- data/lib/geocoder/lookups/maxmind.rb +4 -2
- data/lib/geocoder/lookups/maxmind_geoip2.rb +69 -0
- data/lib/geocoder/lookups/maxmind_local.rb +65 -0
- data/lib/geocoder/lookups/nominatim.rb +9 -1
- data/lib/geocoder/lookups/okf.rb +44 -0
- data/lib/geocoder/lookups/opencagedata.rb +58 -0
- data/lib/geocoder/lookups/pelias.rb +64 -0
- data/lib/geocoder/lookups/pointpin.rb +68 -0
- data/lib/geocoder/lookups/postcode_anywhere_uk.rb +51 -0
- data/lib/geocoder/lookups/smarty_streets.rb +53 -0
- data/lib/geocoder/lookups/telize.rb +55 -0
- data/lib/geocoder/lookups/yandex.rb +8 -4
- data/lib/geocoder/models/active_record.rb +7 -3
- data/lib/geocoder/models/base.rb +1 -4
- data/lib/geocoder/models/mongo_base.rb +6 -4
- data/lib/geocoder/query.rb +9 -5
- data/lib/geocoder/railtie.rb +1 -1
- data/lib/geocoder/request.rb +74 -12
- data/lib/geocoder/results/baidu_ip.rb +62 -0
- data/lib/geocoder/results/bing.rb +4 -0
- data/lib/geocoder/results/esri.rb +30 -6
- data/lib/geocoder/results/freegeoip.rb +2 -2
- data/lib/geocoder/results/geocodio.rb +70 -0
- data/lib/geocoder/results/geoip2.rb +62 -0
- data/lib/geocoder/results/geoportail_lu.rb +69 -0
- data/lib/geocoder/results/google.rb +15 -0
- data/lib/geocoder/results/google_places_details.rb +35 -0
- data/lib/geocoder/results/here.rb +71 -0
- data/lib/geocoder/results/ipapi_com.rb +45 -0
- data/lib/geocoder/results/ipinfo_io.rb +48 -0
- data/lib/geocoder/results/latlon.rb +71 -0
- data/lib/geocoder/results/mapbox.rb +47 -0
- data/lib/geocoder/results/mapquest.rb +5 -8
- data/lib/geocoder/results/mapzen.rb +5 -0
- data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
- data/lib/geocoder/results/maxmind_local.rb +49 -0
- data/lib/geocoder/results/nominatim.rb +6 -1
- data/lib/geocoder/results/okf.rb +106 -0
- data/lib/geocoder/results/opencagedata.rb +90 -0
- data/lib/geocoder/results/ovi.rb +9 -0
- data/lib/geocoder/results/pelias.rb +58 -0
- data/lib/geocoder/results/pointpin.rb +40 -0
- data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
- data/lib/geocoder/results/smarty_streets.rb +106 -0
- data/lib/geocoder/results/telize.rb +45 -0
- data/lib/geocoder/results/test.rb +20 -3
- data/lib/geocoder/results/yandex.rb +18 -6
- data/lib/geocoder/sql.rb +16 -15
- data/lib/geocoder/stores/active_record.rb +51 -18
- data/lib/geocoder/stores/base.rb +8 -12
- data/lib/geocoder/stores/mongo_base.rb +0 -31
- data/lib/geocoder/version.rb +1 -1
- data/lib/geocoder.rb +6 -13
- data/lib/maxmind_database.rb +109 -0
- data/lib/tasks/geocoder.rake +14 -3
- data/lib/tasks/maxmind.rake +73 -0
- metadata +59 -85
- data/.gitignore +0 -5
- data/.travis.yml +0 -27
- data/Rakefile +0 -25
- data/gemfiles/Gemfile.mongoid-2.4.x +0 -15
- data/lib/geocoder/lookups/yahoo.rb +0 -86
- data/lib/geocoder/results/yahoo.rb +0 -55
- data/lib/oauth_util.rb +0 -112
- data/test/active_record_test.rb +0 -15
- data/test/cache_test.rb +0 -35
- data/test/calculations_test.rb +0 -211
- data/test/configuration_test.rb +0 -78
- data/test/custom_block_test.rb +0 -32
- data/test/error_handling_test.rb +0 -43
- data/test/fixtures/baidu_invalid_key +0 -1
- data/test/fixtures/baidu_no_results +0 -1
- data/test/fixtures/baidu_reverse +0 -1
- data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
- data/test/fixtures/bing_invalid_key +0 -1
- data/test/fixtures/bing_madison_square_garden +0 -40
- data/test/fixtures/bing_no_results +0 -16
- data/test/fixtures/bing_reverse +0 -42
- data/test/fixtures/esri_madison_square_garden +0 -59
- data/test/fixtures/esri_no_results +0 -8
- data/test/fixtures/esri_reverse +0 -21
- data/test/fixtures/freegeoip_74_200_247_59 +0 -12
- data/test/fixtures/freegeoip_no_results +0 -1
- data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
- data/test/fixtures/geocoder_ca_no_results +0 -1
- data/test/fixtures/geocoder_ca_reverse +0 -34
- data/test/fixtures/geocoder_us_madison_square_garden +0 -1
- data/test/fixtures/geocoder_us_no_results +0 -1
- data/test/fixtures/google_garbage +0 -456
- data/test/fixtures/google_madison_square_garden +0 -57
- data/test/fixtures/google_no_city_data +0 -44
- data/test/fixtures/google_no_locality +0 -51
- data/test/fixtures/google_no_results +0 -4
- data/test/fixtures/google_over_limit +0 -4
- data/test/fixtures/mapquest_error +0 -16
- data/test/fixtures/mapquest_invalid_api_key +0 -16
- data/test/fixtures/mapquest_invalid_request +0 -16
- data/test/fixtures/mapquest_madison_square_garden +0 -52
- data/test/fixtures/mapquest_no_results +0 -16
- data/test/fixtures/maxmind_24_24_24_21 +0 -1
- data/test/fixtures/maxmind_24_24_24_22 +0 -1
- data/test/fixtures/maxmind_24_24_24_23 +0 -1
- data/test/fixtures/maxmind_24_24_24_24 +0 -1
- data/test/fixtures/maxmind_74_200_247_59 +0 -1
- data/test/fixtures/maxmind_invalid_key +0 -1
- data/test/fixtures/maxmind_no_results +0 -1
- data/test/fixtures/nominatim_madison_square_garden +0 -150
- data/test/fixtures/nominatim_no_results +0 -1
- data/test/fixtures/ovi_madison_square_garden +0 -72
- data/test/fixtures/ovi_no_results +0 -8
- data/test/fixtures/yahoo_error +0 -1
- data/test/fixtures/yahoo_invalid_key +0 -2
- data/test/fixtures/yahoo_madison_square_garden +0 -52
- data/test/fixtures/yahoo_no_results +0 -10
- data/test/fixtures/yahoo_over_limit +0 -2
- data/test/fixtures/yandex_invalid_key +0 -1
- data/test/fixtures/yandex_kremlin +0 -48
- data/test/fixtures/yandex_no_city_and_town +0 -112
- data/test/fixtures/yandex_no_results +0 -16
- data/test/geocoder_test.rb +0 -59
- data/test/https_test.rb +0 -16
- data/test/integration/smoke_test.rb +0 -26
- data/test/lookup_test.rb +0 -117
- data/test/method_aliases_test.rb +0 -25
- data/test/mongoid_test.rb +0 -46
- data/test/mongoid_test_helper.rb +0 -43
- data/test/near_test.rb +0 -61
- data/test/oauth_util_test.rb +0 -30
- data/test/proxy_test.rb +0 -36
- data/test/query_test.rb +0 -52
- data/test/request_test.rb +0 -29
- data/test/result_test.rb +0 -42
- data/test/services_test.rb +0 -393
- data/test/test_helper.rb +0 -289
- data/test/test_mode_test.rb +0 -59
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/baidu_ip'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class BaiduIp < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Baidu IP"
|
9
|
+
end
|
10
|
+
|
11
|
+
def required_api_key_parts
|
12
|
+
["key"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def query_url(query)
|
16
|
+
"#{protocol}://api.map.baidu.com/location/ip?" + url_query_string(query)
|
17
|
+
end
|
18
|
+
|
19
|
+
# HTTP only
|
20
|
+
def supported_protocols
|
21
|
+
[:http]
|
22
|
+
end
|
23
|
+
|
24
|
+
private # ---------------------------------------------------------------
|
25
|
+
|
26
|
+
def results(query, reverse = false)
|
27
|
+
return [] unless doc = fetch_data(query)
|
28
|
+
case doc['status']
|
29
|
+
when 0
|
30
|
+
return [doc['content']] unless doc['content'].blank?
|
31
|
+
when 1, 3, 4
|
32
|
+
raise_error(Geocoder::Error, "server error.") ||
|
33
|
+
Geocoder.log(:warn, "Baidu IP Geocoding API error: server error.")
|
34
|
+
when 2
|
35
|
+
raise_error(Geocoder::InvalidRequest, "invalid request.") ||
|
36
|
+
Geocoder.log(:warn, "Baidu IP Geocoding API error: invalid request.")
|
37
|
+
when 5
|
38
|
+
raise_error(Geocoder::InvalidApiKey, "invalid api key.") ||
|
39
|
+
Geocoder.log(:warn, "Baidu IP Geocoding API error: invalid api key.")
|
40
|
+
when 101, 102, 200..299
|
41
|
+
raise_error(Geocoder::RequestDenied, "request denied.") ||
|
42
|
+
Geocoder.log(:warn, "Baidu IP Geocoding API error: request denied.")
|
43
|
+
when 300..399
|
44
|
+
raise_error(Geocoder::OverQueryLimitError, "over query limit") ||
|
45
|
+
Geocoder.log(:warn, "Baidu IP Geocoding API error: over query limit.")
|
46
|
+
end
|
47
|
+
return []
|
48
|
+
end
|
49
|
+
|
50
|
+
def query_url_params(query)
|
51
|
+
{
|
52
|
+
:ip => query.sanitized_text,
|
53
|
+
:ak => configuration.api_key,
|
54
|
+
:coor => "bd09ll"
|
55
|
+
}.merge(super)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -15,6 +15,9 @@ module Geocoder
|
|
15
15
|
module Lookup
|
16
16
|
|
17
17
|
class Base
|
18
|
+
def initialize
|
19
|
+
@cache = nil
|
20
|
+
end
|
18
21
|
|
19
22
|
##
|
20
23
|
# Human-readable name of the geocoding API.
|
@@ -83,6 +86,15 @@ module Geocoder
|
|
83
86
|
@cache
|
84
87
|
end
|
85
88
|
|
89
|
+
##
|
90
|
+
# Array containing the protocols supported by the api.
|
91
|
+
# Should be set to [:http] if only HTTP is supported
|
92
|
+
# or [:https] if only HTTPS is supported.
|
93
|
+
#
|
94
|
+
def supported_protocols
|
95
|
+
[:http, :https]
|
96
|
+
end
|
97
|
+
|
86
98
|
private # -------------------------------------------------------------
|
87
99
|
|
88
100
|
##
|
@@ -96,7 +108,6 @@ module Geocoder
|
|
96
108
|
# Object used to make HTTP requests.
|
97
109
|
#
|
98
110
|
def http_client
|
99
|
-
protocol = "http#{'s' if configuration.use_https}"
|
100
111
|
proxy_name = "#{protocol}_proxy"
|
101
112
|
if proxy = configuration.send(proxy_name)
|
102
113
|
proxy_url = !!(proxy =~ /^#{protocol}/) ? proxy : protocol + '://' + proxy
|
@@ -165,10 +176,12 @@ module Geocoder
|
|
165
176
|
def fetch_data(query)
|
166
177
|
parse_raw_data fetch_raw_data(query)
|
167
178
|
rescue SocketError => err
|
168
|
-
raise_error(err) or warn "Geocoding API connection cannot be established."
|
169
|
-
rescue
|
170
|
-
raise_error(err) or warn "Geocoding API
|
171
|
-
|
179
|
+
raise_error(err) or Geocoder.log(:warn, "Geocoding API connection cannot be established.")
|
180
|
+
rescue Errno::ECONNREFUSED => err
|
181
|
+
raise_error(err) or Geocoder.log(:warn, "Geocoding API connection refused.")
|
182
|
+
rescue Timeout::Error => err
|
183
|
+
raise_error(err) or Geocoder.log(:warn, "Geocoding API not responding fast enough " +
|
184
|
+
"(use Geocoder.configure(:timeout => ...) to set limit).")
|
172
185
|
end
|
173
186
|
|
174
187
|
def parse_json(data)
|
@@ -177,6 +190,8 @@ module Geocoder
|
|
177
190
|
else
|
178
191
|
JSON.parse(data)
|
179
192
|
end
|
193
|
+
rescue
|
194
|
+
raise_error(ResponseParseError.new(data)) or Geocoder.log(:warn, "Geocoding API's response was not valid JSON: #{data}")
|
180
195
|
end
|
181
196
|
|
182
197
|
##
|
@@ -184,8 +199,6 @@ module Geocoder
|
|
184
199
|
#
|
185
200
|
def parse_raw_data(raw_data)
|
186
201
|
parse_json(raw_data)
|
187
|
-
rescue
|
188
|
-
warn "Geocoding API's response was not valid JSON."
|
189
202
|
end
|
190
203
|
|
191
204
|
##
|
@@ -193,7 +206,7 @@ module Geocoder
|
|
193
206
|
# Set in configuration but not available for every service.
|
194
207
|
#
|
195
208
|
def protocol
|
196
|
-
"http" + (
|
209
|
+
"http" + (use_ssl? ? "s" : "")
|
197
210
|
end
|
198
211
|
|
199
212
|
def valid_response?(response)
|
@@ -211,7 +224,21 @@ module Geocoder
|
|
211
224
|
else
|
212
225
|
check_api_key_configuration!(query)
|
213
226
|
response = make_api_request(query)
|
227
|
+
check_response_for_errors!(response)
|
214
228
|
body = response.body
|
229
|
+
|
230
|
+
# apply the charset from the Content-Type header, if possible
|
231
|
+
ct = response['content-type']
|
232
|
+
|
233
|
+
if ct && ct['charset']
|
234
|
+
charset = ct.split(';').select do |s|
|
235
|
+
s['charset']
|
236
|
+
end.first.to_s.split('=')
|
237
|
+
if charset.length == 2
|
238
|
+
body.force_encoding(charset.last) rescue ArgumentError
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
215
242
|
if cache and valid_response?(response)
|
216
243
|
cache[key] = body
|
217
244
|
end
|
@@ -220,26 +247,61 @@ module Geocoder
|
|
220
247
|
body
|
221
248
|
end
|
222
249
|
|
250
|
+
def check_response_for_errors!(response)
|
251
|
+
if response.code.to_i == 400
|
252
|
+
raise_error(Geocoder::InvalidRequest) ||
|
253
|
+
Geocoder.log(:warn, "Geocoding API error: 400 Bad Request")
|
254
|
+
elsif response.code.to_i == 401
|
255
|
+
raise_error(Geocoder::RequestDenied) ||
|
256
|
+
Geocoder.log(:warn, "Geocoding API error: 401 Unauthorized")
|
257
|
+
elsif response.code.to_i == 402
|
258
|
+
raise_error(Geocoder::OverQueryLimitError) ||
|
259
|
+
Geocoder.log(:warn, "Geocoding API error: 402 Payment Required")
|
260
|
+
elsif response.code.to_i == 429
|
261
|
+
raise_error(Geocoder::OverQueryLimitError) ||
|
262
|
+
Geocoder.log(:warn, "Geocoding API error: 429 Too Many Requests")
|
263
|
+
elsif response.code.to_i == 503
|
264
|
+
raise_error(Geocoder::ServiceUnavailable) ||
|
265
|
+
Geocoder.log(:warn, "Geocoding API error: 503 Service Unavailable")
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
223
269
|
##
|
224
270
|
# Make an HTTP(S) request to a geocoding API and
|
225
271
|
# return the response object.
|
226
272
|
#
|
227
273
|
def make_api_request(query)
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
client.request(req)
|
274
|
+
uri = URI.parse(query_url(query))
|
275
|
+
Geocoder.log(:debug, "Geocoder: HTTP request being made for #{uri.to_s}")
|
276
|
+
http_client.start(uri.host, uri.port, use_ssl: use_ssl?, open_timeout: configuration.timeout, read_timeout: configuration.timeout) do |client|
|
277
|
+
configure_ssl!(client) if use_ssl?
|
278
|
+
req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
|
279
|
+
if configuration.basic_auth[:user] and configuration.basic_auth[:password]
|
280
|
+
req.basic_auth(
|
281
|
+
configuration.basic_auth[:user],
|
282
|
+
configuration.basic_auth[:password]
|
283
|
+
)
|
239
284
|
end
|
285
|
+
client.request(req)
|
286
|
+
end
|
287
|
+
rescue Timeout::Error
|
288
|
+
raise Geocoder::LookupTimeout
|
289
|
+
rescue Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ENETUNREACH
|
290
|
+
raise Geocoder::NetworkError
|
291
|
+
end
|
292
|
+
|
293
|
+
def use_ssl?
|
294
|
+
if supported_protocols == [:https]
|
295
|
+
true
|
296
|
+
elsif supported_protocols == [:http]
|
297
|
+
false
|
298
|
+
else
|
299
|
+
configuration.use_https
|
240
300
|
end
|
241
301
|
end
|
242
302
|
|
303
|
+
def configure_ssl!(client); end
|
304
|
+
|
243
305
|
def check_api_key_configuration!(query)
|
244
306
|
key_parts = query.lookup.required_api_key_parts
|
245
307
|
if key_parts.size > Array(configuration.api_key).size
|
@@ -17,31 +17,64 @@ module Geocoder::Lookup
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def query_url(query)
|
20
|
-
|
21
|
-
(query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?") +
|
22
|
-
url_query_string(query)
|
20
|
+
base_url(query) + url_query_string(query)
|
23
21
|
end
|
24
22
|
|
25
23
|
private # ---------------------------------------------------------------
|
26
24
|
|
25
|
+
def base_url(query)
|
26
|
+
url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations"
|
27
|
+
|
28
|
+
if !query.reverse_geocode?
|
29
|
+
if r = query.options[:region]
|
30
|
+
url << "/#{r}"
|
31
|
+
end
|
32
|
+
# use the more forgiving 'unstructured' query format to allow special
|
33
|
+
# chars, newlines, brackets, typos.
|
34
|
+
url + "?q=" + URI.escape(query.sanitized_text.strip) + "&"
|
35
|
+
else
|
36
|
+
url + "/#{URI.escape(query.sanitized_text.strip)}?"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
27
40
|
def results(query)
|
28
41
|
return [] unless doc = fetch_data(query)
|
29
42
|
|
30
43
|
if doc['statusCode'] == 200
|
31
44
|
return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : []
|
32
45
|
elsif doc['statusCode'] == 401 and doc["authenticationResultCode"] == "InvalidCredentials"
|
33
|
-
raise_error(Geocoder::InvalidApiKey) || warn
|
46
|
+
raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid Bing API key.")
|
34
47
|
else
|
35
|
-
warn "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']})."
|
48
|
+
Geocoder.log(:warn, "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']}).")
|
36
49
|
end
|
37
50
|
return []
|
38
51
|
end
|
39
52
|
|
40
53
|
def query_url_params(query)
|
41
54
|
{
|
42
|
-
:
|
43
|
-
:query => query.reverse_geocode? ? nil : query.sanitized_text
|
55
|
+
key: configuration.api_key
|
44
56
|
}.merge(super)
|
45
57
|
end
|
58
|
+
|
59
|
+
def check_response_for_errors!(response)
|
60
|
+
super
|
61
|
+
if server_overloaded?(response)
|
62
|
+
raise_error(Geocoder::ServiceUnavailable) ||
|
63
|
+
Geocoder.log(:warn, "Bing Geocoding API error: Service Unavailable")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def valid_response?(response)
|
68
|
+
super(response) and not server_overloaded?(response)
|
69
|
+
end
|
70
|
+
|
71
|
+
def server_overloaded?(response)
|
72
|
+
# Occasionally, the servers processing service requests can be overloaded,
|
73
|
+
# and you may receive some responses that contain no results for queries that
|
74
|
+
# you would normally receive a result. To identify this situation,
|
75
|
+
# check the HTTP headers of the response. If the HTTP header X-MS-BM-WS-INFO is set to 1,
|
76
|
+
# it is best to wait a few seconds and try again.
|
77
|
+
response['x-ms-bm-ws-info'].to_i == 1
|
78
|
+
end
|
46
79
|
end
|
47
80
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'geocoder/lookups/base'
|
2
2
|
require "geocoder/results/esri"
|
3
|
+
require 'geocoder/esri_token'
|
3
4
|
|
4
5
|
module Geocoder::Lookup
|
5
6
|
class Esri < Base
|
@@ -9,19 +10,21 @@ module Geocoder::Lookup
|
|
9
10
|
end
|
10
11
|
|
11
12
|
def query_url(query)
|
12
|
-
|
13
|
-
|
14
|
-
"#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{search_keyword}?" +
|
15
|
-
url_query_string(query)
|
13
|
+
base_query_url(query) + url_query_string(query)
|
16
14
|
end
|
17
15
|
|
18
16
|
private # ---------------------------------------------------------------
|
19
17
|
|
18
|
+
def base_query_url(query)
|
19
|
+
action = query.reverse_geocode? ? "reverseGeocode" : "find"
|
20
|
+
"#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{action}?"
|
21
|
+
end
|
22
|
+
|
20
23
|
def results(query)
|
21
24
|
return [] unless doc = fetch_data(query)
|
22
25
|
|
23
26
|
if (!query.reverse_geocode?)
|
24
|
-
return [] if doc['locations'].empty?
|
27
|
+
return [] if !doc['locations'] || doc['locations'].empty?
|
25
28
|
end
|
26
29
|
|
27
30
|
if (doc['error'].nil?)
|
@@ -31,6 +34,17 @@ module Geocoder::Lookup
|
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
37
|
+
def cache_key(query)
|
38
|
+
base_query_url(query) + hash_to_query(cache_key_params(query))
|
39
|
+
end
|
40
|
+
|
41
|
+
def cache_key_params(query)
|
42
|
+
# omit api_key and token because they may vary among requests
|
43
|
+
query_url_params(query).reject do |key,value|
|
44
|
+
[:api_key, :token].include?(key)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
34
48
|
def query_url_params(query)
|
35
49
|
params = {
|
36
50
|
:f => "pjson",
|
@@ -41,8 +55,31 @@ module Geocoder::Lookup
|
|
41
55
|
else
|
42
56
|
params[:text] = query.sanitized_text
|
43
57
|
end
|
58
|
+
params[:token] = token
|
59
|
+
params[:forStorage] = configuration[:for_storage] if configuration[:for_storage]
|
60
|
+
params[:sourceCountry] = configuration[:source_country] if configuration[:source_country]
|
44
61
|
params.merge(super)
|
45
62
|
end
|
46
63
|
|
64
|
+
def token
|
65
|
+
create_and_save_token! if !valid_token_configured? and configuration.api_key
|
66
|
+
configuration[:token].to_s unless configuration[:token].nil?
|
67
|
+
end
|
68
|
+
|
69
|
+
def valid_token_configured?
|
70
|
+
!configuration[:token].nil? and configuration[:token].active?
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_and_save_token!
|
74
|
+
save_token!(create_token)
|
75
|
+
end
|
76
|
+
|
77
|
+
def create_token
|
78
|
+
Geocoder::EsriToken.generate_token(*configuration.api_key)
|
79
|
+
end
|
80
|
+
|
81
|
+
def save_token!(token_instance)
|
82
|
+
Geocoder.merge_into_lookup_config(:esri, token: token_instance)
|
83
|
+
end
|
47
84
|
end
|
48
85
|
end
|
@@ -7,9 +7,13 @@ module Geocoder::Lookup
|
|
7
7
|
def name
|
8
8
|
"FreeGeoIP"
|
9
9
|
end
|
10
|
+
|
11
|
+
def supported_protocols
|
12
|
+
[:http]
|
13
|
+
end
|
10
14
|
|
11
15
|
def query_url(query)
|
12
|
-
"#{protocol}
|
16
|
+
"#{protocol}://#{host}/json/#{query.sanitized_text}"
|
13
17
|
end
|
14
18
|
|
15
19
|
private # ---------------------------------------------------------------
|
@@ -39,5 +43,9 @@ module Geocoder::Lookup
|
|
39
43
|
"country_code" => "RD"
|
40
44
|
}
|
41
45
|
end
|
46
|
+
|
47
|
+
def host
|
48
|
+
configuration[:host] || "freegeoip.io"
|
49
|
+
end
|
42
50
|
end
|
43
51
|
end
|
@@ -21,7 +21,7 @@ module Geocoder::Lookup
|
|
21
21
|
elsif doc['error']['code'] == "005"
|
22
22
|
# "Postal Code is not in the proper Format" => no results, just shut up
|
23
23
|
else
|
24
|
-
warn "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']})."
|
24
|
+
Geocoder.log(:warn, "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']}).")
|
25
25
|
end
|
26
26
|
return []
|
27
27
|
end
|
@@ -51,4 +51,3 @@ module Geocoder::Lookup
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
@@ -8,11 +8,15 @@ module Geocoder::Lookup
|
|
8
8
|
"Geocoder.us"
|
9
9
|
end
|
10
10
|
|
11
|
+
def supported_protocols
|
12
|
+
[:http]
|
13
|
+
end
|
14
|
+
|
11
15
|
def query_url(query)
|
12
16
|
if configuration.api_key
|
13
|
-
"
|
17
|
+
"#{protocol}://#{configuration.api_key}@geocoder.us/member/service/csv/geocode?" + url_query_string(query)
|
14
18
|
else
|
15
|
-
"
|
19
|
+
"#{protocol}://geocoder.us/service/csv/geocode?" + url_query_string(query)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require "geocoder/results/geocodio"
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Geocodio < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Geocodio"
|
9
|
+
end
|
10
|
+
|
11
|
+
def query_url(query)
|
12
|
+
path = query.reverse_geocode? ? "reverse" : "geocode"
|
13
|
+
"#{protocol}://api.geocod.io/v1/#{path}?#{url_query_string(query)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def results(query)
|
17
|
+
return [] unless doc = fetch_data(query)
|
18
|
+
return doc["results"] if doc['error'].nil?
|
19
|
+
|
20
|
+
if doc['error'] == 'Invalid API key'
|
21
|
+
raise_error(Geocoder::InvalidApiKey) ||
|
22
|
+
Geocoder.log(:warn, "Geocodio service error: invalid API key.")
|
23
|
+
elsif doc['error'].match(/You have reached your daily maximum/)
|
24
|
+
raise_error(Geocoder::OverQueryLimitError, doc['error']) ||
|
25
|
+
Geocoder.log(:warn, "Geocodio service error: #{doc['error']}.")
|
26
|
+
else
|
27
|
+
raise_error(Geocoder::InvalidRequest, doc['error']) ||
|
28
|
+
Geocoder.log(:warn, "Geocodio service error: #{doc['error']}.")
|
29
|
+
end
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
private # ---------------------------------------------------------------
|
34
|
+
|
35
|
+
def query_url_params(query)
|
36
|
+
{
|
37
|
+
:api_key => configuration.api_key,
|
38
|
+
:q => query.sanitized_text
|
39
|
+
}.merge(super)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/geoip2'
|
3
|
+
|
4
|
+
module Geocoder
|
5
|
+
module Lookup
|
6
|
+
class Geoip2 < Base
|
7
|
+
attr_reader :gem_name
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
unless configuration[:file].nil?
|
11
|
+
begin
|
12
|
+
@gem_name = configuration[:lib] || 'maxminddb'
|
13
|
+
require @gem_name
|
14
|
+
rescue LoadError
|
15
|
+
raise "Could not load Maxmind DB dependency. To use the GeoIP2 lookup you must add the #{@gem_name} gem to your Gemfile or have it installed in your system."
|
16
|
+
end
|
17
|
+
|
18
|
+
@mmdb = db_class.new(configuration[:file].to_s)
|
19
|
+
end
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def name
|
24
|
+
'GeoIP2'
|
25
|
+
end
|
26
|
+
|
27
|
+
def required_api_key_parts
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def db_class
|
34
|
+
gem_name == 'hive_geoip2' ? Hive::GeoIP2 : MaxMindDB
|
35
|
+
end
|
36
|
+
|
37
|
+
def results(query)
|
38
|
+
return [] unless configuration[:file]
|
39
|
+
|
40
|
+
result = @mmdb.lookup(query.to_s)
|
41
|
+
result.nil? ? [] : [result]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require "geocoder/results/geoportail_lu"
|
3
|
+
|
4
|
+
module Geocoder
|
5
|
+
module Lookup
|
6
|
+
class GeoportailLu < Base
|
7
|
+
|
8
|
+
def name
|
9
|
+
"Geoportail.lu"
|
10
|
+
end
|
11
|
+
|
12
|
+
def query_url(query)
|
13
|
+
url_base_path(query) + url_query_string(query)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def url_base_path(query)
|
19
|
+
query.reverse_geocode? ? reverse_geocode_url_base_path : search_url_base_path
|
20
|
+
end
|
21
|
+
|
22
|
+
def search_url_base_path
|
23
|
+
"#{protocol}://api.geoportail.lu/geocoder/search?"
|
24
|
+
end
|
25
|
+
|
26
|
+
def reverse_geocode_url_base_path
|
27
|
+
"#{protocol}://api.geoportail.lu/geocoder/reverseGeocode?"
|
28
|
+
end
|
29
|
+
|
30
|
+
def query_url_geoportail_lu_params(query)
|
31
|
+
query.reverse_geocode? ? reverse_geocode_params(query) : search_params(query)
|
32
|
+
end
|
33
|
+
|
34
|
+
def search_params(query)
|
35
|
+
{
|
36
|
+
queryString: query.sanitized_text
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def reverse_geocode_params(query)
|
41
|
+
lat_lon = query.coordinates
|
42
|
+
{
|
43
|
+
lat: lat_lon.first,
|
44
|
+
lon: lat_lon.last
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def query_url_params(query)
|
49
|
+
query_url_geoportail_lu_params(query).merge(super)
|
50
|
+
end
|
51
|
+
|
52
|
+
def results(query)
|
53
|
+
return [] unless doc = fetch_data(query)
|
54
|
+
if doc['success'] == true
|
55
|
+
result = doc['results']
|
56
|
+
else
|
57
|
+
result = []
|
58
|
+
raise_error(Geocoder::Error) ||
|
59
|
+
warn("Geportail.lu Geocoding API error")
|
60
|
+
end
|
61
|
+
result
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -12,14 +12,35 @@ module Geocoder::Lookup
|
|
12
12
|
"http://maps.google.com/maps?q=#{coordinates.join(',')}"
|
13
13
|
end
|
14
14
|
|
15
|
+
def supported_protocols
|
16
|
+
# Google requires HTTPS if an API key is used.
|
17
|
+
if configuration.api_key
|
18
|
+
[:https]
|
19
|
+
else
|
20
|
+
[:http, :https]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
def query_url(query)
|
16
25
|
"#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
|
17
26
|
end
|
18
27
|
|
19
28
|
private # ---------------------------------------------------------------
|
20
29
|
|
30
|
+
def configure_ssl!(client)
|
31
|
+
client.instance_eval {
|
32
|
+
@ssl_context = OpenSSL::SSL::SSLContext.new
|
33
|
+
options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
|
34
|
+
if OpenSSL::SSL.const_defined?('OP_NO_COMPRESSION')
|
35
|
+
options |= OpenSSL::SSL::OP_NO_COMPRESSION
|
36
|
+
end
|
37
|
+
@ssl_context.set_params({options: options})
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
21
41
|
def valid_response?(response)
|
22
|
-
|
42
|
+
json = parse_json(response.body)
|
43
|
+
status = json["status"] if json
|
23
44
|
super(response) and ['OK', 'ZERO_RESULTS'].include?(status)
|
24
45
|
end
|
25
46
|
|
@@ -29,13 +50,13 @@ module Geocoder::Lookup
|
|
29
50
|
return doc['results']
|
30
51
|
when "OVER_QUERY_LIMIT"
|
31
52
|
raise_error(Geocoder::OverQueryLimitError) ||
|
32
|
-
warn
|
53
|
+
Geocoder.log(:warn, "Google Geocoding API error: over query limit.")
|
33
54
|
when "REQUEST_DENIED"
|
34
55
|
raise_error(Geocoder::RequestDenied) ||
|
35
|
-
warn
|
56
|
+
Geocoder.log(:warn, "Google Geocoding API error: request denied.")
|
36
57
|
when "INVALID_REQUEST"
|
37
58
|
raise_error(Geocoder::InvalidRequest) ||
|
38
|
-
warn
|
59
|
+
Geocoder.log(:warn, "Google Geocoding API error: invalid request.")
|
39
60
|
end
|
40
61
|
return []
|
41
62
|
end
|
@@ -44,7 +65,7 @@ module Geocoder::Lookup
|
|
44
65
|
params = {
|
45
66
|
(query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
|
46
67
|
:sensor => "false",
|
47
|
-
:language => configuration.language
|
68
|
+
:language => (query.language || configuration.language)
|
48
69
|
}
|
49
70
|
unless (bounds = query.options[:bounds]).nil?
|
50
71
|
params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
|
@@ -55,6 +76,9 @@ module Geocoder::Lookup
|
|
55
76
|
unless (components = query.options[:components]).nil?
|
56
77
|
params[:components] = components.is_a?(Array) ? components.join("|") : components
|
57
78
|
end
|
79
|
+
unless (result_type = query.options[:result_type]).nil?
|
80
|
+
params[:result_type] = result_type.is_a?(Array) ? result_type.join("|") : result_type
|
81
|
+
end
|
58
82
|
params
|
59
83
|
end
|
60
84
|
|