public
Description: ruby binding to maxmind geoip library
Homepage: http://geoip-city.rubyforge.org
Clone URL: git://github.com/ry/geoip-city.git
Search Repo:
geoip-city / geoip_city.c
100644 132 lines (117 sloc) 4.432 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* ry dahl <ry@tinyclouds.org> May 21, 2007 */
/* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. */
#include <ruby.h>
#include <GeoIP.h>
#include <GeoIPCity.h>
 
static VALUE cDB;
static VALUE rb_geoip_memory;
static VALUE rb_geoip_filesystem;
static VALUE rb_geoip_index;
 
/* The first argument is the filename of the GeoIPCity.dat file
* load_option = :standard, :index, or :memory. default :memory
* check_cache = true or false. default false
*
* filesystem: read database from filesystem, uses least memory.
*
* index: the most frequently accessed index portion of the database,
* resulting in faster lookups than :filesystem, but less memory usage than
* :memory.
*
* memory: load database into memory, faster performance but uses more
* memory.
*/
static VALUE rb_geoip_new(int argc, VALUE *argv, VALUE self)
{
  GeoIP *gi;
  VALUE database = Qnil;
  VALUE filename, load_option = Qnil, check_cache = Qnil;
  int flag;
 
  rb_scan_args(argc, argv, "12", &filename, &load_option, &check_cache);
  if(NIL_P(load_option))
    load_option = rb_geoip_memory;
  if(NIL_P(check_cache))
    check_cache = Qfalse;
  Check_Type(load_option, T_SYMBOL);
 
  if(load_option == rb_geoip_memory) {
    flag = GEOIP_MEMORY_CACHE;
  } else if(load_option == rb_geoip_filesystem) {
    flag = GEOIP_STANDARD;
  } else if(load_option == rb_geoip_index) {
    flag = GEOIP_INDEX_CACHE;
  } else {
    rb_raise(rb_eTypeError, "the second option must be :memory, :filesystem, or :index");
    return Qnil;
  }
 
  if(RTEST(check_cache)) flag |= GEOIP_CHECK_CACHE;
  
  if(gi = GeoIP_open(STR2CSTR(filename), flag)) {
    database = Data_Wrap_Struct(cDB, 0, GeoIP_delete, gi);
    rb_obj_call_init(database, 0, 0);
  } else {
    rb_sys_fail("Problem opening database");
  }
  return database;
}
 
/* helper */
void rb_hash_sset(VALUE hash, const char *str, VALUE v) {
  rb_hash_aset(hash, ID2SYM(rb_intern(str)), v);
}
 
VALUE rb_record_to_hash (GeoIPRecord *record)
{
  VALUE hash = rb_hash_new();
 
  if(record->country_code)
    rb_hash_sset(hash, "country_code", rb_str_new2(record->country_code));
  if(record->country_code3)
    rb_hash_sset(hash, "country_code3", rb_str_new2(record->country_code3));
  if(record->country_name)
    rb_hash_sset(hash, "country_name", rb_str_new2(record->country_name));
  if(record->region)
    rb_hash_sset(hash, "region", rb_str_new2(record->region));
  if(record->city)
    rb_hash_sset(hash, "city", rb_str_new2(record->city));
  if(record->postal_code)
    rb_hash_sset(hash, "postal_code", rb_str_new2(record->postal_code));
  if(record->latitude)
    rb_hash_sset(hash, "latitude", rb_float_new((double)record->latitude));
  if(record->longitude)
    rb_hash_sset(hash, "longitude", rb_float_new((double)record->longitude));
  if(record->dma_code)
    rb_hash_sset(hash, "dma_code", INT2NUM(record->dma_code));
  if(record->area_code)
    rb_hash_sset(hash, "area_code", INT2NUM(record->area_code));
  
  return hash;
}
 
/* Pass this function an IP address as a string, it will return a hash
* containing all the information that the database knows about the IP
* db.look_up('24.24.24.24')
* => {:city=>"Ithaca", :latitude=>42.4277992248535,
* :country_code=>"US", :longitude=>-76.4981994628906,
* :country_code3=>"USA", :dma_code=>555,
* :country_name=>"United States", :area_code=>607,
* :region=>"NY"}
*/
VALUE rb_geoip_look_up(VALUE self, VALUE addr) {
  GeoIP *gi;
  GeoIPRecord *record = NULL;
  VALUE hash = Qnil;
  
  Check_Type(addr, T_STRING);
  Data_Get_Struct(self, GeoIP, gi);
  if(record = GeoIP_record_by_addr(gi, STR2CSTR(addr))) {
    hash = rb_record_to_hash(record);
    GeoIPRecord_delete(record);
  }
  return hash;
}
 
void Init_geoip_city ()
{
  VALUE mGeoIP = rb_define_module("GeoIPCity");
 
  rb_geoip_memory = ID2SYM(rb_intern("memory"));
  rb_geoip_filesystem = ID2SYM(rb_intern("filesystem"));
  rb_geoip_index = ID2SYM(rb_intern("index"));
 
  cDB = rb_define_class_under(mGeoIP, "Database", rb_cObject);
  rb_define_singleton_method(cDB, "new", rb_geoip_new, -1);
  rb_define_method(cDB, "look_up", rb_geoip_look_up, 1);
}