Skip to content

dkam/datacenter_detector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DatacenterDetector

The DatacenterDetector gem is no more. Below is a simple class to perform the same actions, but using a Redis cache via Kredis.

The following Ruby class is a slim wrapper around the IP Address API.

The number of hits and misses is also tracked.

A Working Cache

require 'kredis'
require 'open-uri'

class IpAddressApi
  # Outside of Rails, configure Kredis like: 
  #   Kredis::Connections.connections[:shared] = Redis.new(url: "redis://localhost:6379/0")
  attr_accessor :prefix, :agent, :cache_only, :ttl

  def initialize(prefix: IpAddressApi.prefix, agent: IpAddressApi.agent, cache_only: false, ttl: 60 * 60 * 24)
    @cache_only = cache_only
    @prefix     = prefix
    @agent      = agent
    @ttl        = ttl 
  end
  
  def key_name(ip) = "#{@prefix}#{ip}"
  def hit_counter  = @hit_counter  ||= Kredis.counter("#{prefix}hits")
  def miss_counter = @miss_counter ||= Kredis.counter("#{prefix}miss")
  
  def stats
    hit  = hit_counter.value
    miss = miss_counter.value

    {hit: hit, miss:, total: hit + miss}
  end

  def hitrate
    hit  = hit_counter.value
    miss = miss_counter.value
    
    hit / (hit + miss).to_f
  end

  def reset_stats
    hit_counter.reset
    miss_counter.reset
  end

  def lookup(ip=nil)
    return {} if ip.nil?

    ip_data = Kredis.json(key_name(ip), expires_in: ttl)
    
    if ip_data.value.blank? && cache_only == true
      miss!
    elsif ip_data.value.blank? && cache_only == false
      miss!
      ip_data.value = JSON.parse( URI.open("https://ipapi.is/json/?q=#{ip}", "User-Agent" => agent).read)
      ip_data.value ||= {}
    else
      hit!
    end

    return ip_data.value
  rescue OpenURI::HTTPError => e
    puts("IP Address API error looking up IP: #{ip} : #{e.inspect}")
    return {}
  end

  def self.prefix      = 'IpAddressApi_'
  def self.agent       = "Ruby/#{RUBY_VERSION}"
  def self.stats       = IpAddressApi.new.stats
  def self.reset_stats = IpAddressApi.new.reset_stats
  def self.hitrate     = IpAddressApi.new.hit_rate

  def self.lookup(ip=nil, cache_only: false, agent: nil) = IpAddressApi.new(cache_only:, agent:).lookup(ip)

  private
  def hit!         = hit_counter.increment
  def miss!        = miss_counter.increment
end

Usage

You can use an instance or class methods.

> result = IpAddressApi.lookup('1.1.1.1')
> result.dig('is_datacenter')
=> false
> result.dig('company', 'name')
=> "APNIC Research and Development"
> result.dig('asn', 'org')
=> "Cloudflare, Inc."

> client = IpAddressApi.new
> client.lookup('52.93.127.126')
> result.is_datacenter
=> true
> result.name
=> "Amazon Technologies Inc."

The cache records its hitrate:

```ruby
> client.hitrate
=> 0.6829268292682927

License

The gem is available as open source under the terms of the MIT License.

About

Detect Datacenter by IP

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages