185 lines
6.3 KiB
Ruby
185 lines
6.3 KiB
Ruby
class MaxMindManager < BaseManager
|
|
|
|
def initialize(options={})
|
|
super(options)
|
|
end
|
|
|
|
|
|
# Returns a hash with location information. Fields are nil if they can't be figured.
|
|
# This is a class method because it doesn't need to be in a transaction.
|
|
def self.lookup(ip_address)
|
|
|
|
city = state = country = nil
|
|
locid = ispid = 0
|
|
|
|
unless ip_address.nil? || ip_address !~ /^\d+\.\d+\.\d+\.\d+$/
|
|
#ActiveRecord::Base.connection_pool.with_connection do |connection|
|
|
# pg_conn = connection.instance_variable_get("@connection")
|
|
# ip_as_int = ip_address_to_int(ip_address)
|
|
# pg_conn.exec("SELECT country, region, city FROM max_mind_geo WHERE ip_start <= $1 AND $2 <= ip_end limit 1", [ip_as_int, ip_as_int]) do |result|
|
|
# if !result.nil? && result.ntuples > 0
|
|
# country = result[0]['country']
|
|
# state = result[0]['region']
|
|
# city = result[0]['city']
|
|
# end
|
|
# end
|
|
#end
|
|
|
|
addr = ip_address_to_int(ip_address)
|
|
|
|
block = GeoIpBlocks.lookup(addr)
|
|
if block
|
|
locid = block.locid
|
|
|
|
location = GeoIpLocations.lookup(locid)
|
|
if location
|
|
# todo translate countrycode to country, region(code) to region
|
|
country = location.countrycode
|
|
state = location.region
|
|
city = location.city
|
|
end
|
|
end
|
|
|
|
isp = JamIsp.lookup(addr)
|
|
if isp
|
|
ispid = isp.coid
|
|
end
|
|
end
|
|
|
|
{city: city, state: state, country: country, addr: addr, locidispid: locid*1000000+ispid}
|
|
end
|
|
|
|
def self.lookup_isp(ip_address)
|
|
|
|
isp = nil
|
|
|
|
unless ip_address.nil? || ip_address !~ /^\d+\.\d+\.\d+\.\d+$/
|
|
ActiveRecord::Base.connection_pool.with_connection do |connection|
|
|
pg_conn = connection.instance_variable_get("@connection")
|
|
ip_as_int = ip_address_to_int(ip_address)
|
|
pg_conn.exec("SELECT isp FROM max_mind_isp WHERE ip_bottom <= $1 AND $2 <= ip_top limit 1", [ip_as_int, ip_as_int]) do |result|
|
|
if !result.nil? && result.ntuples > 0
|
|
isp = result.getvalue(0, 0)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return isp
|
|
end
|
|
|
|
def self.countries()
|
|
#ActiveRecord::Base.connection_pool.with_connection do |connection|
|
|
# pg_conn = connection.instance_variable_get("@connection")
|
|
# pg_conn.exec("SELECT DISTINCT country FROM max_mind_geo ORDER BY country ASC").map do |tuple|
|
|
# tuple["country"]
|
|
# end
|
|
#end
|
|
|
|
raise "no longer supported, use countriesx"
|
|
|
|
# returns ordered array of Country objects (countrycode, countryname)
|
|
#Country.get_all.map { |c| c.countrycode }
|
|
end
|
|
|
|
def self.countriesx()
|
|
#ActiveRecord::Base.connection_pool.with_connection do |connection|
|
|
# pg_conn = connection.instance_variable_get("@connection")
|
|
# pg_conn.exec("SELECT DISTINCT country FROM max_mind_geo ORDER BY country ASC").map do |tuple|
|
|
# tuple["country"]
|
|
# end
|
|
#end
|
|
|
|
# returns ordered array of Country objects (countrycode, countryname)
|
|
Country.get_all.map { |c| {countrycode: c.countrycode, countryname: c.countryname} }
|
|
end
|
|
|
|
|
|
def self.regions(country)
|
|
#ActiveRecord::Base.connection_pool.with_connection do |connection|
|
|
# pg_conn = connection.instance_variable_get("@connection")
|
|
# pg_conn.exec("SELECT DISTINCT region FROM max_mind_geo WHERE country = $1 ORDER BY region ASC", [country]).map do |tuple|
|
|
# tuple["region"]
|
|
# end
|
|
#end
|
|
|
|
# returns an ordered array of Region objects (region, regionname, countrycode)
|
|
Region.get_all(country).map { |r| r.region }
|
|
end
|
|
|
|
|
|
def self.cities(country, region)
|
|
#ActiveRecord::Base.connection_pool.with_connection do |connection|
|
|
# pg_conn = connection.instance_variable_get("@connection")
|
|
# pg_conn.exec("SELECT DISTINCT city FROM max_mind_geo WHERE country = $1 AND region = $2 ORDER BY city ASC", [country, region]).map do |tuple|
|
|
# tuple["city"]
|
|
# end
|
|
#end
|
|
|
|
# returns an ordered array of City (city, region, countrycode)
|
|
City.get_all(country, region).map { |c| c.city }
|
|
end
|
|
|
|
|
|
def self.isps(country)
|
|
ActiveRecord::Base.connection_pool.with_connection do |connection|
|
|
pg_conn = connection.instance_variable_get("@connection")
|
|
pg_conn.exec("SELECT DISTINCT isp FROM max_mind_isp WHERE country = $1 ORDER BY isp ASC", [country]).map do |tuple|
|
|
tuple["isp"]
|
|
end
|
|
end
|
|
end
|
|
|
|
# Note that there's one big country, and then two cities in each region.
|
|
def create_phony_database()
|
|
clear_location_table
|
|
(0..255).each do |top_octet|
|
|
@pg_conn.exec("INSERT INTO max_mind_geo (ip_start, ip_end, country, region, city, lat, lng) VALUES ($1, $2, $3, $4, $5, 0, 0)",
|
|
[
|
|
self.class.ip_address_to_int("#{top_octet}.0.0.0"),
|
|
self.class.ip_address_to_int("#{top_octet}.255.255.255"),
|
|
"US",
|
|
['AB', 'BC', 'CD', 'DE'][top_octet % 4],
|
|
"City #{top_octet}"
|
|
]).clear
|
|
end
|
|
|
|
clear_isp_table
|
|
(0..255).each do |top_octet|
|
|
@pg_conn.exec("INSERT INTO max_mind_isp (ip_bottom, ip_top, isp, country) VALUES ($1, $2, $3, $4)",
|
|
[
|
|
self.class.ip_address_to_int("#{top_octet}.0.0.0"),
|
|
self.class.ip_address_to_int("#{top_octet}.255.255.255"),
|
|
"ISP #{top_octet}",
|
|
"US"
|
|
]).clear
|
|
end
|
|
|
|
@pg_conn.exec "DELETE FROM cities"
|
|
@pg_conn.exec "INSERT INTO cities (city, region, countrycode) SELECT DISTINCT city, region, country FROM max_mind_geo"
|
|
|
|
@pg_conn.exec "DELETE FROM regions"
|
|
@pg_conn.exec "INSERT INTO regions (region, regionname, countrycode) select distinct region, region, countrycode from cities"
|
|
|
|
@pg_conn.exec "DELETE FROM countries"
|
|
@pg_conn.exec "INSERT INTO countries (countrycode, countryname) SELECT DISTINCT countrycode, countrycode FROM regions"
|
|
end
|
|
|
|
private
|
|
|
|
# Make an IP address into an int (bigint)
|
|
def self.ip_address_to_int(ip)
|
|
ip.split('.').inject(0) {|total,value| (total << 8 ) + value.to_i}
|
|
end
|
|
|
|
def clear_location_table
|
|
@pg_conn.exec("DELETE FROM max_mind_geo").clear
|
|
end
|
|
|
|
def clear_isp_table
|
|
@pg_conn.exec("DELETE FROM max_mind_isp").clear
|
|
end
|
|
|
|
end
|
|
|