require 'csv' module JamRuby class MaxMindGeo < ActiveRecord::Base self.table_name = 'max_mind_geo' @@log = Logging.logger[MaxMindGeo] def self.import_from_max_mind(options) file = options[:file] use_copy = options[:use_copy] # File Geo-139 # Format: # startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode start = Time.now MaxMindGeo.delete_all if use_copy Database.copy(MaxMindGeo.table_name, file) else File.open(file, 'r:ISO-8859-1') do |io| s = io.gets.strip # eat the headers line unless s.eql? 'startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode' puts s puts 'startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode' raise 'file does not start with expected header (line 1): startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode' end saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0 count = 0 stmt = "insert into #{MaxMindGeo.table_name} (country,region,city,lat,lng,ip_start,ip_end) values" vals = '' sep = '' i = 0 n = 20 # going from 20 to 40 only changed things a little bit csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false}) csv.each do |row| raise "file does not have expected number of columns (10): #{row.length}" unless row.length == 10 ip_start = ip_address_to_int(strip_quotes(row[0])) ip_end = ip_address_to_int(strip_quotes(row[1])) country = row[2] region = row[3] city = row[4] #postalcode = row[5] lat = row[6] lng = row[7] #dmacode = row[8] #areacode = row[9] vals = vals+sep+"(#{quote_value(country, nil)},#{quote_value(region, nil)},#{quote_value(city, nil)},#{lat},#{lng},#{ip_start},#{ip_end})" sep = ',' i += 1 if count == 0 or i >= n then MaxMindGeo.connection.execute stmt+vals count += i vals = '' sep = '' i = 0 if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then ActiveRecord::Base.logger.debug "... logging inserts into #{MaxMindGeo.table_name} suspended ..." ActiveRecord::Base.logger.level = 1 end if ActiveRecord::Base.logger and count%10000 < n then ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.debug "... inserted #{count} into #{MaxMindGeo.table_name} ..." ActiveRecord::Base.logger.level = 1 end end end if i > 0 then MaxMindGeo.connection.execute stmt+vals count += i end if ActiveRecord::Base.logger then ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.debug "loaded #{count} records into #{MaxMindGeo.table_name}" end end end # User.find_each { |usr| usr.update_lat_lng } # THIS DOESNT ACTUALLY DO ANYTHING BECAUSE IT NEVER SAVES Band.find_each { |bnd| bnd.update_lat_lng } elapsed = Time.now - start @@log.debug("#{MaxMindGeo.table_name} import took #{elapsed} seconds") end def self.where_latlng(relation, params, current_user=nil) # this is only valid to call when relation is about bands distance = params[:distance].to_i if distance > 0 latlng = nil location_city = params[:city] location_state = params[:state] location_country = params[:country] remote_ip = params[:remote_ip] if location_city and location_state and location_country geo = self.where(city: location_city, region: location_state, countrycode: location_country).limit(1).first if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0) # it isn't reasonable for both to be 0... latlng = [geo.lat, geo.lng] end elsif current_user and current_user.locidispid and current_user.locidispid != 0 location = GeoIpLocations.find_by_locid(current_user.locidispid/1000000) if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0) # it isn't reasonable for both to be 0... latlng = [location.latitude, location.longitude] end elsif remote_ip geo = self.ip_lookup(remote_ip) if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0) # it isn't reasonable for both to be 0... latlng = [geo.lat, geo.lng] end end if latlng relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL']).within(distance, origin: latlng) end end relation end end end