mtodd-geoip 0.5.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.
Files changed (6) hide show
  1. data/README.md +105 -0
  2. data/Rakefile +52 -0
  3. data/extconf.rb +9 -0
  4. data/geoip.c +233 -0
  5. data/test.rb +59 -0
  6. metadata +59 -0
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ Ruby GeoIP Bindings
2
+ =======================
3
+
4
+ What?
5
+ -----
6
+
7
+ This is a library which provides a single function. The function takes as
8
+ input an IP address and it outputs a hash containing best-guess geographical
9
+ information (like city, country, latitude, and longitude).
10
+
11
+ Actually this is only a Ruby binding to a C library which provides this
12
+ function. Also, you must download a large binary database with all this
13
+ mapping information. It is kindly provided free of charge by MaxMind.com.
14
+
15
+ Usage
16
+
17
+ require 'geoip'
18
+ db = GeoIP::City::Database.new('/opt/GeoIP/share/GeoIP/GeoLiteCity.dat')
19
+ result = db.look_up('24.24.24.24')
20
+ p result
21
+ # => {:city=>"Ithaca",
22
+ # :latitude=>42.4277992248535,
23
+ # :longitude=>-76.4981994628906,
24
+ # :country_code3=>"USA",
25
+ # :country_code=>"US",
26
+ # :country_name=>"United States",
27
+ # :dma_code=>555,
28
+ # :area_code=>607,
29
+ # :region=>"NY" }
30
+
31
+ There are arguments to database initializer.
32
+
33
+ 1. The first argument is the filename of the GeoIPCity.dat file
34
+
35
+ 2. The second argument (optional) is to specify how GeoIP should
36
+ keep the database in memory. There are three possibilities
37
+
38
+ * `:filesystem` -- Read database from filesystem, uses least memory.
39
+
40
+ * `:index` -- The most frequently accessed index portion of the
41
+ database, resulting in faster lookups than :filesystem, but less
42
+ memory usage than :memory.
43
+
44
+ * `:memory` -- (Default.) Load database into memory, faster performance but uses more memory.
45
+
46
+ 3. The third argument is boolean and decides whether the system should
47
+ reload the database if changes are made to the dat file. (You probably
48
+ don't need this. Default: false.)
49
+
50
+ For example
51
+
52
+ GeoIPCity::Database.new(dbfile, :filesystem, true)
53
+
54
+
55
+ Install
56
+ -------
57
+
58
+ Some variation of the following should work.
59
+
60
+ 1. Install the GeoCity C library. You can get it from
61
+ [maxmind](http://www.maxmind.com/app/c).
62
+ For example, I like to install mine in `/opt/GeoIP`, so I do this:
63
+
64
+ tar -zxvf GeoIP-1.4.3.tar.gz
65
+
66
+ cd GeoIP-1.4.3
67
+
68
+ ./configure --prefix=/opt/GeoIP
69
+
70
+ make && sudo make install
71
+
72
+ 2. Now install the `geoip_city` gem
73
+
74
+ sudo gem install geoip_city -- --with-geoip-dir=/opt/GeoIP
75
+
76
+ 3. Download the GeoLite City database file in binary format at http://www.maxmind.com/app/geolitecity
77
+ Maybe this [direct link](http://www.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz) will work.
78
+ I put this file in
79
+
80
+ /opt/GeoIP/share/GeoIP/GeoLiteCity.dat
81
+
82
+ 4. Use it!
83
+
84
+ Hints
85
+ -----
86
+
87
+ 1. Might need to set
88
+
89
+ export ARCHFLAGS="-arch i386"
90
+
91
+ to be able to compile the gem.
92
+
93
+ Example:
94
+
95
+ sudo env ARCHFLAGS="-arch i386" gem install geoip_city -- --with-geoip-dir=/opt/GeoIP
96
+
97
+ 2. You might find [this shell
98
+ script](http://github.com/grimen/my_shell_scripts/blob/8cf04cb6829e68a47f2d6f9d9e057766ea72beb4/install_geoip-city.sh)
99
+ helpful to install the C library.
100
+
101
+ License
102
+ -------
103
+ Copyright (C) 2007--2009 Ryan Dahl (ry@tinyclouds.org), Matt Todd (mtodd@highgroove.com)
104
+
105
+ I give permission for you to do whatever you'd like to do with this software.
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+
7
+ task :default => [:compile, :test]
8
+
9
+ CLEAN.add "geoip.{o,bundle,so,obj,pdb,lib,def,exp}"
10
+ CLOBBER.add ['Makefile', 'mkmf.log','doc']
11
+
12
+ Rake::RDocTask.new do |rdoc|
13
+ rdoc.rdoc_files.add ['README', 'geoip.c']
14
+ rdoc.main = "README" # page to start on
15
+ rdoc.rdoc_dir = 'doc/' # rdoc output folder
16
+ end
17
+
18
+ Rake::TestTask.new do |t|
19
+ t.test_files = 'test.rb'
20
+ t.verbose = true
21
+ end
22
+
23
+ spec = Gem::Specification.new do |s|
24
+ s.name = 'geoip'
25
+ s.description = 'Generic GeoIP lookup tool. Based on the geoip_city RubyGem by Ryan Dahl'
26
+ s.author = 'Matt Todd'
27
+ s.email = 'mtodd@highgroove.com'
28
+ s.version = "0.5.0"
29
+ s.summary = "A Binding to the GeoIP C library"
30
+ s.homepage = "http://github.com/mtodd/geoip"
31
+ s.files = FileList['Rakefile', '*.rb', '*.c', 'README*']
32
+ s.test_files = 'test.rb'
33
+ s.extensions = 'extconf.rb'
34
+ s.require_path = '.'
35
+ end
36
+
37
+ Rake::GemPackageTask.new(spec) do |p|
38
+ p.need_tar = true
39
+ p.gem_spec = spec
40
+ end
41
+
42
+ desc 'compile the extension'
43
+ task(:compile => 'Makefile') { sh 'make' }
44
+ file('Makefile' => "geoip.c") { ruby 'extconf.rb' }
45
+
46
+ task :install => [:gem] do
47
+ `sudo env ARCHFLAGS="-arch i386" gem install pkg/geoip-0.5.0.gem -- --with-geoip-dir=/opt/GeoIP`
48
+ end
49
+
50
+ task(:webpage) do
51
+ sh 'scp -r doc/* rydahl@rubyforge.org:/var/www/gforge-projects/geoip-city/'
52
+ end
data/extconf.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("geoip")
4
+
5
+ if have_library('GeoIP', 'GeoIP_record_by_ipnum') and have_header('GeoIPCity.h')
6
+ create_makefile('geoip')
7
+ else
8
+ abort("you must have geoip c library installed!")
9
+ end
data/geoip.c ADDED
@@ -0,0 +1,233 @@
1
+ /* ry dahl <ry@tinyclouds.org> May 21, 2007 */
2
+ /* This program is free software. It comes without any warranty, to
3
+ * the extent permitted by applicable law. You can redistribute it
4
+ * and/or modify it under the terms of the Do What The Fuck You Want
5
+ * To Public License, Version 2, as published by Sam Hocevar. See
6
+ * http://sam.zoy.org/wtfpl/COPYING for more details. */
7
+ #include <ruby.h>
8
+ #include <GeoIP.h>
9
+ #include <GeoIPCity.h>
10
+
11
+ static VALUE mGeoIP;
12
+ static VALUE mGeoIP_City;
13
+ static VALUE mGeoIP_Organization;
14
+ static VALUE rb_geoip_memory;
15
+ static VALUE rb_geoip_filesystem;
16
+ static VALUE rb_geoip_index;
17
+
18
+ /* helper */
19
+ void rb_hash_sset(VALUE hash, const char *str, VALUE v) {
20
+ rb_hash_aset(hash, ID2SYM(rb_intern(str)), v);
21
+ }
22
+
23
+ /* GeoIP::City ***************************************************************/
24
+
25
+ VALUE rb_city_record_to_hash(GeoIPRecord *record)
26
+ {
27
+ VALUE hash = rb_hash_new();
28
+
29
+ if(record->country_code)
30
+ rb_hash_sset(hash, "country_code", rb_str_new2(record->country_code));
31
+ if(record->country_code3)
32
+ rb_hash_sset(hash, "country_code3", rb_str_new2(record->country_code3));
33
+ if(record->country_name)
34
+ rb_hash_sset(hash, "country_name", rb_str_new2(record->country_name));
35
+ if(record->region)
36
+ rb_hash_sset(hash, "region", rb_str_new2(record->region));
37
+ if(record->city)
38
+ rb_hash_sset(hash, "city", rb_str_new2(record->city));
39
+ if(record->postal_code)
40
+ rb_hash_sset(hash, "postal_code", rb_str_new2(record->postal_code));
41
+ if(record->latitude)
42
+ rb_hash_sset(hash, "latitude", rb_float_new((double)record->latitude));
43
+ if(record->longitude)
44
+ rb_hash_sset(hash, "longitude", rb_float_new((double)record->longitude));
45
+ if(record->dma_code)
46
+ rb_hash_sset(hash, "dma_code", INT2NUM(record->dma_code));
47
+ if(record->area_code)
48
+ rb_hash_sset(hash, "area_code", INT2NUM(record->area_code));
49
+
50
+ return hash;
51
+ }
52
+
53
+ /* The first argument is the filename of the GeoIPCity.dat file
54
+ * load_option = :standard, :index, or :memory. default :memory
55
+ * check_cache = true or false. default false
56
+ *
57
+ * filesystem: read database from filesystem, uses least memory.
58
+ *
59
+ * index: the most frequently accessed index portion of the database,
60
+ * resulting in faster lookups than :filesystem, but less memory usage than
61
+ * :memory.
62
+ *
63
+ * memory: load database into memory, faster performance but uses more
64
+ * memory.
65
+ */
66
+ static VALUE rb_geoip_city_new(int argc, VALUE *argv, VALUE self)
67
+ {
68
+ GeoIP *gi;
69
+ VALUE database = Qnil;
70
+ VALUE filename, load_option = Qnil, check_cache = Qnil;
71
+ int flag;
72
+
73
+ rb_scan_args(argc, argv, "12", &filename, &load_option, &check_cache);
74
+ if(NIL_P(load_option))
75
+ load_option = rb_geoip_memory;
76
+ if(NIL_P(check_cache))
77
+ check_cache = Qfalse;
78
+ Check_Type(load_option, T_SYMBOL);
79
+
80
+ if(load_option == rb_geoip_memory) {
81
+ flag = GEOIP_MEMORY_CACHE;
82
+ } else if(load_option == rb_geoip_filesystem) {
83
+ flag = GEOIP_STANDARD;
84
+ } else if(load_option == rb_geoip_index) {
85
+ flag = GEOIP_INDEX_CACHE;
86
+ } else {
87
+ rb_raise(rb_eTypeError, "the second option must be :memory, :filesystem, or :index");
88
+ return Qnil;
89
+ }
90
+
91
+ if(RTEST(check_cache)) flag |= GEOIP_CHECK_CACHE;
92
+
93
+ if(gi = GeoIP_open(STR2CSTR(filename), flag)) {
94
+ database = Data_Wrap_Struct(mGeoIP_City, 0, GeoIP_delete, gi);
95
+ rb_obj_call_init(database, 0, 0);
96
+ } else {
97
+ rb_sys_fail("Problem opening database");
98
+ }
99
+ return database;
100
+ }
101
+
102
+ /* Pass this function an IP address as a string, it will return a hash
103
+ * containing all the information that the database knows about the IP
104
+ * db.look_up('24.24.24.24')
105
+ * => {:city=>"Ithaca", :latitude=>42.4277992248535,
106
+ * :country_code=>"US", :longitude=>-76.4981994628906,
107
+ * :country_code3=>"USA", :dma_code=>555,
108
+ * :country_name=>"United States", :area_code=>607,
109
+ * :region=>"NY"}
110
+ */
111
+ VALUE rb_geoip_city_look_up(VALUE self, VALUE addr) {
112
+ GeoIP *gi;
113
+ GeoIPRecord *record = NULL;
114
+ VALUE hash = Qnil;
115
+
116
+ Check_Type(addr, T_STRING);
117
+ Data_Get_Struct(self, GeoIP, gi);
118
+ if(record = GeoIP_record_by_addr(gi, STR2CSTR(addr))) {
119
+ hash = rb_city_record_to_hash(record);
120
+ GeoIPRecord_delete(record);
121
+ }
122
+ return hash;
123
+ }
124
+
125
+ /* GeoIP::Organization *******************************************************/
126
+
127
+ // VALUE rb_org_record_to_hash(GeoIPRecord *record)
128
+ // {
129
+ // VALUE hash = rb_hash_new();
130
+ //
131
+ // if(record->country_code)
132
+ // rb_hash_sset(hash, "country_code", rb_str_new2(record->country_code));
133
+ // if(record->country_code3)
134
+ // rb_hash_sset(hash, "country_code3", rb_str_new2(record->country_code3));
135
+ // if(record->country_name)
136
+ // rb_hash_sset(hash, "country_name", rb_str_new2(record->country_name));
137
+ // if(record->region)
138
+ // rb_hash_sset(hash, "region", rb_str_new2(record->region));
139
+ // if(record->city)
140
+ // rb_hash_sset(hash, "city", rb_str_new2(record->city));
141
+ // if(record->postal_code)
142
+ // rb_hash_sset(hash, "postal_code", rb_str_new2(record->postal_code));
143
+ // if(record->latitude)
144
+ // rb_hash_sset(hash, "latitude", rb_float_new((double)record->latitude));
145
+ // if(record->longitude)
146
+ // rb_hash_sset(hash, "longitude", rb_float_new((double)record->longitude));
147
+ // if(record->dma_code)
148
+ // rb_hash_sset(hash, "dma_code", INT2NUM(record->dma_code));
149
+ // if(record->area_code)
150
+ // rb_hash_sset(hash, "area_code", INT2NUM(record->area_code));
151
+ //
152
+ // return hash;
153
+ // }
154
+
155
+ static VALUE rb_geoip_org_new(int argc, VALUE *argv, VALUE self)
156
+ {
157
+ GeoIP *gi;
158
+ VALUE database = Qnil;
159
+ VALUE filename, load_option = Qnil, check_cache = Qnil;
160
+ int flag;
161
+
162
+ rb_scan_args(argc, argv, "12", &filename, &load_option, &check_cache);
163
+ if(NIL_P(load_option))
164
+ load_option = rb_geoip_memory;
165
+ if(NIL_P(check_cache))
166
+ check_cache = Qfalse;
167
+ Check_Type(load_option, T_SYMBOL);
168
+
169
+ if(load_option == rb_geoip_memory) {
170
+ flag = GEOIP_MEMORY_CACHE;
171
+ } else if(load_option == rb_geoip_filesystem) {
172
+ flag = GEOIP_STANDARD;
173
+ } else if(load_option == rb_geoip_index) {
174
+ flag = GEOIP_INDEX_CACHE;
175
+ } else {
176
+ rb_raise(rb_eTypeError, "the second option must be :memory, :filesystem, or :index");
177
+ return Qnil;
178
+ }
179
+
180
+ if(RTEST(check_cache)) flag |= GEOIP_CHECK_CACHE;
181
+
182
+ if(gi = GeoIP_open(STR2CSTR(filename), flag)) {
183
+ database = Data_Wrap_Struct(mGeoIP_Organization, 0, GeoIP_delete, gi);
184
+ rb_obj_call_init(database, 0, 0);
185
+ } else {
186
+ rb_sys_fail("Problem opening database");
187
+ }
188
+ return database;
189
+ }
190
+
191
+ /* Pass this function an IP address as a string, it will return a hash
192
+ * containing all the information that the database knows about the IP
193
+ * db.look_up('24.24.24.24')
194
+ * => {}
195
+ */
196
+ VALUE rb_geoip_org_look_up(VALUE self, VALUE addr) {
197
+ GeoIP *gi;
198
+ GeoIPRecord *record = NULL;
199
+ VALUE hash = rb_hash_new();
200
+ char * name = NULL;
201
+
202
+ Check_Type(addr, T_STRING);
203
+ Data_Get_Struct(self, GeoIP, gi);
204
+ if(name = GeoIP_org_by_addr(gi, STR2CSTR(addr))) {
205
+ rb_hash_sset(hash, "name", rb_str_new2(name));
206
+ }
207
+ return hash;
208
+ }
209
+
210
+ /* GeoIP *********************************************************************/
211
+
212
+ /* module GeoIP
213
+ * class City; end
214
+ * class Organization; end
215
+ * end
216
+ */
217
+
218
+ void Init_geoip()
219
+ {
220
+ mGeoIP = rb_define_module("GeoIP");
221
+
222
+ rb_geoip_memory = ID2SYM(rb_intern("memory"));
223
+ rb_geoip_filesystem = ID2SYM(rb_intern("filesystem"));
224
+ rb_geoip_index = ID2SYM(rb_intern("index"));
225
+
226
+ mGeoIP_City = rb_define_class_under(mGeoIP, "City", rb_cObject);
227
+ rb_define_singleton_method(mGeoIP_City, "new", rb_geoip_city_new, -1);
228
+ rb_define_method(mGeoIP_City, "look_up", rb_geoip_city_look_up, 1);
229
+
230
+ mGeoIP_Organization = rb_define_class_under(mGeoIP, "Organization", rb_cObject);
231
+ rb_define_singleton_method( mGeoIP_Organization, "new", rb_geoip_org_new, -1);
232
+ rb_define_method( mGeoIP_Organization, "look_up", rb_geoip_org_look_up, 1);
233
+ }
data/test.rb ADDED
@@ -0,0 +1,59 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/geoip_city'
3
+ require 'rubygems'
4
+ require 'ruby-debug'
5
+ Debugger.start
6
+
7
+ class GeoIPTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ ## Change me!
11
+ @dbfile = '/opt/GeoIP-1.4.2/share/GeoIP/GeoLiteCity.dat'
12
+ end
13
+
14
+
15
+ def test_construction_default
16
+ db = GeoIPCity::Database.new(@dbfile)
17
+
18
+ assert_raises TypeError do
19
+ db.look_up(nil)
20
+ end
21
+
22
+ h = db.look_up('24.24.24.24')
23
+ #debugger
24
+ assert_kind_of Hash, h
25
+ assert_equal 'Ithaca', h[:city]
26
+ assert_equal 'United States', h[:country_name]
27
+ end
28
+
29
+ def test_construction_index
30
+ db = GeoIPCity::Database.new(@dbfile, :index)
31
+ h = db.look_up('24.24.24.24')
32
+ assert_equal 'Ithaca', h[:city]
33
+ end
34
+
35
+ def test_construction_filesystem
36
+ db = GeoIPCity::Database.new(@dbfile, :filesystem)
37
+ h = db.look_up('24.24.24.24')
38
+ assert_equal 'Ithaca', h[:city]
39
+ end
40
+
41
+ def test_construction_memory
42
+ db = GeoIPCity::Database.new(@dbfile, :memory)
43
+ h = db.look_up('24.24.24.24')
44
+ assert_equal 'Ithaca', h[:city]
45
+ end
46
+
47
+ def test_construction_filesystem_check
48
+ db = GeoIPCity::Database.new(@dbfile, :filesystem, true)
49
+ h = db.look_up('24.24.24.24')
50
+ assert_equal 'Ithaca', h[:city]
51
+ end
52
+
53
+ def test_bad_db_file
54
+ assert_raises Errno::ENOENT do
55
+ GeoIPCity::Database.new('/blah')
56
+ end
57
+ end
58
+
59
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mtodd-geoip
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Dahl
8
+ - Matt Todd
9
+ - Charles Brian Quinn
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-05-16 00:00:00 -07:00
15
+ default_executable:
16
+ dependencies: []
17
+
18
+ description: Generic GeoIP lookup tool. Based on the geoip_city RubyGem by Ryan Dahl
19
+ email: mtodd@highgroove.com
20
+ executables: []
21
+
22
+ extensions:
23
+ - extconf.rb
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - Rakefile
28
+ - extconf.rb
29
+ - test.rb
30
+ - geoip.c
31
+ - README.md
32
+ has_rdoc: false
33
+ homepage: http://github.com/mtodd/geoip
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - .
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project:
54
+ rubygems_version: 1.2.0
55
+ signing_key:
56
+ specification_version: 2
57
+ summary: A Binding to the GeoIP C library
58
+ test_files:
59
+ - test.rb