Class: IPLookup::DB

Inherits:
Object
  • Object
show all
Defined in:
lib/ip_lookup/db.rb

Constant Summary collapse

DEFAULT_UPDATE_PERIOD_IN_DAYS =
30
DEFAULT_UPDATE_URI =
"https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(silent_exceptions) ⇒ DB

Returns a new instance of DB.



13
14
15
# File 'lib/ip_lookup/db.rb', line 13

def initialize(silent_exceptions)
  @silent_exceptions = silent_exceptions
end

Instance Attribute Details

#silent_exceptionsObject (readonly)

Returns the value of attribute silent_exceptions.



11
12
13
# File 'lib/ip_lookup/db.rb', line 11

def silent_exceptions
  @silent_exceptions
end

Class Method Details

.dbObject



25
26
27
28
29
30
31
# File 'lib/ip_lookup/db.rb', line 25

def db
  mutex.synchronize do
    @db ||= begin
      MaxMindDB.new full_db_path
    end
  end
end

.db_ageObject



84
85
86
# File 'lib/ip_lookup/db.rb', line 84

def db_age
  (Time.now - File.mtime(full_db_path)) / (24 * 60 * 60)
end

.db_exists?Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/ip_lookup/db.rb', line 80

def db_exists?
  File.file? full_db_path
end

.db_filenameObject



92
93
94
# File 'lib/ip_lookup/db.rb', line 92

def db_filename
  "/geolite-city.mmdb"
end

.db_pathObject



96
97
98
99
100
101
102
# File 'lib/ip_lookup/db.rb', line 96

def db_path
  if Gem.loaded_specs["ip_lookup"]
    File.join(Gem.loaded_specs["ip_lookup"].full_gem_path, "/support")
  else
    File.join(File.expand_path("../..", File.dirname(__FILE__)), "/support")
  end
end

.fetch_db(update_uri) ⇒ Object



43
44
45
46
47
48
49
50
51
# File 'lib/ip_lookup/db.rb', line 43

def fetch_db(update_uri)
  uri = URI(update_uri)

  response = Net::HTTP.get(uri)

  sio_response = StringIO.new(response)
  gz = Zlib::GzipReader.new(sio_response)
  gz.read
end

.flock(file) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ip_lookup/db.rb', line 63

def flock(file)
  # return and don't update db if file is locked, because db is already been updated
  return unless file.flock(File::LOCK_EX | File::LOCK_NB)

  if file.flock(File::LOCK_EX)
    begin
      yield file
    ensure
      file.flock(File::LOCK_UN)
    end
  end
end

.full_db_pathObject



88
89
90
# File 'lib/ip_lookup/db.rb', line 88

def full_db_path
  File.join(db_path, db_filename)
end

.mutexObject



33
34
35
# File 'lib/ip_lookup/db.rb', line 33

def mutex
  @mutex ||= Mutex.new
end

.save_db(result) ⇒ Object



53
54
55
56
57
58
59
60
61
# File 'lib/ip_lookup/db.rb', line 53

def save_db(result)
  Dir.mkdir(db_path) unless File.exist?(db_path)

  File.open(full_db_path, 'w') do |file|
    flock(file) do |f|
      f.write(result)
    end
  end
end

.update(update_period: DEFAULT_UPDATE_PERIOD_IN_DAYS, update_uri: DEFAULT_UPDATE_URI) ⇒ Object



37
38
39
40
41
# File 'lib/ip_lookup/db.rb', line 37

def update(update_period: DEFAULT_UPDATE_PERIOD_IN_DAYS, update_uri: DEFAULT_UPDATE_URI)
  return unless update_db? update_period

  save_db fetch_db(update_uri)
end

.update_db?(update_period) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/ip_lookup/db.rb', line 76

def update_db?(update_period)
  !db_exists? || (update_period >= 0 && db_age > update_period)
end

Instance Method Details

#lookup(ip_address) ⇒ Object



17
18
19
20
21
# File 'lib/ip_lookup/db.rb', line 17

def lookup(ip_address)
  self.class.db.lookup ip_address
rescue Errno::ENOENT
  raise DBFileNotFoundError, "Couldn't find DB file. Please update DB before using lookup." unless silent_exceptions
end