lib/geocoder/lookups/maxmind_geoip2.rb



require 'geocoder/lookups/base'
require 'geocoder/results/maxmind_geoip2'

module Geocoder::Lookup
  class MaxmindGeoip2 < Base

    def name
      "MaxMind GeoIP2"
    end

    # Maxmind's GeoIP2 Precision Services only supports HTTPS,
    # otherwise a `404 Not Found` HTTP response will be returned
    def supported_protocols
      [:https]
    end

    def query_url(query)
      "#{protocol}://geoip.maxmind.com/geoip/v2.1/#{configured_service!}/#{URI.escape(query.sanitized_text.strip)}"
    end

    private # ---------------------------------------------------------------

    ##
    # Return the name of the configured service, or raise an exception.
    #
    def configured_service!
      if s = configuration[:service] and services.include?(s) and configuration[:basic_auth][:user] and configuration[:basic_auth][:password]
        return s
      else
        raise(
          Geocoder::ConfigurationError,
          "When using MaxMind GeoIP2 you MUST specify a service name and basic_auth: " +
          "Geocoder.configure(:maxmind_geoip2 => {:service => ...}, " +
          ":basic_auth => {:user ..., :password => ...}), " +
          "where service is one of: #{services.inspect}"
        )
      end
    end

    def data_contains_error?(doc)
      (["code", "error"] - doc.keys).empty?
    end

    ##
    # Service names used in URL.
    #
    def services
      [
        :country,
        :city,
        :insights,
      ]
    end

    def results(query)
      # don't look up a loopback address
      return [] if query.loopback_ip_address?
      doc = fetch_data(query)
      if doc
        if !data_contains_error?(doc)
          return [doc]
        else
          Geocoder.log(:warn, "MaxMind GeoIP2 Geocoding API error: #{doc['code']} (#{doc['error']}).")
        end
      end
      return []
    end
  end
end