Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IP2Location LITE support #1633

Merged
merged 4 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ group :development, :test do
gem 'rubyzip'
gem 'rails', '~>5.1.0'
gem 'test-unit' # needed for Ruby >=2.2.0
gem 'ip2location_ruby'

platforms :jruby do
gem 'jruby-openssl'
Expand Down
22 changes: 22 additions & 0 deletions README_API_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -815,4 +815,26 @@ You can generate ActiveRecord migrations and download and import data via provid

You can replace `city` with `country` in any of the above tasks, generators, and configurations.

### IP2Location LITE (`:ip2location_lite`)

This lookup provides methods for geocoding IP addresses without making a call to a remote API (improves speed and availability).

* **API key**: none (requires a IP2Location or FREE IP2Location LITE binary database which can be downloaded from [IP2Location LITE](https://lite.ip2location.com/))
* **Quota**: none
* **Region**: world
* **SSL support**: N/A
* **Languages**: English
* **Documentation**: https://lite.ip2location.com/
* **Terms of Service**: https://lite.ip2location.com/
* **Notes**: **You must download a binary database (BIN) file from IP2Location LITE and set the `:file` configuration option.** Set the path to the database file in your configuration:

Geocoder.configure(
ip_lookup: :ip2location_lite,
ip2location_lite: {
file: File.join('folder', 'IP2LOCATION-LITE-DB11.BIN')
}
)

You must add the *[ip2location_ruby](https://rubygems.org/gems/ip2location_ruby)* gem (pure Ruby implementation) to your Gemfile or have it installed in your system.

Copyright (c) 2009-2021 Alex Reisner, released under the MIT license.
5 changes: 3 additions & 2 deletions lib/geocoder/lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def all_services_except_test
# For example, Amazon Location Service uses the AWS gem, not HTTP REST requests, to fetch data.
#
def all_services_with_http_requests
all_services_except_test - [:amazon_location_service]
all_services_except_test - [:amazon_location_service, :ip2location_lite]
end

##
Expand Down Expand Up @@ -95,7 +95,8 @@ def ip_services
:ipgeolocation,
:ipqualityscore,
:ipbase,
:ip2location_io
:ip2location_io,
:ip2location_lite
]
end

Expand Down
40 changes: 40 additions & 0 deletions lib/geocoder/lookups/ip2location_lite.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'geocoder/lookups/base'
require 'geocoder/results/ip2location_lite'

module Geocoder
module Lookup
class Ip2locationLite < Base
attr_reader :gem_name

def initialize
unless configuration[:file].nil?
begin
@gem_name = 'ip2location_ruby'
require @gem_name
rescue LoadError
raise "Could not load IP2Location DB dependency. To use the IP2LocationLite lookup you must add the #{@gem_name} gem to your Gemfile or have it installed in your system."
end
end
super
end

def name
'IP2LocationLite'
end

def required_api_key_parts
[]
end

private

def results(query)
return [] unless configuration[:file]

i2l = Ip2location.new.open(configuration[:file].to_s)
result = i2l.get_all(query.to_s)
result.nil? ? [] : [result]
end
end
end
end
47 changes: 47 additions & 0 deletions lib/geocoder/results/ip2location_lite.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require 'geocoder/results/base'

module Geocoder::Result
class Ip2locationLite < Base

def coordinates
[@data[:latitude], @data[:longitude]]
end

def city
@data[:city]
end

def state
@data[:region]
end

def state_code
"" # Not available in Maxmind's database
end

def country
@data[:country_long]
end

def country_code
@data[:country_short]
end

def postal_code
@data[:zipcode]
end

def self.response_attributes
%w[country_short country_long region latitude longitude isp
domain netspeed areacode iddcode timezone zipcode weatherstationname
weatherstationcode mcc mnc mobilebrand elevation usagetype addresstype
category district asn as]
end

response_attributes.each do |a|
define_method a do
@data[a] || ""
end
end
end
end
17 changes: 17 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,23 @@ def default_fixture_filename
end
end

require 'geocoder/lookups/ip2location_lite'
class Ip2locationLite
private

remove_method(:results)

def results query
return [] if query.to_s == "no results"

if query.to_s == '127.0.0.1'
[{:country_short=>"-", :country_long=>"-", :region=>"-", :city=>"-", :latitude=>0.0, :longitude=>0.0, :zipcode=>"-", :timezone=>"-", :isp=>"Loopback", :domain=>"-", :netspeed=>"-", :iddcode=>"-", :areacode=>"-", :weatherstationcode=>"-", :weatherstationname=>"-", :mcc=>"-", :mnc=>"-", :mobilebrand=>"-", :elevation=>0, :usagetype=>"RSV", :addresstype=>"U", :category=>"IAB24", :district=>"-", :asn=>"-", :as=>"-"}]
elsif query.to_s == '8.8.8.8'
[{:country_short=>"US", :country_long=>"United States of America", :region=>"California", :city=>"Mountain View", :latitude=>37.40599060058594, :longitude=>-122.0785140991211, :zipcode=>"94043", :timezone=>"-07:00", :isp=>"Google LLC", :domain=>"google.com", :netspeed=>"T1", :iddcode=>"1", :areacode=>"650", :weatherstationcode=>"USCA0746", :weatherstationname=>"Mountain View", :mcc=>"-", :mnc=>"-", :mobilebrand=>"-", :elevation=>32, :usagetype=>"DCH", :addresstype=>"A", :category=>"IAB19-11", :district=>"San Diego County", :asn=>"15169", :as=>"Google LLC"}]
end
end
end

require 'geocoder/lookups/ipgeolocation'
class Ipgeolocation
private
Expand Down
1 change: 1 addition & 0 deletions test/unit/cache_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def test_second_occurrence_of_request_is_cache_hit
# local, does not use cache
l == :maxmind_local ||
l == :geoip2 ||
l == :ip2location_lite ||
# uses the AWS gem, not HTTP requests with caching
l == :amazon_location_service
Geocoder.configure(:lookup => l)
Expand Down
8 changes: 4 additions & 4 deletions test/unit/error_handling_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_never_raise_response_parse_error
def test_always_raise_timeout_error
Geocoder.configure(:always_raise => [Timeout::Error])
Geocoder::Lookup.all_services_with_http_requests.each do |l|
next if l == :maxmind_local || l == :geoip2 # local, does not use cache
next if l == :maxmind_local || l == :geoip2 || l == :ip2location_lite # local, does not use cache
lookup = Geocoder::Lookup.get(l)
set_api_key!(l)
assert_raises Timeout::Error do
Expand All @@ -55,7 +55,7 @@ def test_always_raise_timeout_error
def test_always_raise_socket_error
Geocoder.configure(:always_raise => [SocketError])
Geocoder::Lookup.all_services_with_http_requests.each do |l|
next if l == :maxmind_local || l == :geoip2 # local, does not use cache
next if l == :maxmind_local || l == :geoip2 || l == :ip2location_lite # local, does not use cache
lookup = Geocoder::Lookup.get(l)
set_api_key!(l)
assert_raises SocketError do
Expand All @@ -67,7 +67,7 @@ def test_always_raise_socket_error
def test_always_raise_connection_refused_error
Geocoder.configure(:always_raise => [Errno::ECONNREFUSED])
Geocoder::Lookup.all_services_with_http_requests.each do |l|
next if l == :maxmind_local || l == :geoip2 # local, does not use cache
next if l == :maxmind_local || l == :geoip2 || l == :ip2location_lite # local, does not use cache
lookup = Geocoder::Lookup.get(l)
set_api_key!(l)
assert_raises Errno::ECONNREFUSED do
Expand All @@ -79,7 +79,7 @@ def test_always_raise_connection_refused_error
def test_always_raise_host_unreachable_error
Geocoder.configure(:always_raise => [Errno::EHOSTUNREACH])
Geocoder::Lookup.all_services_with_http_requests.each do |l|
next if l == :maxmind_local || l == :geoip2 # local, does not use cache
next if l == :maxmind_local || l == :geoip2 || l == :ip2location_lite # local, does not use cache
lookup = Geocoder::Lookup.get(l)
set_api_key!(l)
assert_raises Errno::EHOSTUNREACH do
Expand Down
2 changes: 1 addition & 1 deletion test/unit/lookup_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_search_returns_empty_array_when_no_results

def test_query_url_contains_values_in_params_hash
Geocoder::Lookup.all_services_except_test.each do |l|
next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox, :ipdata_co, :ipinfo_io, :ipapi_com, :ipregistry, :ipstack, :postcodes_io, :uk_ordnance_survey_names, :amazon_location_service, :ipbase].include? l # does not use query string
next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox, :ipdata_co, :ipinfo_io, :ipapi_com, :ipregistry, :ipstack, :postcodes_io, :uk_ordnance_survey_names, :amazon_location_service, :ipbase, :ip2location_lite].include? l # does not use query string
set_api_key!(l)
url = Geocoder::Lookup.get(l).query_url(Geocoder::Query.new(
"test", :params => {:one_in_the_hand => "two in the bush"}
Expand Down
14 changes: 14 additions & 0 deletions test/unit/lookups/ip2location_lite_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# encoding: utf-8
require 'test_helper'

class Ip2locationLiteTest < GeocoderTestCase
def setup
super
Geocoder.configure(ip_lookup: :ip2location_lite, ip2location_lite: { file: File.join('folder', 'test_file') })
end

def test_loopback
result = Geocoder.search('127.0.0.1').first
assert_equal '', result.country_short
end
end
2 changes: 2 additions & 0 deletions test/unit/result_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def test_forward_geocoding_result_has_required_attributes
next if [
:ip2location, # has pay-per-attribute pricing model
:ip2location_io, # has pay-per-attribute pricing model
:ip2location_lite, # no forward geocoding
:twogis, # cant find 'Madison Square Garden'
].include?(l)

Expand All @@ -23,6 +24,7 @@ def test_reverse_geocoding_result_has_required_attributes
next if [
:ip2location, # has pay-per-attribute pricing model
:ip2location_io, # has pay-per-attribute pricing model
:ip2location_lite, # no reverse geocoding
:nationaal_georegister_nl, # no reverse geocoding
:melissa_street, # reverse geocoding not implemented
:twogis, # cant find 'Madison Square Garden'
Expand Down