From 158a4d7f3e9ebeacf249612361ec3efe87f8cdda Mon Sep 17 00:00:00 2001 From: SaadHassan-dev Date: Tue, 2 Jan 2024 17:21:03 +0500 Subject: [PATCH] Restructured code. Added _v6 functions. Updated README file. --- README.md | 21 ++----- lib/ipinfo.rb | 133 ++++++++++++++++++++++++++---------------- lib/ipinfo/adapter.rb | 2 +- test/ipinfo_test.rb | 92 ++++++++++++++--------------- 4 files changed, 133 insertions(+), 115 deletions(-) diff --git a/README.md b/README.md index d098c62..dce9070 100644 --- a/README.md +++ b/README.md @@ -40,25 +40,11 @@ handler = IPinfo::create(access_token) ip_address = '216.239.36.21' details = handler.details(ip_address) +details_v6 = handler.details_v6() # to get details from ipinfo's IPv6 host city = details.city # Emeryville loc = details.loc # 37.8342,-122.2900 ``` -#### To make an IPv6 request - -```ruby -require 'ipinfo' - -access_token = '123456789abc' -handler = IPinfo::create(access_token) -handler.initialize_v6 -ip_address = '216.239.36.21' - -details = handler.details(ip_address) -city = details.city # Emeryville -loc = details.loc # 37.8342,-122.2900 -`````` - ##### Note about Rails 6+ If using this package in Rails 6+, the Zeitwerk auto-loader may not properly @@ -73,7 +59,7 @@ require 'ipinfo' unless defined?(IPinfo) #### Usage -The `IPinfo.details()` method accepts an IP address as an optional, positional +The `IPinfo.details()` and `IPinfo.details_v6()` methods accept an IP address as an optional, positional argument. If no IP address is specified, the API will return data for the IP address from which it receives the request. @@ -84,6 +70,7 @@ access_token = '123456789abc' handler = IPinfo::create(access_token) details = handler.details() +details_v6 = handler.details_v6() # to get details from ipinfo's IPv6 host city = details.city # "Emeryville" loc = details.loc # 37.8342,-122.2900 ``` @@ -101,7 +88,7 @@ handler = IPinfo::create(access_token) #### Details Data -`handler.details()` will return a `Response` object that contains all fields +`handler.details()` and `handler.details_v6` will return a `Response` object that contains all fields listed in the [IPinfo developerdocs](https://ipinfo.io/developers/responses#full-response) with a few minor additions. Properties can be accessed directly. diff --git a/lib/ipinfo.rb b/lib/ipinfo.rb index 0ae29ea..e915b1b 100644 --- a/lib/ipinfo.rb +++ b/lib/ipinfo.rb @@ -41,6 +41,85 @@ def initialize_v6(access_token = nil, settings = {}) end def details(ip_address = nil) + details_base(ip_address, host_type: :v4) + end + + def details_v6(ip_address = nil) + details_base(ip_address, host_type: :v6) + end + + def get_map_url(ips) + get_map_url_base(ips, host_type: :v4) + end + + def get_map_url_v6(ips) + get_map_url_base(ips, host_type: :v6) + end + + def batch_requests(url_array, api_token) + batch_requests_base(url_array, api_token, host_type: :v4) + end + + def batch_requests_v6(url_array, api_token) + batch_requests_base(url_array, api_token, host_type: :v6) + end + + private + + def request_details(ip_address = nil) + if isBogon(ip_address) + details[:ip] = ip_address + details[:bogon] = true + details[:ip_address] = IPAddr.new(ip_address) + + return details + end + + res = @cache.get(cache_key(ip_address)) + return res unless res.nil? + + response = @httpc.get(escape_path(ip_address)) + + if response.status.eql?(429) + raise RateLimitError, + RATE_LIMIT_MESSAGE + end + + details = JSON.parse(response.body, symbolize_names: true) + @cache.set(cache_key(ip_address), details) + details + end + + def prepare_http_client(httpc = nil) + @httpc = httpc ? Adapter.new(access_token, httpc, host_type) : + Adapter.new(access_token, :net_http, host_type) + end + + def init_adapter(settings = {}, host_type: :v4) + puts "old val: #{@host_type}, new val: #{host_type}" + if @host_type.nil? || @host_type != host_type + puts "value changing" + @host_type = host_type + @httpc = prepare_http_client(settings.fetch('http_client', nil)) + end + end + + def initialize_base(access_token = nil, settings = {}, host_type: :v4) + @access_token = access_token + init_adapter(settings, host_type: host_type) + + maxsize = settings.fetch('maxsize', DEFAULT_CACHE_MAXSIZE) + ttl = settings.fetch('ttl', DEFAULT_CACHE_TTL) + @cache = settings.fetch('cache', DefaultCache.new(ttl, maxsize)) + @countries = settings.fetch('countries', DEFAULT_COUNTRY_LIST) + @eu_countries = settings.fetch('eu_countries', DEFAULT_EU_COUNTRIES_LIST) + @countries_flags = settings.fetch('countries_flags', DEFAULT_COUNTRIES_FLAG_LIST) + @countries_currencies = settings.fetch('countries_currencies', DEFAULT_COUNTRIES_CURRENCIES_LIST) + @continents = settings.fetch('continents', DEFAULT_CONTINENT_LIST) + end + + def details_base(ip_address, settings = {}, host_type: :v4) + init_adapter(settings, host_type: host_type) details = request_details(ip_address) if details.key? :country details[:country_name] = @@ -70,7 +149,8 @@ def details(ip_address = nil) Response.new(details) end - def get_map_url(ips) + def get_map_url_base(ips, settings = {}, host_type: :v4) + init_adapter(settings, host_type: host_type) if !ips.kind_of?(Array) return JSON.generate({:error => 'Invalid input. Array required!'}) end @@ -85,7 +165,8 @@ def get_map_url(ips) obj['reportUrl'] end - def batch_requests(url_array, api_token) + def batch_requests_base(url_array, api_token, settings = {}, host_type: :v4) + init_adapter(settings, host_type: host_type) result = Hash.new lookup_ips = [] @@ -125,54 +206,6 @@ def batch_requests(url_array, api_token) result end - protected - - def request_details(ip_address = nil) - if isBogon(ip_address) - details[:ip] = ip_address - details[:bogon] = true - details[:ip_address] = IPAddr.new(ip_address) - - return details - end - - res = @cache.get(cache_key(ip_address)) - return res unless res.nil? - - response = @httpc.get(escape_path(ip_address)) - - if response.status.eql?(429) - raise RateLimitError, - RATE_LIMIT_MESSAGE - end - - details = JSON.parse(response.body, symbolize_names: true) - @cache.set(cache_key(ip_address), details) - details - end - - def prepare_http_client(httpc = nil) - @httpc = httpc ? Adapter.new(access_token, httpc, host_type) : - Adapter.new(access_token, :net_http, host_type) - end - - private - - def initialize_base(access_token = nil, settings = {}, host_type: :v4) - @access_token = access_token - @host_type = host_type - @httpc = prepare_http_client(settings.fetch('http_client', nil)) - - maxsize = settings.fetch('maxsize', DEFAULT_CACHE_MAXSIZE) - ttl = settings.fetch('ttl', DEFAULT_CACHE_TTL) - @cache = settings.fetch('cache', DefaultCache.new(ttl, maxsize)) - @countries = settings.fetch('countries', DEFAULT_COUNTRY_LIST) - @eu_countries = settings.fetch('eu_countries', DEFAULT_EU_COUNTRIES_LIST) - @countries_flags = settings.fetch('countries_flags', DEFAULT_COUNTRIES_FLAG_LIST) - @countries_currencies = settings.fetch('countries_currencies', DEFAULT_COUNTRIES_CURRENCIES_LIST) - @continents = settings.fetch('continents', DEFAULT_CONTINENT_LIST) - end - def isBogon(ip) if ip.nil? return false diff --git a/lib/ipinfo/adapter.rb b/lib/ipinfo/adapter.rb index a4a1f56..6899911 100644 --- a/lib/ipinfo/adapter.rb +++ b/lib/ipinfo/adapter.rb @@ -45,7 +45,7 @@ def connection(adapter) def default_headers headers = { - 'User-Agent' => 'IPinfoClient/Ruby/#{IPinfo::VERSION}', + 'User-Agent' => "IPinfoClient/Ruby/#{IPinfo::VERSION}", 'Accept' => 'application/json' } headers['Authorization'] = "Bearer #{CGI.escape(token)}" if token diff --git a/test/ipinfo_test.rb b/test/ipinfo_test.rb index 8c8b79f..db9411c 100644 --- a/test/ipinfo_test.rb +++ b/test/ipinfo_test.rb @@ -6,29 +6,6 @@ class IPinfoTest < Minitest::Test TEST_IPV4 = '8.8.8.8' TEST_IPV6 = '2601:9:7680:363:75df:f491:6f85:352f' - def test_that_it_has_a_version_number - refute_nil ::IPinfo::VERSION - end - - def test_set_adapter_v4 - ipinfo = IPinfo.create( - ENV['IPINFO_TOKEN'], - { http_client: :excon } - ) - - assert(ipinfo.httpc = :excon) - end - - def test_set_adapter_v6 - ipinfo = IPinfo.create( - ENV['IPINFO_TOKEN'], - { http_client: :excon } - ) - ipinfo.initialize_v6 - - assert(ipinfo.httpc = :excon) - end - def assert_ip6(resp) assert_equal(resp.ip, TEST_IPV6) assert_equal(resp.ip_address, IPAddr.new(TEST_IPV6)) @@ -94,28 +71,6 @@ def assert_ip6(resp) ) end - def test_lookup_ip6 - ipinfo = IPinfo.create(ENV['IPINFO_TOKEN']) - - # multiple checks for cache - (0...5).each do |_| - resp = ipinfo.details(TEST_IPV6) - assert_ip6(resp) - end - end - - # # Requires IPv6 support - # def test_lookup_ip6_on_host_v6 - # ipinfo = IPinfo.create(ENV['IPINFO_TOKEN']) - # ipinfo.initialize_v6 - - # # multiple checks for cache - # (0...5).each do |_| - # resp = ipinfo.details(TEST_IPV6) - # assert_ip6(resp) - # end - # end - def assert_ip4(resp) assert_equal(resp.ip, TEST_IPV4) assert_equal(resp.ip_address, IPAddr.new(TEST_IPV4)) @@ -184,6 +139,50 @@ def assert_ip4(resp) refute_nil(resp.domains[:domains]) end + def test_that_it_has_a_version_number + refute_nil ::IPinfo::VERSION + end + + def test_set_adapter_v4 + ipinfo = IPinfo.create( + ENV['IPINFO_TOKEN'], + { http_client: :excon } + ) + + assert(ipinfo.httpc = :excon) + end + + def test_set_adapter_v6 + ipinfo = IPinfo.create( + ENV['IPINFO_TOKEN'], + { http_client: :excon } + ) + ipinfo.initialize_v6 + + assert(ipinfo.httpc = :excon) + end + + def test_lookup_ip6 + ipinfo = IPinfo.create(ENV['IPINFO_TOKEN']) + + # multiple checks for cache + (0...5).each do |_| + resp = ipinfo.details(TEST_IPV6) + assert_ip6(resp) + end + end + + # # Requires IPv6 support + # def test_lookup_ip6_on_host_v6 + # ipinfo = IPinfo.create(ENV['IPINFO_TOKEN']) + + # # multiple checks for cache + # (0...5).each do |_| + # resp = ipinfo.details_v6(TEST_IPV6) + # assert_ip6(resp) + # end + # end + def test_lookup_ip4 ipinfo = IPinfo.create(ENV['IPINFO_TOKEN']) @@ -197,11 +196,10 @@ def test_lookup_ip4 # # Requires IPv6 support # def test_lookup_ip4_on_host_v6 # ipinfo = IPinfo.create(ENV['IPINFO_TOKEN']) - # ipinfo.initialize_v6 # # multiple checks for cache # (0...5).each do |_| - # resp = ipinfo.details(TEST_IPV4) + # resp = ipinfo.details_v6(TEST_IPV4) # assert_ip4(resp) # end # end