geoipdb 0.5.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -8
- data/.ruby-version +1 -0
- data/Gemfile +1 -3
- data/Makefile +10 -0
- data/README.md +2 -5
- data/Rakefile +0 -13
- data/geoipdb.gemspec +5 -12
- data/lib/geoipdb.jar +0 -0
- data/lib/geoipdb.rb +224 -5
- data/sample_data/ip_ranges.csv +2 -2
- data/spec/geoipdb_spec.rb +8 -43
- data/spec/spec_helper.rb +10 -7
- data/{ext/geoipdb/src → src}/City.java +0 -0
- data/{ext/geoipdb/src → src}/CsvReader.java +0 -0
- data/src/IPDB.java +66 -0
- data/{ext/geoipdb/src → src}/IpRange.java +21 -7
- metadata +30 -38
- data/ext/geoipdb/extconf.rb +0 -3
- data/ext/geoipdb/geoipdb.c +0 -107
- data/ext/geoipdb/ipdb.c +0 -668
- data/ext/geoipdb/ipdb.h +0 -84
- data/ext/geoipdb/src/GeoIpDb.java +0 -101
- data/lib/cgeoipdb.rb +0 -1
- data/lib/ip_information.rb +0 -27
- data/lib/jgeoipdb.rb +0 -41
- data/sample_data/citiess_corrupt.csv +0 -8
- data/sample_data/ip_ranges_corrupt.csv +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a9d74eeb52c1411ef3b7615bdab98fa6ed21550
|
4
|
+
data.tar.gz: e496789447d83354ca3bb9305361cb836aef0671
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e85f35fbdd49016fa40b71be6a31ea14ed80dcdc75baaadc39124b43afa7f8f5df196851f8be3d1ac18fa3e37d473704bbca6440bb2a204c77f41a0744f368b
|
7
|
+
data.tar.gz: 842b770d73b5e0f054688f3bd45448c04a925a60c3b18ae5aa6324af1a67f352a84070e474f4b95c6e6755eb7a87ff9b738f1fb0300eadd13ef556e0d5f20480
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
jruby
|
data/Gemfile
CHANGED
data/Makefile
ADDED
data/README.md
CHANGED
@@ -1,9 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# GeoIPDB
|
2
2
|
|
3
|
-
Fast
|
4
|
-
|
5
|
-
* Returns a GeoLocation and additional information for a given IP.
|
6
|
-
* Reads Data from CSV-Files and uses internal binary caching.
|
3
|
+
Fast GeoIPDB implementation for JRuby.
|
7
4
|
|
8
5
|
[](http://badge.fury.io/rb/geoipdb)
|
9
6
|
[](http://travis-ci.org/liquidm/geoipdb)
|
data/Rakefile
CHANGED
@@ -1,16 +1,3 @@
|
|
1
1
|
require "bundler/setup"
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
require "liquid/tasks"
|
4
|
-
|
5
|
-
case RUBY_PLATFORM
|
6
|
-
when 'java'
|
7
|
-
require 'rake/javaextensiontask'
|
8
|
-
Rake::JavaExtensionTask.new('geoipdb')
|
9
|
-
else
|
10
|
-
require 'rake/extensiontask'
|
11
|
-
Rake::ExtensionTask.new('geoipdb')
|
12
|
-
end
|
13
|
-
|
14
|
-
task :default => [:spec]
|
15
|
-
task :build => :compile
|
16
|
-
task :spec => :compile
|
data/geoipdb.gemspec
CHANGED
@@ -2,25 +2,18 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "geoipdb"
|
5
|
-
spec.version = "0.
|
5
|
+
spec.version = "1.0.0"
|
6
6
|
spec.authors = ["LiquidM, Inc."]
|
7
7
|
spec.email = ["opensource@liquidm.com"]
|
8
|
-
spec.description = "Fast
|
9
|
-
spec.summary = "Fast
|
8
|
+
spec.description = "Fast IPDB implementation for JRuby"
|
9
|
+
spec.summary = "Fast IPDB implementation for JRuby"
|
10
10
|
spec.homepage = "http://github.com/liquidm/geoipdb"
|
11
11
|
spec.licenses = ["MIT"]
|
12
12
|
|
13
13
|
spec.files = `git ls-files`.split($/)
|
14
14
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
15
15
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
|
-
spec.require_paths = ["lib"
|
16
|
+
spec.require_paths = ["lib"]
|
17
17
|
|
18
|
-
|
19
|
-
spec.platform = "java"
|
20
|
-
spec.files << "lib/geoipdb.jar"
|
21
|
-
else
|
22
|
-
spec.extensions = ["ext/geoipdb/extconf.rb"]
|
23
|
-
end
|
24
|
-
|
25
|
-
spec.add_development_dependency "rake-compiler"
|
18
|
+
spec.add_dependency "liquid-ext"
|
26
19
|
end
|
data/lib/geoipdb.jar
ADDED
Binary file
|
data/lib/geoipdb.rb
CHANGED
@@ -1,7 +1,226 @@
|
|
1
|
-
require '
|
1
|
+
require 'liquid/boot'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'singleton'
|
6
|
+
require 'uri'
|
7
|
+
require 'zlib'
|
8
|
+
|
9
|
+
java_import 'java.lang.NumberFormatException'
|
10
|
+
java_import 'java.net.InetAddress'
|
11
|
+
|
12
|
+
require File.expand_path('../geoipdb.jar', __FILE__)
|
13
|
+
|
14
|
+
class IPDB
|
15
|
+
include Singleton
|
16
|
+
|
17
|
+
attr_accessor :base_url
|
18
|
+
|
19
|
+
DATA_FILES = [
|
20
|
+
'cities.csv',
|
21
|
+
'ip_ranges.csv',
|
22
|
+
]
|
23
|
+
|
24
|
+
class IPDBError < Exception
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.init(base_url)
|
28
|
+
instance.update!(base_url)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.lookup(ip)
|
32
|
+
instance.lookup(ip)
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@version = Gem.loaded_specs['geoipdb'].version.to_s
|
37
|
+
@cache_path = File.expand_path("~/.cache/geoipdb/v#{@version}")
|
38
|
+
# by default load sample data
|
39
|
+
sample_path = File.expand_path('../../sample_data', __FILE__)
|
40
|
+
files = DATA_FILES.map { |file_name| File.join(sample_path, file_name) }
|
41
|
+
self.load(*files)
|
42
|
+
end
|
43
|
+
|
44
|
+
def load(*files)
|
45
|
+
@db = Java::IPDB.new(*files)
|
46
|
+
end
|
47
|
+
|
48
|
+
def update!(base_url)
|
49
|
+
return nil if @initialized
|
50
|
+
@start = Time.now.to_f
|
51
|
+
@base_url = base_url
|
52
|
+
@initialized = true
|
53
|
+
|
54
|
+
$log.info("ipdb:load", cache_path: @cache_path)
|
55
|
+
FileUtils.mkdir_p(@cache_path)
|
56
|
+
|
57
|
+
@updating = false
|
58
|
+
if !uptodate?
|
59
|
+
@updating = true
|
60
|
+
$log.info("ipdb:init", update: true)
|
61
|
+
download_update
|
62
|
+
end
|
63
|
+
|
64
|
+
load_data_files
|
65
|
+
end
|
66
|
+
|
67
|
+
def load_data_files
|
68
|
+
files = DATA_FILES.map { |file_name| File.join(@cache_path, file_name) }
|
69
|
+
self.load(*files)
|
70
|
+
self_test
|
71
|
+
make_backup if @updating
|
72
|
+
$log.info("ipdb:init", rt: Time.now.to_f - @start)
|
73
|
+
rescue IPDBError => e
|
74
|
+
$log.exception(e)
|
75
|
+
$log.info("ipdb:init", revert: true)
|
76
|
+
restore_backup
|
77
|
+
load_data_files
|
78
|
+
self_test
|
79
|
+
end
|
80
|
+
|
81
|
+
def lookup(ip)
|
82
|
+
return nil unless @db
|
83
|
+
ip = InetAddress.get_by_name(ip).address if ip.is_a?(String)
|
84
|
+
range = @db.find_range_for_ip(ip)
|
85
|
+
return nil unless range
|
86
|
+
city = @db.find_city_for_ip_range(range)
|
87
|
+
return nil unless city
|
88
|
+
isp = range.isp_name
|
89
|
+
info = IpInformation.new
|
90
|
+
info.country_iso_code = city.country_iso2
|
91
|
+
info.city_name = city.name
|
92
|
+
info.city_code = city.city_code
|
93
|
+
info.lng = city.lng
|
94
|
+
info.lat = city.lat
|
95
|
+
info.is_mobile = range.is_mobile
|
96
|
+
info.isp_name = isp && isp.to_sym
|
97
|
+
info
|
98
|
+
rescue EncodingError, NumberFormatException
|
99
|
+
# TODO: do we really want to silence these exceptions?
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def uptodate?
|
106
|
+
days14 = 24*60*60*14 # 14days
|
107
|
+
now = Time.now.to_f
|
108
|
+
|
109
|
+
DATA_FILES.each do |file_name|
|
110
|
+
path = File.join(@cache_path, file_name)
|
111
|
+
if !File.exist?(path)
|
112
|
+
$log.info("ipdb:check", result: false, file: file_name, reason: "#{path} does not exist")
|
113
|
+
return false
|
114
|
+
elsif File.stat(path).ctime.to_f + days14 < now
|
115
|
+
$log.info("ipdb:check", result: false, file: file_name, reason: "#{path} is too old - needs update!")
|
116
|
+
return false
|
117
|
+
else
|
118
|
+
$log.info("ipdb:check", result: true, file: file_name)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
return true
|
122
|
+
end
|
123
|
+
|
124
|
+
def download_update
|
125
|
+
DATA_FILES.each do |file_name|
|
126
|
+
download(file_name)
|
127
|
+
unzip(file_name)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def download(file_name)
|
132
|
+
$log.info("ipdb:download", file: file_name)
|
133
|
+
file_name = "#{file_name}.gz"
|
134
|
+
source = URI.parse("#{@base_url}/#{file_name}")
|
135
|
+
dest = "#{@cache_path}/#{file_name}"
|
136
|
+
File.write(dest, source.read)
|
137
|
+
end
|
138
|
+
|
139
|
+
def unzip(file_name)
|
140
|
+
$log.info("ipdb:unzip", file: file_name)
|
141
|
+
source = File.join(@cache_path, "#{file_name}.gz")
|
142
|
+
dest = File.join(@cache_path, file_name)
|
143
|
+
Zlib::GzipReader.open(source) do |gz|
|
144
|
+
File.write(dest, gz.read)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def make_backup
|
149
|
+
DATA_FILES.each do |file_name|
|
150
|
+
path = File.join(@cache_path, file_name)
|
151
|
+
backup_path = File.join(@cache_path, "#{file_name}.backup")
|
152
|
+
next unless File.exists?(path)
|
153
|
+
$log.info("ipdb:backup", path: path, backup_path: backup_path)
|
154
|
+
FileUtils.cp(path, backup_path)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def restore_backup
|
159
|
+
DATA_FILES.each do |file_name|
|
160
|
+
path = File.join(@cache_path, file_name)
|
161
|
+
backup_path = File.join(@cache_path, "#{file_name}.backup")
|
162
|
+
if File.exists?(backup_path)
|
163
|
+
$log.info("ipdb:restore", backup_path: backup_path, path: path)
|
164
|
+
FileUtils.cp(backup_path, path)
|
165
|
+
else
|
166
|
+
$log.error("ipdb:restore", reason: "#{backup_path} does not exist")
|
167
|
+
return false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
return true
|
171
|
+
end
|
172
|
+
|
173
|
+
def self_test
|
174
|
+
{
|
175
|
+
'10.0.0.1' => '--',
|
176
|
+
'127.0.0.1' => '--',
|
177
|
+
'192.168.1.1' => '--',
|
178
|
+
'93.219.159.76' => 'de',
|
179
|
+
'91.44.76.101' => 'de',
|
180
|
+
'82.113.100.1' => 'de',
|
181
|
+
'84.1.10.4' => 'hu',
|
182
|
+
'83.23.11.5' => 'pl',
|
183
|
+
'52.13.100.1' => 'us',
|
184
|
+
}.each do |ip, country|
|
185
|
+
result = lookup(ip)
|
186
|
+
next if country == result.country_iso_code
|
187
|
+
raise IPDBError.new("IPDB selftest FAILED! IP lookup failed: #{ip} should be #{country} but was #{result.country_iso_code}.")
|
188
|
+
end
|
189
|
+
return true
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
class IpInformation
|
195
|
+
|
196
|
+
ATTRIBS = [
|
197
|
+
:country_iso_code,
|
198
|
+
:city_code,
|
199
|
+
:city_name,
|
200
|
+
:lat,
|
201
|
+
:lng,
|
202
|
+
:is_mobile,
|
203
|
+
:isp_name,
|
204
|
+
]
|
205
|
+
|
206
|
+
ATTRIBS.each do |attrib|
|
207
|
+
attr_accessor attrib
|
208
|
+
end
|
209
|
+
|
210
|
+
def initialize(attribs = {})
|
211
|
+
attribs.each do |key, value|
|
212
|
+
send("#{key}=", value)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def mobile?
|
217
|
+
@is_mobile
|
218
|
+
end
|
219
|
+
|
220
|
+
def to_h
|
221
|
+
Hash[ATTRIBS.map do |attrib|
|
222
|
+
[attrib, send(attrib)]
|
223
|
+
end]
|
224
|
+
end
|
2
225
|
|
3
|
-
if defined?(JRUBY_VERSION)
|
4
|
-
require 'jgeoipdb'
|
5
|
-
else
|
6
|
-
require 'cgeoipdb'
|
7
226
|
end
|
data/sample_data/ip_ranges.csv
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
start_ip,end_ip,
|
1
|
+
start_ip,end_ip,conn-speed,city-code,isp-name
|
2
2
|
0.0.0.0,0.0.0.255,mobile,0,?
|
3
3
|
0.0.1.0,0.255.255.255,mobile,1,asdf,
|
4
4
|
1.0.0.0,1.0.0.255,xdsl,2,vodafone
|
5
5
|
1.0.1.0,1.1.0.255,wireless,3,?
|
6
|
-
1.1.1.0,1.1.1.255,mobile,4,
|
6
|
+
1.1.1.0,1.1.1.255,mobile,4,o2
|
7
7
|
1.1.2.0,1.2.2.255,mobile,5,?
|
8
8
|
1.2.3.0,1.2.3.255,mobile,5,?
|
9
9
|
1.2.4.0,1.3.255.255,mobile,2,?
|
data/spec/geoipdb_spec.rb
CHANGED
@@ -1,38 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require 'geoipdb'
|
2
2
|
|
3
|
-
|
4
|
-
describe GeoIpDb do
|
5
|
-
|
6
|
-
CACHE_FILE = 'sample_data/ipdb.cache'
|
7
|
-
|
8
|
-
def init_db
|
9
|
-
@db = GeoIpDb.init './sample_data/cities.csv', './sample_data/ip_ranges.csv', CACHE_FILE
|
10
|
-
end
|
11
|
-
|
12
|
-
it "should not throw an exception fault if data is corrupt" do
|
13
|
-
@db = GeoIpDb.init './sample_data/cities_corrupt.csv', './sample_data/ip_ranges_corrupt.csv', CACHE_FILE
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should not init a db object if data files are missing" do
|
17
|
-
GeoIpDb.init( './sample_data/bla.csv', './sample_data/blubb.csv', CACHE_FILE ).should be_nil
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should init correctly with sample data" do
|
21
|
-
init_db
|
22
|
-
@db.should_not be_nil
|
23
|
-
end
|
24
|
-
|
25
|
-
unless defined? JRUBY_VERSION
|
26
|
-
it "initializes cache_file correctly with sample data" do
|
27
|
-
init_db
|
28
|
-
File.exist?(CACHE_FILE).should be_true
|
29
|
-
end
|
30
|
-
end
|
3
|
+
describe IPDB do
|
31
4
|
|
32
5
|
it "sould find the sample cities correcty" do
|
33
|
-
|
34
|
-
#afg,no region,kabul,-1,3,34.5167,69.1833
|
35
|
-
info = @db.information_for_ip "1.1.0.254"
|
6
|
+
info = IPDB.lookup "1.1.0.254"
|
36
7
|
info.city_code.should == 3
|
37
8
|
info.city_name.should == 'kabul'
|
38
9
|
info.country_iso_code.should == 'af'
|
@@ -42,20 +13,14 @@ describe GeoIpDb do
|
|
42
13
|
end
|
43
14
|
|
44
15
|
it 'should return correct is_mobile information' do
|
45
|
-
|
46
|
-
|
47
|
-
@db.information_for_ip("1.1.1.1").should be_mobile
|
16
|
+
IPDB.lookup("1.0.0.1").should_not be_mobile
|
17
|
+
IPDB.lookup("1.1.1.1").should be_mobile
|
48
18
|
end
|
49
19
|
|
50
20
|
it 'should return correct isp_name in ip_information' do
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@db.information_for_ip("1.2.1.1").isp_name.should == :"?"
|
55
|
-
end
|
56
|
-
|
57
|
-
after :each do
|
58
|
-
File.unlink CACHE_FILE if File.exist? CACHE_FILE
|
21
|
+
IPDB.lookup("1.0.0.1").isp_name.should == :vodafone
|
22
|
+
IPDB.lookup("1.1.1.1").isp_name.should == :o2
|
23
|
+
IPDB.lookup("1.2.1.1").isp_name.should == :"?"
|
59
24
|
end
|
60
25
|
|
61
26
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
-
|
2
|
-
require 'rspec'
|
1
|
+
ROOT = File.expand_path('../..', __FILE__)
|
3
2
|
|
4
|
-
require '
|
5
|
-
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'liquid/boot'
|
6
5
|
|
7
|
-
|
8
|
-
$:.unshift(File.dirname(__FILE__) + '/../ext')
|
9
|
-
require 'geoipdb'
|
6
|
+
require 'rspec'
|
10
7
|
|
8
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
11
9
|
RSpec.configure do |config|
|
10
|
+
# Run specs in random order to surface order dependencies. If you find an
|
11
|
+
# order dependency and want to debug it, you can fix the order by providing
|
12
|
+
# the seed, which is printed after each run.
|
13
|
+
# --seed 1234
|
14
|
+
config.order = 'random'
|
12
15
|
end
|