ffi-geoip 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,68 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ module Base
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def release(ptr)
11
+ FFIGeoIP.GeoIP_delete(ptr)
12
+ end
13
+ end
14
+
15
+ def value_to_addr(value)
16
+ case value
17
+ when Numeric
18
+ GeoIP.num_to_addr(value)
19
+
20
+ when /^\d+\.\d+\.\d+\.\d+$/
21
+ value
22
+ end
23
+ end
24
+
25
+ private
26
+ def initialize_geoip(file, load_option = nil, check_cache = nil)
27
+ if load_option.nil?
28
+ load_option = :memory
29
+ end
30
+
31
+ flags = check_load_option(load_option) or
32
+ raise TypeError.new("the second option must be :memory, :filesystem, or :index")
33
+
34
+ if check_cache
35
+ flags |= GeoIPOptions[:check_cache]
36
+ end
37
+
38
+ if !File.exists?(file)
39
+ raise enoent_exception
40
+ else
41
+ @ptr = FFI::AutoPointer.new(
42
+ FFIGeoIP.GeoIP_open(file, flags),
43
+ self.class.method(:release)
44
+ )
45
+
46
+ if @ptr.null?
47
+ raise_enoent
48
+ end
49
+ end
50
+ end
51
+
52
+ def enoent_exception
53
+ Errno::ENOENT.new("Problem opening database")
54
+ end
55
+
56
+ def check_load_option(load_option)
57
+ case load_option
58
+ when :memory
59
+ GeoIP::GeoIPOptions[:memory_cache]
60
+ when :filesystem
61
+ GeoIP::GeoIPOptions[:standard]
62
+ when :index
63
+ GeoIP::GeoIPOptions[:index_cache]
64
+ end
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class City
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ record = Record.new(FFIGeoIP.GeoIP_record_by_addr(@ptr, addr))
17
+
18
+ if !record.null?
19
+ hash = record.to_h
20
+ FFIGeoIP.GeoIPRecord_delete(record)
21
+ hash
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class Country
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ fix_encoding(
17
+ :country_code => FFIGeoIP.GeoIP_country_code_by_addr(@ptr, addr),
18
+ :country_code3 => FFIGeoIP.GeoIP_country_code3_by_addr(@ptr, addr),
19
+ :country_name => FFIGeoIP.GeoIP_country_name_by_addr(@ptr, addr)
20
+ )
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class ISP
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ fix_encoding(:isp => FFIGeoIP.GeoIP_name_by_addr(@ptr, addr))
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class Organization
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ fix_encoding(:name => FFIGeoIP.GeoIP_name_by_addr(@ptr, addr))
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class Record < FFI::Struct
5
+ include Tools
6
+
7
+ layout(
8
+ :country_code, :string,
9
+ :country_code3, :string,
10
+ :country_name, :string,
11
+ :region, :string,
12
+ :city, :string,
13
+ :postal_code, :string,
14
+ :latitude, :float,
15
+ :longitude, :float,
16
+ :dma_code, :int,
17
+ :area_code, :int,
18
+ :charset, :int,
19
+ :continent_code, :string,
20
+ :country_conf, :uchar,
21
+ :region_conf, :uchar,
22
+ :city_conf, :uchar,
23
+ :postal_conf, :uchar,
24
+ :accuracy_radius, :int
25
+ )
26
+
27
+ HASH_KEYS = [
28
+ :country_code,
29
+ :country_code3,
30
+ :country_name,
31
+ :region,
32
+ :city,
33
+ :postal_code,
34
+ :latitude,
35
+ :longitude,
36
+ :dma_code,
37
+ :area_code
38
+ ].freeze
39
+
40
+ def to_h
41
+ hash = HASH_KEYS.each_with_object({}) do |key, memo|
42
+ memo[key] = self[key] unless self[key].nil?
43
+ end
44
+
45
+ if self[:region]
46
+ hash[:region_name] = FFIGeoIP.GeoIP_region_name_by_code(self[:country_code], self[:region])
47
+ end
48
+
49
+ fix_encoding(hash)
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ module Tools
5
+ private
6
+ def check_enum_value(enum, value)
7
+ enum[value] or
8
+ raise TypeError.new("Couldn't find valid #{enum.tag} value: #{value}")
9
+ end
10
+
11
+ def check_type(value, *types)
12
+ if !types.include?(value.class)
13
+ type_names = types.collect(&:name).join(' or ')
14
+
15
+ raise TypeError.new("wrong argument type #{value.class.name} (expected #{type_names})")
16
+ end
17
+ end
18
+
19
+ def fix_encoding(hash)
20
+ hash.each do |_, value|
21
+ value.encode!('UTF-8', 'ISO-8859-1') if value.is_a?(String)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ VERSION = "0.0.1"
5
+ end
6
+
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPCityTest < Minitest::Test
7
+ PITTSBURGH = {
8
+ :country_code => "US",
9
+ :country_code3 => "USA",
10
+ :country_name => "United States",
11
+ :region => "PA",
12
+ :city => "Pittsburgh",
13
+ :latitude => 40.44060134887695,
14
+ :longitude => -79.99590301513672,
15
+ :dma_code => 508,
16
+ :area_code => 412,
17
+ :region_name => "Pennsylvania"
18
+ }
19
+
20
+ PITTSBURGH_IP = '12.87.118.0'
21
+
22
+ def assert_look_up(db, expected = PITTSBURGH, lookup = PITTSBURGH_IP)
23
+ hash = db.look_up(lookup)
24
+ assert_kind_of(Hash, hash)
25
+ assert_equal(expected, hash)
26
+ end
27
+
28
+ def assert_raises_type_error(db)
29
+ assert_raises(TypeError) do
30
+ db.look_up(nil)
31
+ end
32
+ end
33
+
34
+ def test_construction_default
35
+ db = GeoIP::City.new(CITY_DB)
36
+ assert_raises_type_error(db)
37
+ assert_look_up(db)
38
+ end
39
+
40
+ def test_construction_index
41
+ db = GeoIP::City.new(CITY_DB, :index)
42
+ assert_raises_type_error(db)
43
+ assert_look_up(db)
44
+ end
45
+
46
+ def test_construction_filesystem
47
+ db = GeoIP::City.new(CITY_DB, :filesystem)
48
+ assert_raises_type_error(db)
49
+ assert_look_up(db)
50
+ end
51
+
52
+ def test_construction_memory
53
+ db = GeoIP::City.new(CITY_DB, :memory)
54
+ assert_raises_type_error(db)
55
+ assert_look_up(db)
56
+ end
57
+
58
+ def test_construction_filesystem_check
59
+ db = GeoIP::City.new(CITY_DB, :filesystem, true)
60
+ assert_raises_type_error(db)
61
+ assert_look_up(db)
62
+ end
63
+
64
+ def test_bad_db_file
65
+ assert_raises(Errno::ENOENT) do
66
+ GeoIP::City.new('/supposed-to-fail')
67
+ end
68
+ end
69
+
70
+ def test_character_encoding_converted_to_utf8_first
71
+ db = GeoIP::City.new(CITY_DB, :filesystem, true)
72
+ hash = db.look_up('89.160.20.112')
73
+ assert_equal('UTF-8', hash[:city].encoding.to_s)
74
+ assert_equal('Linköping', hash[:city])
75
+ end
76
+ end
77
+
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPCountryTest < Minitest::Test
7
+ UNITED_STATES = {
8
+ :country_code => "US",
9
+ :country_code3 => "USA",
10
+ :country_name => "United States"
11
+ }
12
+
13
+ UNITED_STATES_IP = '12.87.118.0'
14
+
15
+ def assert_look_up(db, expected = UNITED_STATES, lookup = UNITED_STATES_IP)
16
+ hash = db.look_up(lookup)
17
+ assert_kind_of(Hash, hash)
18
+ assert_equal(expected, hash)
19
+ end
20
+
21
+ def test_construction_default
22
+ db = GeoIP::Country.new(COUNTRY_DB)
23
+ assert_raises_type_error(db)
24
+ assert_look_up(db)
25
+ end
26
+
27
+ def test_construction_filesystem
28
+ db = GeoIP::Country.new(COUNTRY_DB, :filesystem)
29
+ assert_raises_type_error(db)
30
+ assert_look_up(db)
31
+ end
32
+
33
+ def test_construction_memory
34
+ db = GeoIP::Country.new(COUNTRY_DB, :memory)
35
+ assert_raises_type_error(db)
36
+ assert_look_up(db)
37
+ end
38
+
39
+ def test_construction_filesystem_check
40
+ db = GeoIP::Country.new(COUNTRY_DB, :filesystem, true)
41
+ assert_raises_type_error(db)
42
+ assert_look_up(db)
43
+ end
44
+
45
+ def test_bad_db_file
46
+ assert_raises(Errno::ENOENT) do
47
+ GeoIP::Country.new('/supposed-to-fail')
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,50 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPTest < Minitest::Test
7
+ def setup
8
+ @ip = "24.24.24.24"
9
+ @ipnum = 16777216 * 24 + 65536 * 24 + 256 * 24 + 24
10
+
11
+ @large_ip = "245.245.245.245"
12
+ @large_ipnum = 16777216 * 245 + 65536 * 245 + 256 * 245 + 245
13
+ end
14
+
15
+ def test_addr_to_num_converts_an_ip_to_an_ipnum
16
+ assert_equal @ipnum, GeoIP.addr_to_num(@ip)
17
+ end
18
+
19
+ def test_addr_to_num_converts_large_ips_to_an_ipnum_correctly
20
+ assert_equal @large_ipnum, GeoIP.addr_to_num(@large_ip)
21
+ end
22
+
23
+ def test_addr_to_num_expects_an_ip_string
24
+ assert_raises TypeError do
25
+ GeoIP.addr_to_num(nil)
26
+ end
27
+ end
28
+
29
+ def test_addr_to_num_returns_zero_for_an_illformed_ip_string
30
+ assert_equal 0, GeoIP.addr_to_num("foo.bar")
31
+ end
32
+
33
+ def test_num_to_addr_converts_an_ipnum_to_an_ip
34
+ assert_equal @ip, GeoIP.num_to_addr(@ipnum)
35
+ end
36
+
37
+ def test_num_to_addr_converts_large_ipnums_to_an_ip_correctly
38
+ assert_equal @large_ip, GeoIP.num_to_addr(@large_ipnum)
39
+ end
40
+
41
+ def test_num_to_addr_expects_a_numeric_ip
42
+ assert_raises TypeError do
43
+ GeoIP.num_to_addr(nil)
44
+ end
45
+ assert_raises TypeError do
46
+ GeoIP.num_to_addr("foo.bar")
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,54 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPISPTest < Minitest::Test
7
+ ISP = {
8
+ :isp => "AT&T Services"
9
+ }
10
+
11
+ ISP_IP = '12.87.118.0'
12
+
13
+ def assert_look_up(db, expected = ISP, lookup = ISP_IP)
14
+ hash = db.look_up(lookup)
15
+ assert_kind_of(Hash, hash)
16
+ assert_equal(expected, hash)
17
+ end
18
+
19
+ def test_construction_default
20
+ db = GeoIP::ISP.new(ISP_DB)
21
+ assert_raises_type_error(db)
22
+ assert_look_up(db)
23
+ end
24
+
25
+ # def test_construction_index
26
+ # db = GeoIP::ISP.new(ISP_DB, :index)
27
+ # assert_look_up(db, ISP_IP, :isp, 'Bell Aliant')
28
+ # end
29
+
30
+ def test_construction_filesystem
31
+ db = GeoIP::ISP.new(ISP_DB, :filesystem)
32
+ assert_raises_type_error(db)
33
+ assert_look_up(db)
34
+ end
35
+
36
+ def test_construction_memory
37
+ db = GeoIP::ISP.new(ISP_DB, :memory)
38
+ assert_raises_type_error(db)
39
+ assert_look_up(db)
40
+ end
41
+
42
+ def test_construction_filesystem_check
43
+ db = GeoIP::ISP.new(ISP_DB, :filesystem, true)
44
+ assert_raises_type_error(db)
45
+ assert_look_up(db)
46
+ end
47
+
48
+ def test_bad_db_file
49
+ assert_raises Errno::ENOENT do
50
+ GeoIP::ISP.new('/supposed-to-fail')
51
+ end
52
+ end
53
+ end
54
+