geocoder 1.6.6 → 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +68 -2
- data/README.md +355 -211
- data/examples/app_defined_lookup_services.rb +22 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +6 -1
- data/lib/geocoder/cache.rb +14 -35
- data/lib/geocoder/cache_stores/base.rb +40 -0
- data/lib/geocoder/cache_stores/generic.rb +35 -0
- data/lib/geocoder/cache_stores/redis.rb +34 -0
- data/lib/geocoder/configuration.rb +17 -4
- data/lib/geocoder/ip_address.rb +9 -0
- data/lib/geocoder/lookup.rb +37 -5
- data/lib/geocoder/lookups/abstract_api.rb +46 -0
- data/lib/geocoder/lookups/amap.rb +2 -2
- data/lib/geocoder/lookups/amazon_location_service.rb +58 -0
- data/lib/geocoder/lookups/azure.rb +56 -0
- data/lib/geocoder/lookups/ban_data_gouv_fr.rb +1 -1
- data/lib/geocoder/lookups/base.rb +2 -1
- data/lib/geocoder/lookups/bing.rb +2 -2
- data/lib/geocoder/lookups/esri.rb +18 -5
- data/lib/geocoder/lookups/freegeoip.rb +8 -6
- data/lib/geocoder/lookups/geoapify.rb +78 -0
- data/lib/geocoder/lookups/geoip2.rb +4 -0
- data/lib/geocoder/lookups/geoportail_lu.rb +1 -1
- data/lib/geocoder/lookups/google_places_details.rb +20 -0
- data/lib/geocoder/lookups/google_places_search.rb +21 -5
- data/lib/geocoder/lookups/here.rb +25 -20
- data/lib/geocoder/lookups/ip2location.rb +10 -6
- data/lib/geocoder/lookups/ip2location_io.rb +62 -0
- data/lib/geocoder/lookups/ip2location_lite.rb +40 -0
- data/lib/geocoder/lookups/ipbase.rb +49 -0
- data/lib/geocoder/lookups/ipdata_co.rb +1 -1
- data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
- data/lib/geocoder/lookups/location_iq.rb +5 -1
- data/lib/geocoder/lookups/mapbox.rb +3 -3
- data/lib/geocoder/lookups/melissa_street.rb +41 -0
- data/lib/geocoder/lookups/pc_miler.rb +85 -0
- data/lib/geocoder/lookups/pdok_nl.rb +43 -0
- data/lib/geocoder/lookups/photon.rb +89 -0
- data/lib/geocoder/lookups/test.rb +1 -0
- data/lib/geocoder/lookups/twogis.rb +58 -0
- data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +1 -1
- data/lib/geocoder/lookups/yandex.rb +3 -3
- data/lib/geocoder/query.rb +1 -1
- data/lib/geocoder/results/abstract_api.rb +146 -0
- data/lib/geocoder/results/amazon_location_service.rb +62 -0
- data/lib/geocoder/results/azure.rb +65 -0
- data/lib/geocoder/results/ban_data_gouv_fr.rb +1 -1
- data/lib/geocoder/results/esri.rb +5 -2
- data/lib/geocoder/results/geoapify.rb +179 -0
- data/lib/geocoder/results/here.rb +20 -25
- data/lib/geocoder/results/ip2location_io.rb +21 -0
- data/lib/geocoder/results/ip2location_lite.rb +47 -0
- data/lib/geocoder/results/ipbase.rb +40 -0
- data/lib/geocoder/results/ipqualityscore.rb +54 -0
- data/lib/geocoder/results/mapbox.rb +34 -10
- data/lib/geocoder/results/melissa_street.rb +46 -0
- data/lib/geocoder/results/nominatim.rb +24 -16
- data/lib/geocoder/results/pc_miler.rb +98 -0
- data/lib/geocoder/results/pdok_nl.rb +62 -0
- data/lib/geocoder/results/photon.rb +119 -0
- data/lib/geocoder/results/twogis.rb +76 -0
- data/lib/geocoder/version.rb +1 -1
- data/lib/maxmind_database.rb +12 -12
- data/lib/tasks/maxmind.rake +1 -1
- metadata +65 -11
- data/examples/autoexpire_cache_dalli.rb +0 -62
- data/examples/autoexpire_cache_redis.rb +0 -30
- data/lib/geocoder/lookups/dstk.rb +0 -22
- data/lib/geocoder/results/dstk.rb +0 -6
@@ -0,0 +1,22 @@
|
|
1
|
+
# To extend the Geocoder with additional lookups that come from the application,
|
2
|
+
# not shipped with the gem, define a "child" lookup in your application, based on existing one.
|
3
|
+
# This is required because the Geocoder::Configuration is a Singleton and stores one api key per lookup.
|
4
|
+
|
5
|
+
# in app/libs/geocoder/lookup/my_preciousss.rb
|
6
|
+
module Geocoder::Lookup
|
7
|
+
class MyPreciousss < Google
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Update Geocoder's street_services on initialize:
|
12
|
+
# config/initializers/geocoder.rb
|
13
|
+
Geocoder::Lookup.street_services << :my_preciousss
|
14
|
+
|
15
|
+
# Override the configuration when necessary (e.g. provide separate Google API key for the account):
|
16
|
+
Geocoder.configure(my_preciousss: { api_key: 'abcdef' })
|
17
|
+
|
18
|
+
# Lastly, search using your custom lookup service/api keys
|
19
|
+
Geocoder.search("Paris", lookup: :my_preciousss)
|
20
|
+
|
21
|
+
# This is useful when we have groups of users in the application who use Google paid services
|
22
|
+
# and we want to properly separate them and allow using individual API KEYS or timeouts.
|
@@ -9,7 +9,6 @@ Geocoder.configure(
|
|
9
9
|
# https_proxy: nil, # HTTPS proxy server (user:pass@host:port)
|
10
10
|
# api_key: nil, # API key for geocoding service
|
11
11
|
# cache: nil, # cache object (must respond to #[], #[]=, and #del)
|
12
|
-
# cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys
|
13
12
|
|
14
13
|
# Exceptions that should not be rescued by default
|
15
14
|
# (if you want to implement custom error handling);
|
@@ -19,4 +18,10 @@ Geocoder.configure(
|
|
19
18
|
# Calculation options
|
20
19
|
# units: :mi, # :km for kilometers or :mi for miles
|
21
20
|
# distances: :linear # :spherical or :linear
|
21
|
+
|
22
|
+
# Cache configuration
|
23
|
+
# cache_options: {
|
24
|
+
# expiration: 2.days,
|
25
|
+
# prefix: 'geocoder:'
|
26
|
+
# }
|
22
27
|
)
|
data/lib/geocoder/cache.rb
CHANGED
@@ -1,41 +1,29 @@
|
|
1
|
+
Dir["#{__dir__}/cache_stores/*.rb"].each {|file| require file }
|
2
|
+
|
1
3
|
module Geocoder
|
2
4
|
class Cache
|
3
5
|
|
4
|
-
def initialize(store,
|
5
|
-
@
|
6
|
-
@
|
6
|
+
def initialize(store, config)
|
7
|
+
@class = (Geocoder::CacheStore.const_get("#{store.class}", false) rescue Geocoder::CacheStore::Generic)
|
8
|
+
@store_service = @class.new(store, config)
|
7
9
|
end
|
8
10
|
|
9
11
|
##
|
10
12
|
# Read from the Cache.
|
11
13
|
#
|
12
14
|
def [](url)
|
13
|
-
interpret
|
14
|
-
when store.respond_to?(:[])
|
15
|
-
store[key_for(url)]
|
16
|
-
when store.respond_to?(:get)
|
17
|
-
store.get key_for(url)
|
18
|
-
when store.respond_to?(:read)
|
19
|
-
store.read key_for(url)
|
20
|
-
end
|
15
|
+
interpret store_service.read(url)
|
21
16
|
rescue => e
|
22
|
-
warn "Geocoder cache read error: #{e}"
|
17
|
+
Geocoder.log(:warn, "Geocoder cache read error: #{e}")
|
23
18
|
end
|
24
19
|
|
25
20
|
##
|
26
21
|
# Write to the Cache.
|
27
22
|
#
|
28
23
|
def []=(url, value)
|
29
|
-
|
30
|
-
when store.respond_to?(:[]=)
|
31
|
-
store[key_for(url)] = value
|
32
|
-
when store.respond_to?(:set)
|
33
|
-
store.set key_for(url), value
|
34
|
-
when store.respond_to?(:write)
|
35
|
-
store.write key_for(url), value
|
36
|
-
end
|
24
|
+
store_service.write(url, value)
|
37
25
|
rescue => e
|
38
|
-
warn "Geocoder cache write error: #{e}"
|
26
|
+
Geocoder.log(:warn, "Geocoder cache write error: #{e}")
|
39
27
|
end
|
40
28
|
|
41
29
|
##
|
@@ -44,7 +32,7 @@ module Geocoder
|
|
44
32
|
#
|
45
33
|
def expire(url)
|
46
34
|
if url == :all
|
47
|
-
if
|
35
|
+
if store_service.respond_to?(:keys)
|
48
36
|
urls.each{ |u| expire(u) }
|
49
37
|
else
|
50
38
|
raise(NoMethodError, "The Geocoder cache store must implement `#keys` for `expire(:all)` to work")
|
@@ -57,29 +45,21 @@ module Geocoder
|
|
57
45
|
|
58
46
|
private # ----------------------------------------------------------------
|
59
47
|
|
60
|
-
def
|
61
|
-
def store; @store; end
|
62
|
-
|
63
|
-
##
|
64
|
-
# Cache key for a given URL.
|
65
|
-
#
|
66
|
-
def key_for(url)
|
67
|
-
[prefix, url].join
|
68
|
-
end
|
48
|
+
def store_service; @store_service; end
|
69
49
|
|
70
50
|
##
|
71
51
|
# Array of keys with the currently configured prefix
|
72
52
|
# that have non-nil values.
|
73
53
|
#
|
74
54
|
def keys
|
75
|
-
|
55
|
+
store_service.keys
|
76
56
|
end
|
77
57
|
|
78
58
|
##
|
79
59
|
# Array of cached URLs.
|
80
60
|
#
|
81
61
|
def urls
|
82
|
-
|
62
|
+
store_service.urls
|
83
63
|
end
|
84
64
|
|
85
65
|
##
|
@@ -91,8 +71,7 @@ module Geocoder
|
|
91
71
|
end
|
92
72
|
|
93
73
|
def expire_single_url(url)
|
94
|
-
|
95
|
-
store.respond_to?(:del) ? store.del(key) : store.delete(key)
|
74
|
+
store_service.remove(url)
|
96
75
|
end
|
97
76
|
end
|
98
77
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Geocoder::CacheStore
|
2
|
+
class Base
|
3
|
+
def initialize(store, options)
|
4
|
+
@store = store
|
5
|
+
@config = options
|
6
|
+
@prefix = config[:prefix]
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Array of keys with the currently configured prefix
|
11
|
+
# that have non-nil values.
|
12
|
+
def keys
|
13
|
+
store.keys.select { |k| k.match(/^#{prefix}/) and self[k] }
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Array of cached URLs.
|
18
|
+
#
|
19
|
+
def urls
|
20
|
+
keys
|
21
|
+
end
|
22
|
+
|
23
|
+
protected # ----------------------------------------------------------------
|
24
|
+
|
25
|
+
def prefix; @prefix; end
|
26
|
+
def store; @store; end
|
27
|
+
def config; @config; end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Cache key for a given URL.
|
31
|
+
#
|
32
|
+
def key_for(url)
|
33
|
+
if url.match(/^#{prefix}/)
|
34
|
+
url
|
35
|
+
else
|
36
|
+
[prefix, url].join
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'geocoder/cache_stores/base'
|
2
|
+
|
3
|
+
module Geocoder::CacheStore
|
4
|
+
class Generic < Base
|
5
|
+
def write(url, value)
|
6
|
+
case
|
7
|
+
when store.respond_to?(:[]=)
|
8
|
+
store[key_for(url)] = value
|
9
|
+
when store.respond_to?(:set)
|
10
|
+
store.set key_for(url), value
|
11
|
+
when store.respond_to?(:write)
|
12
|
+
store.write key_for(url), value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def read(url)
|
17
|
+
case
|
18
|
+
when store.respond_to?(:[])
|
19
|
+
store[key_for(url)]
|
20
|
+
when store.respond_to?(:get)
|
21
|
+
store.get key_for(url)
|
22
|
+
when store.respond_to?(:read)
|
23
|
+
store.read key_for(url)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def keys
|
28
|
+
store.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove(key)
|
32
|
+
store.delete(key)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'geocoder/cache_stores/base'
|
2
|
+
|
3
|
+
module Geocoder::CacheStore
|
4
|
+
class Redis < Base
|
5
|
+
def initialize(store, options)
|
6
|
+
super
|
7
|
+
@expiration = options[:expiration]
|
8
|
+
end
|
9
|
+
|
10
|
+
def write(url, value, expire = @expiration)
|
11
|
+
if expire.present?
|
12
|
+
store.set key_for(url), value, ex: expire
|
13
|
+
else
|
14
|
+
store.set key_for(url), value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def read(url)
|
19
|
+
store.get key_for(url)
|
20
|
+
end
|
21
|
+
|
22
|
+
def keys
|
23
|
+
store.keys("#{prefix}*")
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove(key)
|
27
|
+
store.del(key)
|
28
|
+
end
|
29
|
+
|
30
|
+
private # ----------------------------------------------------------------
|
31
|
+
|
32
|
+
def expire; @expiration; end
|
33
|
+
end
|
34
|
+
end
|
@@ -55,19 +55,20 @@ module Geocoder
|
|
55
55
|
:lookup,
|
56
56
|
:ip_lookup,
|
57
57
|
:language,
|
58
|
+
:host,
|
58
59
|
:http_headers,
|
59
60
|
:use_https,
|
60
61
|
:http_proxy,
|
61
62
|
:https_proxy,
|
62
63
|
:api_key,
|
63
64
|
:cache,
|
64
|
-
:cache_prefix,
|
65
65
|
:always_raise,
|
66
66
|
:units,
|
67
67
|
:distances,
|
68
68
|
:basic_auth,
|
69
69
|
:logger,
|
70
|
-
:kernel_logger_level
|
70
|
+
:kernel_logger_level,
|
71
|
+
:cache_options
|
71
72
|
]
|
72
73
|
|
73
74
|
attr_accessor :data
|
@@ -76,6 +77,10 @@ module Geocoder
|
|
76
77
|
instance.set_defaults
|
77
78
|
end
|
78
79
|
|
80
|
+
def self.initialize
|
81
|
+
instance.send(:initialize)
|
82
|
+
end
|
83
|
+
|
79
84
|
OPTIONS.each do |o|
|
80
85
|
define_method o do
|
81
86
|
@data[o]
|
@@ -106,8 +111,6 @@ module Geocoder
|
|
106
111
|
@data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
|
107
112
|
@data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
|
108
113
|
@data[:api_key] = nil # API key for geocoding service
|
109
|
-
@data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
|
110
|
-
@data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
|
111
114
|
@data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
|
112
115
|
@data[:logger] = :kernel # :kernel or Logger instance
|
113
116
|
@data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
|
@@ -120,6 +123,16 @@ module Geocoder
|
|
120
123
|
# calculation options
|
121
124
|
@data[:units] = :mi # :mi or :km
|
122
125
|
@data[:distances] = :linear # :linear or :spherical
|
126
|
+
|
127
|
+
# Set the default values for the caching mechanism
|
128
|
+
# By default, the cache keys will not expire as IP addresses and phyiscal
|
129
|
+
# addresses will rarely change.
|
130
|
+
@data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
|
131
|
+
@data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
|
132
|
+
@data[:cache_options] = {
|
133
|
+
prefix: 'geocoder:',
|
134
|
+
expiration: nil
|
135
|
+
}
|
123
136
|
end
|
124
137
|
|
125
138
|
instance_eval(OPTIONS.map do |option|
|
data/lib/geocoder/ip_address.rb
CHANGED
@@ -7,6 +7,15 @@ module Geocoder
|
|
7
7
|
'192.168.0.0/16',
|
8
8
|
].map { |ip| IPAddr.new(ip) }.freeze
|
9
9
|
|
10
|
+
def initialize(ip)
|
11
|
+
ip = ip.to_string if ip.is_a?(IPAddr)
|
12
|
+
if ip.is_a?(Hash)
|
13
|
+
super(**ip)
|
14
|
+
else
|
15
|
+
super(ip)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
10
19
|
def internal?
|
11
20
|
loopback? || private?
|
12
21
|
end
|
data/lib/geocoder/lookup.rb
CHANGED
@@ -18,13 +18,21 @@ module Geocoder
|
|
18
18
|
all_services - [:test]
|
19
19
|
end
|
20
20
|
|
21
|
+
##
|
22
|
+
# Array of valid Lookup service names, excluding any that do not build their own HTTP requests.
|
23
|
+
# For example, Amazon Location Service uses the AWS gem, not HTTP REST requests, to fetch data.
|
24
|
+
#
|
25
|
+
def all_services_with_http_requests
|
26
|
+
all_services_except_test - [:amazon_location_service, :maxmind_local, :geoip2, :ip2location_lite]
|
27
|
+
end
|
28
|
+
|
21
29
|
##
|
22
30
|
# All street address lookup services, default first.
|
23
31
|
#
|
24
32
|
def street_services
|
25
33
|
@street_services ||= [
|
26
34
|
:location_iq,
|
27
|
-
:
|
35
|
+
:azure,
|
28
36
|
:esri,
|
29
37
|
:google,
|
30
38
|
:google_premier,
|
@@ -40,6 +48,7 @@ module Geocoder
|
|
40
48
|
:uk_ordnance_survey_names,
|
41
49
|
:opencagedata,
|
42
50
|
:pelias,
|
51
|
+
:pdok_nl,
|
43
52
|
:pickpoint,
|
44
53
|
:here,
|
45
54
|
:baidu,
|
@@ -53,7 +62,13 @@ module Geocoder
|
|
53
62
|
:test,
|
54
63
|
:latlon,
|
55
64
|
:amap,
|
56
|
-
:osmnames
|
65
|
+
:osmnames,
|
66
|
+
:melissa_street,
|
67
|
+
:amazon_location_service,
|
68
|
+
:geoapify,
|
69
|
+
:photon,
|
70
|
+
:twogis,
|
71
|
+
:pc_miler
|
57
72
|
]
|
58
73
|
end
|
59
74
|
|
@@ -63,6 +78,7 @@ module Geocoder
|
|
63
78
|
def ip_services
|
64
79
|
@ip_services ||= [
|
65
80
|
:baidu_ip,
|
81
|
+
:abstract_api,
|
66
82
|
:freegeoip,
|
67
83
|
:geoip2,
|
68
84
|
:maxmind,
|
@@ -77,7 +93,11 @@ module Geocoder
|
|
77
93
|
:db_ip_com,
|
78
94
|
:ipstack,
|
79
95
|
:ip2location,
|
80
|
-
:ipgeolocation
|
96
|
+
:ipgeolocation,
|
97
|
+
:ipqualityscore,
|
98
|
+
:ipbase,
|
99
|
+
:ip2location_io,
|
100
|
+
:ip2location_lite
|
81
101
|
]
|
82
102
|
end
|
83
103
|
|
@@ -103,8 +123,7 @@ module Geocoder
|
|
103
123
|
def spawn(name)
|
104
124
|
if all_services.include?(name)
|
105
125
|
name = name.to_s
|
106
|
-
|
107
|
-
Geocoder::Lookup.const_get(classify_name(name)).new
|
126
|
+
instantiate_lookup(name)
|
108
127
|
else
|
109
128
|
valids = all_services.map(&:inspect).join(", ")
|
110
129
|
raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
|
@@ -118,5 +137,18 @@ module Geocoder
|
|
118
137
|
def classify_name(filename)
|
119
138
|
filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
|
120
139
|
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Safely instantiate Lookup
|
143
|
+
#
|
144
|
+
def instantiate_lookup(name)
|
145
|
+
class_name = classify_name(name)
|
146
|
+
begin
|
147
|
+
Geocoder::Lookup.const_get(class_name, inherit=false)
|
148
|
+
rescue NameError
|
149
|
+
require "geocoder/lookups/#{name}"
|
150
|
+
end
|
151
|
+
Geocoder::Lookup.const_get(class_name).new
|
152
|
+
end
|
121
153
|
end
|
122
154
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'geocoder/lookups/base'
|
4
|
+
require 'geocoder/results/abstract_api'
|
5
|
+
|
6
|
+
module Geocoder::Lookup
|
7
|
+
class AbstractApi < Base
|
8
|
+
|
9
|
+
def name
|
10
|
+
"Abstract API"
|
11
|
+
end
|
12
|
+
|
13
|
+
def required_api_key_parts
|
14
|
+
['api_key']
|
15
|
+
end
|
16
|
+
|
17
|
+
def supported_protocols
|
18
|
+
[:https]
|
19
|
+
end
|
20
|
+
|
21
|
+
private # ---------------------------------------------------------------
|
22
|
+
|
23
|
+
def base_query_url(query)
|
24
|
+
"#{protocol}://ipgeolocation.abstractapi.com/v1/?"
|
25
|
+
end
|
26
|
+
|
27
|
+
def query_url_params(query)
|
28
|
+
params = {api_key: configuration.api_key}
|
29
|
+
|
30
|
+
ip_address = query.sanitized_text
|
31
|
+
if ip_address.is_a?(String) && ip_address.length > 0
|
32
|
+
params[:ip_address] = ip_address
|
33
|
+
end
|
34
|
+
|
35
|
+
params.merge(super)
|
36
|
+
end
|
37
|
+
|
38
|
+
def results(query, reverse = false)
|
39
|
+
if doc = fetch_data(query)
|
40
|
+
[doc]
|
41
|
+
else
|
42
|
+
[]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -32,10 +32,10 @@ module Geocoder::Lookup
|
|
32
32
|
return doc['geocodes'] unless doc['geocodes'].blank?
|
33
33
|
when ['0', 'INVALID_USER_KEY']
|
34
34
|
raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
|
35
|
-
warn
|
35
|
+
Geocoder.log(:warn, "#{self.name} Geocoding API error: invalid api key.")
|
36
36
|
else
|
37
37
|
raise_error(Geocoder::Error, "server error.") ||
|
38
|
-
warn
|
38
|
+
Geocoder.log(:warn, "#{self.name} Geocoding API error: server error - [#{doc['info']}]")
|
39
39
|
end
|
40
40
|
return []
|
41
41
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/amazon_location_service'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class AmazonLocationService < Base
|
6
|
+
def results(query)
|
7
|
+
params = query.options.dup
|
8
|
+
|
9
|
+
# index_name is required
|
10
|
+
# Aws::ParamValidator raises ArgumentError on missing required keys
|
11
|
+
params.merge!(index_name: configuration[:index_name])
|
12
|
+
|
13
|
+
# Aws::ParamValidator raises ArgumentError on unexpected keys
|
14
|
+
params.delete(:lookup)
|
15
|
+
|
16
|
+
# Inherit language from configuration
|
17
|
+
params.merge!(language: configuration[:language])
|
18
|
+
|
19
|
+
resp = if query.reverse_geocode?
|
20
|
+
client.search_place_index_for_position(params.merge(position: query.coordinates.reverse))
|
21
|
+
else
|
22
|
+
client.search_place_index_for_text(params.merge(text: query.text))
|
23
|
+
end
|
24
|
+
|
25
|
+
resp.results
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def client
|
31
|
+
return @client if @client
|
32
|
+
require_sdk
|
33
|
+
keys = configuration.api_key
|
34
|
+
if keys
|
35
|
+
@client = Aws::LocationService::Client.new(**{
|
36
|
+
region: keys[:region],
|
37
|
+
access_key_id: keys[:access_key_id],
|
38
|
+
secret_access_key: keys[:secret_access_key]
|
39
|
+
}.compact)
|
40
|
+
else
|
41
|
+
@client = Aws::LocationService::Client.new
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def require_sdk
|
46
|
+
begin
|
47
|
+
require 'aws-sdk-locationservice'
|
48
|
+
rescue LoadError
|
49
|
+
raise_error(Geocoder::ConfigurationError) ||
|
50
|
+
Geocoder.log(
|
51
|
+
:error,
|
52
|
+
"Couldn't load the Amazon Location Service SDK. " +
|
53
|
+
"Install it with: gem install aws-sdk-locationservice -v '~> 1.4'"
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/azure'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Azure < Base
|
6
|
+
def name
|
7
|
+
'Azure'
|
8
|
+
end
|
9
|
+
|
10
|
+
def required_api_key_parts
|
11
|
+
['api_key']
|
12
|
+
end
|
13
|
+
|
14
|
+
def supported_protocols
|
15
|
+
[:https]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def base_query_url(query)
|
21
|
+
host = 'atlas.microsoft.com/search/address'
|
22
|
+
|
23
|
+
if query.reverse_geocode?
|
24
|
+
"#{protocol}://#{host}/reverse/json?"
|
25
|
+
else
|
26
|
+
"#{protocol}://#{host}/json?"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def query_url_params(query)
|
31
|
+
params = {
|
32
|
+
'api-version' => 1.0,
|
33
|
+
'language' => query.options[:language] || 'en',
|
34
|
+
'limit' => configuration[:limit] || 10,
|
35
|
+
'query' => query.sanitized_text,
|
36
|
+
'subscription-key' => configuration.api_key
|
37
|
+
}
|
38
|
+
|
39
|
+
params.merge(super)
|
40
|
+
end
|
41
|
+
|
42
|
+
def results(query)
|
43
|
+
return [] unless (doc = fetch_data(query))
|
44
|
+
|
45
|
+
return doc if doc['error']
|
46
|
+
|
47
|
+
if doc['results']&.any?
|
48
|
+
doc['results']
|
49
|
+
elsif doc['addresses']&.any?
|
50
|
+
doc['addresses']
|
51
|
+
else
|
52
|
+
[]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -125,7 +125,7 @@ module Geocoder::Lookup
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def type_param_is_valid?(param)
|
128
|
-
%w(housenumber street locality
|
128
|
+
%w(housenumber street locality municipality).include?(param.downcase)
|
129
129
|
end
|
130
130
|
|
131
131
|
def code_param_is_valid?(param)
|
@@ -19,7 +19,7 @@ module Geocoder::Lookup
|
|
19
19
|
private # ---------------------------------------------------------------
|
20
20
|
|
21
21
|
def base_query_url(query)
|
22
|
-
text =
|
22
|
+
text = ERB::Util.url_encode(query.sanitized_text.strip)
|
23
23
|
url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations/"
|
24
24
|
if query.reverse_geocode?
|
25
25
|
url + "#{text}?"
|
@@ -54,7 +54,7 @@ module Geocoder::Lookup
|
|
54
54
|
def query_url_params(query)
|
55
55
|
{
|
56
56
|
key: configuration.api_key,
|
57
|
-
|
57
|
+
culture: (query.language || configuration.language)
|
58
58
|
}.merge(super)
|
59
59
|
end
|
60
60
|
|
@@ -23,15 +23,28 @@ module Geocoder::Lookup
|
|
23
23
|
def results(query)
|
24
24
|
return [] unless doc = fetch_data(query)
|
25
25
|
|
26
|
-
if (!query.reverse_geocode?)
|
27
|
-
return [] if !doc['locations'] || doc['locations'].empty?
|
28
|
-
end
|
29
|
-
|
30
26
|
if (doc['error'].nil?)
|
27
|
+
if (!query.reverse_geocode?)
|
28
|
+
return [] if !doc['locations'] || doc['locations'].empty?
|
29
|
+
end
|
31
30
|
return [ doc ]
|
32
31
|
else
|
33
|
-
|
32
|
+
case [ doc['error']['code'] ]
|
33
|
+
when [498]
|
34
|
+
raise_error(Geocoder::InvalidApiKey, doc['error']['message']) ||
|
35
|
+
Geocoder.log(:warn, "#{self.name} Geocoding API error: #{doc['error']['message']}")
|
36
|
+
when [ 403 ]
|
37
|
+
raise_error(Geocoder::RequestDenied, 'ESRI request denied') ||
|
38
|
+
Geocoder.log(:warn, "#{self.name} ESRI request denied: #{doc['error']['message']}")
|
39
|
+
when [ 500 ], [501]
|
40
|
+
raise_error(Geocoder::ServiceUnavailable, 'ESRI service unavailable') ||
|
41
|
+
Geocoder.log(:warn, "#{self.name} ESRI service error: #{doc['error']['message']}")
|
42
|
+
else
|
43
|
+
raise_error(Geocoder::Error, doc['error']['message']) ||
|
44
|
+
Geocoder.log(:warn, "#{self.name} Geocoding error: #{doc['error']['message']}")
|
45
|
+
end
|
34
46
|
end
|
47
|
+
return []
|
35
48
|
end
|
36
49
|
|
37
50
|
def query_url_params(query)
|