diff --git a/README.md b/README.md index 1cabb3549ae18830f9630c733006bd13c2e9aea7..c97e3494d2ba223807853fd116740e9e3cb0887a 100644 --- a/README.md +++ b/README.md @@ -394,6 +394,17 @@ Yahoo BOSS is **not a free service**. As of November 17, 2012 Yahoo no longer of * **Terms of Service**: ? * **Limitations**: ? +#### MaxMind Web Services (`:maxmind`) + +* **API key**: required +* **Quota**: Request Packs can be purchased +* **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/lookup.rb b/lib/geocoder/lookup.rb index 4e58888d09ab9f46a4e5287883a4a23075f92e4e..472a164a01193e823eac1cea726dfae4f685f074 100644 --- a/lib/geocoder/lookup.rb +++ b/lib/geocoder/lookup.rb @@ -37,7 +37,7 @@ module Geocoder # All IP address lookup services, default first. # def ip_services - [:freegeoip] + [:freegeoip, :maxmind] end ## diff --git a/lib/geocoder/lookups/maxmind.rb b/lib/geocoder/lookups/maxmind.rb new file mode 100644 index 0000000000000000000000000000000000000000..ab57f8b28250d83134fa1d9007e7bdfda876293b --- /dev/null +++ b/lib/geocoder/lookups/maxmind.rb @@ -0,0 +1,41 @@ +require 'geocoder/lookups/base' +require 'geocoder/results/maxmind' +require 'csv' + +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) + # Maxmind just returns text/plain as csv format but according to documentation, + # we get ISO-8859-1 encoded string. We need to convert it. + CSV.parse_line raw_data.force_encoding("ISO-8859-1").encode("UTF-8") + 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..22fce3390f59c095a1c844430478794ceac813d8 --- /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 , US","Layered Technologies , US" \ 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 4c9a00478a879694992d7abf1b6f84a9086f75f6..80fa5cdb17107f41cb55a0df121f5dcfadda0c4f 100644 --- a/test/lookup_test.rb +++ b/test/lookup_test.rb @@ -43,4 +43,10 @@ class LookupTest < Test::Unit::TestCase Geocoder.search("Madison Square Garden, New York, NY 10001, United States") end 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 d33a648f16f6e8cab7a1eea80f3e19e825f5b2fb..f47f6593d12f91db48004c8238faa234c9416827 100644 --- a/test/services_test.rb +++ b/test/services_test.rb @@ -142,6 +142,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 bff1219907fc5343f6426f114a9290135e195a05..a594ef9ee6f7994411a40909620cb30e8032e3e2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -161,6 +161,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 make_api_request(query)