Class: Trackdown::Providers::MaxmindProvider
- Inherits:
-
BaseProvider
- Object
- BaseProvider
- Trackdown::Providers::MaxmindProvider
- Defined in:
- lib/trackdown/providers/maxmind_provider.rb
Overview
Provider that uses MaxMind GeoLite2 database for IP geolocation Requires the maxmind-db gem and a downloaded database file
Defined Under Namespace
Classes: DatabaseError, TimeoutError
Constant Summary collapse
- ACCURACY_RADIUS_CONFIDENCE_PERCENTAGE =
MaxMind publishes the accuracy radius as the radius, in kilometres, within which the address is likely to be, at a 67% confidence level: https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy
67
Class Method Summary collapse
-
.available?(request: nil) ⇒ Boolean
Check if MaxMind database is available.
-
.database_fingerprint ⇒ Object
The fingerprint used by the most recent successful reader fetch.
-
.locate(ip, request: nil) ⇒ LocationResult
Locate IP using MaxMind database.
- .provider_name ⇒ Object
- .provider_source ⇒ Object
-
.reset_database! ⇒ Object
Forget the open database.
Methods inherited from BaseProvider
get_country_name, get_emoji_flag, parse_coordinate, request_provenance
Class Method Details
.available?(request: nil) ⇒ Boolean
Check if MaxMind database is available
49 50 51 52 53 54 |
# File 'lib/trackdown/providers/maxmind_provider.rb', line 49 def available?(request: nil) return false unless maxmind_available? return false unless Trackdown.database_exists? true end |
.database_fingerprint ⇒ Object
The fingerprint used by the most recent successful reader fetch. Results do not read this global diagnostic: each one retains its reader-bound fingerprint, so concurrent generations can never mix provenance.
59 60 61 |
# File 'lib/trackdown/providers/maxmind_provider.rb', line 59 def database_fingerprint @fingerprint_mutex.synchronize { @database_fingerprint } end |
.locate(ip, request: nil) ⇒ LocationResult
Locate IP using MaxMind database
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/trackdown/providers/maxmind_provider.rb', line 83 def locate(ip, request: nil) raise Trackdown::Error, "MaxMind database not found" unless Trackdown.database_exists? raise Trackdown::Error, "maxmind-db gem not installed. Add it to your Gemfile: gem 'maxmind-db'" unless maxmind_available? lookup = fetch_record(ip) record = lookup.record fingerprint = lookup.fingerprint provenance = database_provenance(fingerprint) # We looked, in this exact database, and this address simply isn't in it. return LocationResult.unavailable(:address_not_found, **provenance) if record.nil? country_code = extract_country_code(record) country_name = extract_country_name(record) city = extract_city(record) flag_emoji = get_emoji_flag(country_code) accuracy_radius = record&.dig('location', 'accuracy_radius') LocationResult.new( country_code, country_name, city, flag_emoji, region: extract_region(record), region_code: record&.dig('subdivisions', 0, 'iso_code'), continent: record&.dig('continent', 'code'), timezone: record&.dig('location', 'time_zone'), latitude: record&.dig('location', 'latitude'), longitude: record&.dig('location', 'longitude'), postal_code: record&.dig('postal', 'code'), metro_code: record&.dig('location', 'metro_code')&.to_s, accuracy_radius_in_kilometers: accuracy_radius, accuracy_radius_confidence_percentage: (ACCURACY_RADIUS_CONFIDENCE_PERCENTAGE if accuracy_radius), **provenance ) end |
.provider_name ⇒ Object
40 41 42 |
# File 'lib/trackdown/providers/maxmind_provider.rb', line 40 def provider_name :maxmind end |
.provider_source ⇒ Object
44 45 46 |
# File 'lib/trackdown/providers/maxmind_provider.rb', line 44 def provider_source :maxmind_local_database end |
.reset_database! ⇒ Object
Forget the open database. Call this after replacing the .mmdb file so the next lookup opens the new one — Trackdown::DatabaseUpdater already does.
65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/trackdown/providers/maxmind_provider.rb', line 65 def reset_database! # Let go of the pool rather than shutting it down: a lookup already in # flight must not fail because a refresh happened underneath it. Ruby # reclaims the old readers once the last lookup lets go of them. @pool_mutex.synchronize do @reader_pool = nil @fingerprint_mutex.synchronize do @database_fingerprint = nil @database_fingerprints = {} end end nil end |