Skip to content

Commit

Permalink
Add IP2Location LITE support (#1633)
Browse files Browse the repository at this point in the history
  • Loading branch information
ip2location committed Oct 10, 2023
1 parent 35a143d commit e05a5ae
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 7 deletions.
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 @@ -816,4 +816,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

0 comments on commit e05a5ae

Please sign in to comment.