diff --git a/README.rdoc b/README.rdoc index ce88545d3d50536d78b17a9c10bfd5538fca2b74..d4210ba3eee90a87b15dd3580c767b608e3216d5 100644 --- a/README.rdoc +++ b/README.rdoc @@ -235,6 +235,12 @@ By default Geocoder uses Google's geocoding API to fetch coordinates and street # to use an API key: Geocoder::Configuration.api_key = "..." + # IP geocoding service : + Geocoder::Configuration.ip_lookup = :maxmind + + # to use an API key for IP geocoding service: + Geocoder::Configuration.ip_lookup_api_key = "..." + # geocoding service request timeout, in seconds (default 3): Geocoder::Configuration.timeout = 5 @@ -328,6 +334,16 @@ Documentation:: http://github.com/fiorix/freegeoip/blob/master/README.rst Terms of Service:: ? Limitations:: ? +==== MaxMind City + +API key:: required +Quota:: Requests Packs can be purchased (starting at 50,000 for 20$) +Region:: world +SSL support:: no +Languages:: English +Documentation:: http://www.maxmind.com/app/web_services +Terms of Service:: ? +Limitations:: ? == Caching diff --git a/lib/geocoder.rb b/lib/geocoder.rb index 5bce2283b9e2463c76edf7ba9e4e99e1bd830ff7..123cb619448a3d6acf3e321452382bb3563a50ec 100644 --- a/lib/geocoder.rb +++ b/lib/geocoder.rb @@ -63,7 +63,7 @@ module Geocoder # All IP address lookups, default first. # def ip_lookups - [:freegeoip] + [:freegeoip, :maxmind] end @@ -81,7 +81,7 @@ module Geocoder # def lookup(query) if ip_address?(query) - get_lookup(ip_lookups.first) + get_lookup(Configuration.ip_lookup || ip_lookups.first) else get_lookup(Configuration.lookup || street_lookups.first) end diff --git a/lib/geocoder/configuration.rb b/lib/geocoder/configuration.rb index 44baabeebf4547d063ee0798ce643a2d1aebfa86..13d39e361e4d8c98d2d8d8cae19e9919c35a16a7 100644 --- a/lib/geocoder/configuration.rb +++ b/lib/geocoder/configuration.rb @@ -25,6 +25,14 @@ module Geocoder # for Google Premier use a 3-element array: [key, client, channel] [:api_key, nil], + # name of IP geocoding service (symbol) + # FIXME: temporary added for Maxmind support, need clean rewrite + [:ip_lookup, nil], + + # API key for IP geocoding service + # FIXME: temporary added for Maxmind support, need clean rewrite + [:ip_lookup_api_key, nil], + # cache object (must respond to #[], #[]=, and #keys) [:cache, nil], diff --git a/lib/geocoder/lookups/maxmind.rb b/lib/geocoder/lookups/maxmind.rb new file mode 100644 index 0000000000000000000000000000000000000000..334463d5e92032b18ef5bc5160f5bcf7a356ec66 --- /dev/null +++ b/lib/geocoder/lookups/maxmind.rb @@ -0,0 +1,38 @@ +require 'geocoder/lookups/base' +require 'geocoder/results/maxmind' + +module Geocoder::Lookup + class Maxmind < Base + + private # --------------------------------------------------------------- + + def results(query, reverse = false) + # don't look up a loopback address, just return the stored result + return [reserved_result] if loopback_address?(query) + begin + doc = fetch_data(query, reverse) + if doc && doc.size == 10 + return [doc] + else + warn "Maxmind error : #{doc[10]}" if doc + return [] + end + rescue StandardError => err + raise_error(err) + return [] + end + end + + def parse_raw_data(raw_data) + raw_data.split(',') # Maxmind just returns text/plain + end + + def reserved_result + ",,,,0,0,0,0,," + end + + def query_url(query, reverse = false) + "http://geoip3.maxmind.com/f?l=#{Geocoder::Configuration.ip_lookup_api_key}&i=#{query}" + end + end +end diff --git a/lib/geocoder/results/maxmind.rb b/lib/geocoder/results/maxmind.rb new file mode 100644 index 0000000000000000000000000000000000000000..8963ab5c729ab4d0a13ed24545e8a7211c5570c0 --- /dev/null +++ b/lib/geocoder/results/maxmind.rb @@ -0,0 +1,55 @@ +require 'geocoder/results/base' + +module Geocoder::Result + class Maxmind < Base + + def address(format = :full) + s = state_code.to_s == "" ? "" : ", #{state_code}" + "#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "") + end + + def country_code + @data[0] + end + + def state_code + @data[1] + end + + def city + @data[2] + end + + def postal_code + @data[3] + end + + def coordinates + [@data[4].to_f, @data[5].to_f] + end + + def metrocode + @data[6] + end + + def area_code + @data[7] + end + + def isp + @data[8][1,@data[8].length-2] + end + + def organization + @data[9][1,@data[9].length-2] + end + + def country #not given by MaxMind + country_code + end + + def state #not given by MaxMind + state_code + end + end +end diff --git a/test/fixtures/maxmind_74_200_247_59.txt b/test/fixtures/maxmind_74_200_247_59.txt new file mode 100644 index 0000000000000000000000000000000000000000..226e7219ce802849045a8e44a550bbe2e68dabb2 --- /dev/null +++ b/test/fixtures/maxmind_74_200_247_59.txt @@ -0,0 +1 @@ +US,TX,Plano,75093,33.034698,-96.813400,623,972,"Layered Technologies","Layered Technologies" \ No newline at end of file diff --git a/test/fixtures/maxmind_no_results.txt b/test/fixtures/maxmind_no_results.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1d1bc2d3195d6084a0e152a2a2dbf193382bc04 --- /dev/null +++ b/test/fixtures/maxmind_no_results.txt @@ -0,0 +1 @@ +,,,,,,,,,,IP_NOT_FOUND \ No newline at end of file diff --git a/test/lookup_test.rb b/test/lookup_test.rb index 3c72d05b84294fce0a7ce0394ee9645d649edf81..7574566643e13a3e6be54f99ead3c3d3e8240906 100644 --- a/test/lookup_test.rb +++ b/test/lookup_test.rb @@ -27,4 +27,10 @@ class LookupTest < Test::Unit::TestCase g = Geocoder::Lookup::Yahoo.new assert_match "appid=MY_KEY", g.send(:query_url, "Madison Square Garden, New York, NY 10001, United States") end + + def test_maxmind_api_key + Geocoder::Configuration.ip_lookup_api_key = "MY_KEY" + g = Geocoder::Lookup::Maxmind.new + assert_match "l=MY_KEY", g.send(:query_url, "74.200.247.59") + end end diff --git a/test/services_test.rb b/test/services_test.rb index b01b84abcbdb03c4c2f466f6b39859d687b26774..7c421e817bdb28c15f0f842a59a2b19b84e5dfbd 100644 --- a/test/services_test.rb +++ b/test/services_test.rb @@ -94,6 +94,20 @@ class ServicesTest < Test::Unit::TestCase assert_equal "Plano, TX 75093, United States", result.address end + # --- MaxMind --- + + def test_maxmind_result_on_ip_address_search + Geocoder::Configuration.ip_lookup = :maxmind + result = Geocoder.search("74.200.247.59").first + assert result.is_a?(Geocoder::Result::Maxmind) + end + + def test_maxmind_result_components + Geocoder::Configuration.ip_lookup = :maxmind + result = Geocoder.search("74.200.247.59").first + assert_equal "Plano, TX 75093, US", result.address + end + # --- Bing --- diff --git a/test/test_helper.rb b/test/test_helper.rb index 137f756fdbad489f0880c08e64f452d0bf2ef7cb..e0567689cc352094b30c1adc41a34632e23b6e11 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -133,6 +133,19 @@ module Geocoder end end + class Maxmind < Base + private #----------------------------------------------------------------- + def fetch_raw_data(query, reverse = false) + raise TimeoutError if query == "timeout" + raise SocketError if query == "socket_error" + file = case query + when "no results"; :no_results + else "74_200_247_59" + end + read_fixture "maxmind_#{file}.txt" + end + end + class Bing < Base private #----------------------------------------------------------------- def fetch_raw_data(query, reverse = false)