geoip2_c 0.1.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 +7 -0
- data/.gitignore +14 -0
- data/.gitmodules +3 -0
- data/.travis.yml +25 -0
- data/Dockerfile +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +57 -0
- data/Rakefile +18 -0
- data/docker-compose.yml +6 -0
- data/ext/geoip2/extconf.rb +10 -0
- data/ext/geoip2/geoip2.c +421 -0
- data/geoip2_c.gemspec +29 -0
- data/lib/geoip2/database.rb +4 -0
- data/lib/geoip2/lookup_result.rb +7 -0
- data/lib/geoip2/version.rb +3 -0
- data/lib/geoip2.rb +7 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a385241251a43ddd2d075ae6edf6079eee160022
|
4
|
+
data.tar.gz: ba99231f74e179e16f3274eda636860123e2923b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 460dc2adc04bb35833fe48b27688a8d1709ad39526e067bc13ce41d64bb85ee10326c6ff5f493668fad85d135ff213aad862f292e9754db518770e023b2e8756
|
7
|
+
data.tar.gz: 81b9fb3f1b408568894747fe0695d5892250a94dfdc373c663c6fdcd3d6d9def2fc3eacdeffbfdff77fb303b8fff75cb12ae742284eadba62400cf3b0f5a445d
|
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
sudo: required
|
2
|
+
services:
|
3
|
+
- docker
|
4
|
+
|
5
|
+
env:
|
6
|
+
DOCKER_COMPOSE_VERSION: 1.8.1
|
7
|
+
|
8
|
+
before_install:
|
9
|
+
#- sudo apt-get update
|
10
|
+
#- sudo apt-get install -y docker-engine
|
11
|
+
- sudo rm /usr/local/bin/docker-compose
|
12
|
+
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m) > docker-compose
|
13
|
+
- chmod +x docker-compose
|
14
|
+
- sudo mv docker-compose /usr/local/bin/
|
15
|
+
|
16
|
+
before_script:
|
17
|
+
- docker-compose build
|
18
|
+
- docker-compose ps
|
19
|
+
- docker-compose up -d
|
20
|
+
- docker-compose exec test bundle install
|
21
|
+
- docker-compose exec test bundle exec rake compile
|
22
|
+
|
23
|
+
script:
|
24
|
+
- docker-compose exec test bundle exec rake test
|
25
|
+
|
data/Dockerfile
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 okkez
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# GeoIP2
|
2
|
+
|
3
|
+
This gem provides binding [libmaxminddb](http://maxmind.github.io/libmaxminddb/).
|
4
|
+
|
5
|
+
This binding does not traverse all elements in lookup result by default.
|
6
|
+
So you can get the element you want fast such as city name, country name or etc.
|
7
|
+
|
8
|
+
## Requirements
|
9
|
+
|
10
|
+
* Ruby 2.3 or later
|
11
|
+
|
12
|
+
NOTE:
|
13
|
+
|
14
|
+
This library uses `Hash#dig` and `Array#dig`.
|
15
|
+
If you want to use this library with Ruby2.1 or Ruby2.2, you can install a gem which adds support `#dig` method.
|
16
|
+
But I don't want to add extra dependency to this library, so I decided not to add extra dependency to support old Ruby versions.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem 'geoip2_c'
|
24
|
+
```
|
25
|
+
|
26
|
+
And then execute:
|
27
|
+
|
28
|
+
$ bundle
|
29
|
+
|
30
|
+
Or install it yourself as:
|
31
|
+
|
32
|
+
$ gem install geoip2_c
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require "geoip2"
|
38
|
+
|
39
|
+
db = GeoIP2::Databaes.new("/path/to/GeoLite2-City.mmdb")
|
40
|
+
result = db.lookup("66.102.9.80")
|
41
|
+
retuls.get_value("city", "names", "en") # => "Mountain View"
|
42
|
+
```
|
43
|
+
|
44
|
+
## Development
|
45
|
+
|
46
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests.
|
47
|
+
|
48
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
49
|
+
|
50
|
+
## Contributing
|
51
|
+
|
52
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/okkez/geoip2_c.
|
53
|
+
|
54
|
+
## License
|
55
|
+
|
56
|
+
The gem is available as open source under the terms of the [Apache-2.0](http://opensource.org/licenses/Apache-2.0).
|
57
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
8
|
+
end
|
9
|
+
|
10
|
+
require "rake/extensiontask"
|
11
|
+
|
12
|
+
task :build => :compile
|
13
|
+
|
14
|
+
Rake::ExtensionTask.new("geoip2") do |ext|
|
15
|
+
ext.lib_dir = "lib/geoip2"
|
16
|
+
end
|
17
|
+
|
18
|
+
task :default => [:clobber, :compile, :test]
|
data/docker-compose.yml
ADDED
data/ext/geoip2/geoip2.c
ADDED
@@ -0,0 +1,421 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <ruby/encoding.h>
|
3
|
+
#include <maxminddb.h>
|
4
|
+
|
5
|
+
VALUE rb_mGeoIP2;
|
6
|
+
VALUE rb_cGeoIP2Database;
|
7
|
+
VALUE rb_cGeoIP2LookupResult;
|
8
|
+
VALUE rb_eGeoIP2Error;
|
9
|
+
|
10
|
+
static void mmdb_open(const char *db_path, MMDB_s *mmdb);
|
11
|
+
static void mmdb_close(MMDB_s *mmdb);
|
12
|
+
static bool mmdb_is_closed(MMDB_s *mmdb);
|
13
|
+
static void mmdb_free(void *mmdb);
|
14
|
+
static MMDB_lookup_result_s mmdb_lookup(MMDB_s *mmdb, const char *ip_str, bool cleanup);
|
15
|
+
static VALUE mmdb_entry_data_decode(MMDB_entry_data_s *entry_data);
|
16
|
+
static VALUE mmdb_guard_parse_entry_data_list(VALUE ptr);
|
17
|
+
static MMDB_entry_data_list_s *mmdb_parse_entry_data_list(MMDB_entry_data_list_s *data_list, VALUE *obj);
|
18
|
+
|
19
|
+
static VALUE rb_geoip2_db_alloc(VALUE klass);
|
20
|
+
static VALUE rb_geoip2_db_initialize(VALUE self, VALUE path);
|
21
|
+
static VALUE rb_geoip2_db_close(VALUE self);
|
22
|
+
static VALUE rb_geoip2_db_lookup(VALUE self, VALUE ip);
|
23
|
+
|
24
|
+
static VALUE rb_geoip2_lr_alloc(VALUE klass);
|
25
|
+
static VALUE rb_geoip2_lr_initialize(VALUE self);
|
26
|
+
static VALUE rb_geoip2_lr_get_value(int argc, VALUE *argv, VALUE self);
|
27
|
+
static VALUE rb_geoip2_lr_to_h(VALUE self);
|
28
|
+
|
29
|
+
// static void lookup_result_free(void *pointer);
|
30
|
+
// static size_t lookup_result_size(void *pointer);
|
31
|
+
|
32
|
+
static const rb_data_type_t rb_mmdb_type = {
|
33
|
+
"geoip2/mmdb", {
|
34
|
+
0, mmdb_free, 0,
|
35
|
+
}, NULL, NULL
|
36
|
+
};
|
37
|
+
|
38
|
+
static const rb_data_type_t rb_lookup_result_type = {
|
39
|
+
"geoip2/lookup_result", {
|
40
|
+
0, 0, 0,
|
41
|
+
}, NULL, NULL
|
42
|
+
};
|
43
|
+
|
44
|
+
static void
|
45
|
+
mmdb_open(const char *db_path, MMDB_s *mmdb)
|
46
|
+
{
|
47
|
+
int status = MMDB_open(db_path, MMDB_MODE_MMAP, mmdb);
|
48
|
+
|
49
|
+
if (status != MMDB_SUCCESS) {
|
50
|
+
rb_raise(rb_eGeoIP2Error, "%s: %s", MMDB_strerror(status), db_path);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
static void
|
55
|
+
mmdb_close(MMDB_s *mmdb)
|
56
|
+
{
|
57
|
+
MMDB_close(mmdb);
|
58
|
+
mmdb->file_content = NULL;
|
59
|
+
}
|
60
|
+
|
61
|
+
static bool
|
62
|
+
mmdb_is_closed(MMDB_s *mmdb)
|
63
|
+
{
|
64
|
+
return mmdb->file_content == NULL;
|
65
|
+
}
|
66
|
+
|
67
|
+
static void
|
68
|
+
mmdb_free(void *ptr)
|
69
|
+
{
|
70
|
+
MMDB_s *mmdb = (MMDB_s *)ptr;
|
71
|
+
if (!mmdb_is_closed(mmdb)) {
|
72
|
+
mmdb_close(mmdb);
|
73
|
+
}
|
74
|
+
|
75
|
+
xfree(mmdb);
|
76
|
+
}
|
77
|
+
|
78
|
+
static MMDB_lookup_result_s
|
79
|
+
mmdb_lookup(MMDB_s *mmdb, const char *ip_str, bool cleanup)
|
80
|
+
{
|
81
|
+
int gai_error;
|
82
|
+
int mmdb_error;
|
83
|
+
|
84
|
+
MMDB_lookup_result_s result =
|
85
|
+
MMDB_lookup_string(mmdb, ip_str, &gai_error, &mmdb_error);
|
86
|
+
|
87
|
+
if (gai_error != 0) {
|
88
|
+
if (cleanup && !mmdb_is_closed(mmdb)) {
|
89
|
+
mmdb_close(mmdb);
|
90
|
+
}
|
91
|
+
rb_raise(rb_eGeoIP2Error,
|
92
|
+
"getaddrinfo failed: %s", gai_strerror(gai_error));
|
93
|
+
}
|
94
|
+
|
95
|
+
if (mmdb_error != MMDB_SUCCESS) {
|
96
|
+
if (cleanup && !mmdb_is_closed(mmdb)) {
|
97
|
+
mmdb_close(mmdb);
|
98
|
+
}
|
99
|
+
rb_raise(rb_eGeoIP2Error,
|
100
|
+
"lookup failed: %s", MMDB_strerror(mmdb_error));
|
101
|
+
}
|
102
|
+
|
103
|
+
return result;
|
104
|
+
}
|
105
|
+
|
106
|
+
static VALUE
|
107
|
+
mmdb_entry_data_decode(MMDB_entry_data_s *entry_data)
|
108
|
+
{
|
109
|
+
switch (entry_data->type) {
|
110
|
+
case MMDB_DATA_TYPE_EXTENDED:
|
111
|
+
/* TODO: not implemented */
|
112
|
+
return Qnil;
|
113
|
+
case MMDB_DATA_TYPE_POINTER:
|
114
|
+
/* TODO: not implemented */
|
115
|
+
return Qnil;
|
116
|
+
case MMDB_DATA_TYPE_UTF8_STRING:
|
117
|
+
return rb_enc_str_new(entry_data->utf8_string,
|
118
|
+
entry_data->data_size,
|
119
|
+
rb_utf8_encoding());
|
120
|
+
case MMDB_DATA_TYPE_DOUBLE:
|
121
|
+
return DBL2NUM(entry_data->double_value);
|
122
|
+
case MMDB_DATA_TYPE_BYTES:
|
123
|
+
return rb_enc_str_new((const char *)entry_data->bytes,
|
124
|
+
entry_data->data_size,
|
125
|
+
rb_ascii8bit_encoding());
|
126
|
+
case MMDB_DATA_TYPE_UINT16:
|
127
|
+
return UINT2NUM(entry_data->uint16);
|
128
|
+
case MMDB_DATA_TYPE_UINT32:
|
129
|
+
return UINT2NUM(entry_data->uint32);
|
130
|
+
case MMDB_DATA_TYPE_MAP:
|
131
|
+
/* TODO: not implemented */
|
132
|
+
return Qnil;
|
133
|
+
case MMDB_DATA_TYPE_INT32:
|
134
|
+
return INT2NUM(entry_data->int32);
|
135
|
+
case MMDB_DATA_TYPE_UINT64:
|
136
|
+
return UINT2NUM(entry_data->uint64);
|
137
|
+
case MMDB_DATA_TYPE_UINT128:
|
138
|
+
/* FIXME I'm not sure */
|
139
|
+
return UINT2NUM(entry_data->uint128);
|
140
|
+
case MMDB_DATA_TYPE_ARRAY:
|
141
|
+
/* TODO: not implemented */
|
142
|
+
return Qnil;
|
143
|
+
case MMDB_DATA_TYPE_CONTAINER:
|
144
|
+
/* TODO: not implemented */
|
145
|
+
return Qnil;
|
146
|
+
case MMDB_DATA_TYPE_END_MARKER:
|
147
|
+
return Qnil;
|
148
|
+
case MMDB_DATA_TYPE_BOOLEAN:
|
149
|
+
return entry_data->boolean ? Qtrue : Qfalse;
|
150
|
+
case MMDB_DATA_TYPE_FLOAT:
|
151
|
+
return rb_float_new(entry_data->float_value);
|
152
|
+
default:
|
153
|
+
rb_raise(rb_eGeoIP2Error, "Unkown type: %d", entry_data->type);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
static VALUE
|
158
|
+
mmdb_guard_parse_entry_data_list(VALUE ptr)
|
159
|
+
{
|
160
|
+
MMDB_entry_data_list_s *data_list =
|
161
|
+
(struct MMDB_entry_data_list_s *)ptr;
|
162
|
+
VALUE obj;
|
163
|
+
|
164
|
+
mmdb_parse_entry_data_list(data_list, &obj);
|
165
|
+
return obj;
|
166
|
+
}
|
167
|
+
|
168
|
+
static MMDB_entry_data_list_s *
|
169
|
+
mmdb_parse_entry_data_list(MMDB_entry_data_list_s *data_list, VALUE *obj)
|
170
|
+
{
|
171
|
+
switch (data_list->entry_data.type) {
|
172
|
+
case MMDB_DATA_TYPE_MAP:
|
173
|
+
{
|
174
|
+
uint32_t data_size = data_list->entry_data.data_size;
|
175
|
+
VALUE hash = rb_hash_new();
|
176
|
+
for (data_list = data_list->next; data_size && data_list; data_size--) {
|
177
|
+
VALUE key;
|
178
|
+
VALUE val;
|
179
|
+
key = mmdb_entry_data_decode(&data_list->entry_data);
|
180
|
+
data_list = data_list->next;
|
181
|
+
data_list = mmdb_parse_entry_data_list(data_list, &val);
|
182
|
+
rb_hash_aset(hash, key, val);
|
183
|
+
}
|
184
|
+
*obj = hash;
|
185
|
+
break;
|
186
|
+
}
|
187
|
+
case MMDB_DATA_TYPE_ARRAY:
|
188
|
+
{
|
189
|
+
uint32_t data_size = data_list->entry_data.data_size;
|
190
|
+
VALUE array = rb_ary_new();
|
191
|
+
for (data_list = data_list->next; data_size && data_list; data_size--) {
|
192
|
+
VALUE val;
|
193
|
+
data_list = mmdb_parse_entry_data_list(data_list, &val);
|
194
|
+
rb_ary_push(array, val);
|
195
|
+
}
|
196
|
+
*obj = array;
|
197
|
+
break;
|
198
|
+
}
|
199
|
+
case MMDB_DATA_TYPE_UTF8_STRING: /* fall through */
|
200
|
+
case MMDB_DATA_TYPE_BYTES:
|
201
|
+
case MMDB_DATA_TYPE_DOUBLE:
|
202
|
+
case MMDB_DATA_TYPE_UINT16:
|
203
|
+
case MMDB_DATA_TYPE_UINT32:
|
204
|
+
case MMDB_DATA_TYPE_INT32:
|
205
|
+
case MMDB_DATA_TYPE_UINT64:
|
206
|
+
case MMDB_DATA_TYPE_UINT128:
|
207
|
+
case MMDB_DATA_TYPE_BOOLEAN:
|
208
|
+
case MMDB_DATA_TYPE_FLOAT:
|
209
|
+
{
|
210
|
+
VALUE val = mmdb_entry_data_decode(&data_list->entry_data);
|
211
|
+
data_list = data_list->next;
|
212
|
+
*obj = val;
|
213
|
+
break;
|
214
|
+
}
|
215
|
+
default:
|
216
|
+
rb_raise(rb_eGeoIP2Error,
|
217
|
+
"Unkown type: %d",
|
218
|
+
data_list->entry_data.type);
|
219
|
+
}
|
220
|
+
return data_list;
|
221
|
+
}
|
222
|
+
|
223
|
+
static VALUE
|
224
|
+
rb_geoip2_db_alloc(VALUE klass)
|
225
|
+
{
|
226
|
+
VALUE obj;
|
227
|
+
MMDB_s *mmdb;
|
228
|
+
obj = TypedData_Make_Struct(klass, struct MMDB_s, &rb_mmdb_type, mmdb);
|
229
|
+
return obj;
|
230
|
+
}
|
231
|
+
|
232
|
+
static VALUE
|
233
|
+
rb_geoip2_db_initialize(VALUE self, VALUE path)
|
234
|
+
{
|
235
|
+
char *db_path;
|
236
|
+
MMDB_s *mmdb;
|
237
|
+
|
238
|
+
Check_Type(path, T_STRING);
|
239
|
+
|
240
|
+
db_path = StringValueCStr(path);
|
241
|
+
|
242
|
+
TypedData_Get_Struct(self, struct MMDB_s, &rb_mmdb_type, mmdb);
|
243
|
+
mmdb_open(db_path, mmdb);
|
244
|
+
|
245
|
+
return Qnil;
|
246
|
+
}
|
247
|
+
|
248
|
+
static VALUE
|
249
|
+
rb_geoip2_db_close(VALUE self)
|
250
|
+
{
|
251
|
+
MMDB_s *mmdb;
|
252
|
+
|
253
|
+
TypedData_Get_Struct(self, struct MMDB_s, &rb_mmdb_type, mmdb);
|
254
|
+
|
255
|
+
if (!mmdb_is_closed(mmdb)) {
|
256
|
+
mmdb_close(mmdb);
|
257
|
+
}
|
258
|
+
|
259
|
+
return Qnil;
|
260
|
+
}
|
261
|
+
|
262
|
+
static VALUE
|
263
|
+
rb_geoip2_db_lookup(VALUE self, VALUE ip)
|
264
|
+
{
|
265
|
+
char *ip_str;
|
266
|
+
MMDB_s *mmdb;
|
267
|
+
MMDB_lookup_result_s result;
|
268
|
+
MMDB_lookup_result_s *result_ptr;
|
269
|
+
VALUE obj;
|
270
|
+
|
271
|
+
Check_Type(ip, T_STRING);
|
272
|
+
ip_str = StringValueCStr(ip);
|
273
|
+
|
274
|
+
TypedData_Get_Struct(self, struct MMDB_s, &rb_mmdb_type, mmdb);
|
275
|
+
result = mmdb_lookup(mmdb, ip_str, false);
|
276
|
+
|
277
|
+
if (!result.found_entry) {
|
278
|
+
return Qnil;
|
279
|
+
}
|
280
|
+
|
281
|
+
obj = TypedData_Make_Struct(rb_cGeoIP2LookupResult,
|
282
|
+
struct MMDB_lookup_result_s,
|
283
|
+
&rb_lookup_result_type,
|
284
|
+
result_ptr);
|
285
|
+
result_ptr->found_entry = result.found_entry;
|
286
|
+
result_ptr->entry = result.entry;
|
287
|
+
result_ptr->netmask = result.netmask;
|
288
|
+
return obj;
|
289
|
+
}
|
290
|
+
|
291
|
+
static VALUE
|
292
|
+
rb_geoip2_lr_alloc(VALUE klass)
|
293
|
+
{
|
294
|
+
VALUE obj;
|
295
|
+
MMDB_lookup_result_s *result;
|
296
|
+
obj = TypedData_Make_Struct(klass,
|
297
|
+
struct MMDB_lookup_result_s,
|
298
|
+
&rb_lookup_result_type,
|
299
|
+
result);
|
300
|
+
return obj;
|
301
|
+
}
|
302
|
+
|
303
|
+
static VALUE
|
304
|
+
rb_geoip2_lr_initialize(VALUE self)
|
305
|
+
{
|
306
|
+
return Qnil;
|
307
|
+
}
|
308
|
+
|
309
|
+
static VALUE
|
310
|
+
rb_geoip2_lr_get_value(int argc, VALUE *argv, VALUE self)
|
311
|
+
{
|
312
|
+
VALUE arg;
|
313
|
+
VALUE rest;
|
314
|
+
char **path;
|
315
|
+
int i = 0;
|
316
|
+
MMDB_lookup_result_s *result = NULL;
|
317
|
+
MMDB_entry_s entry;
|
318
|
+
MMDB_entry_data_s entry_data;
|
319
|
+
char *tmp;
|
320
|
+
VALUE e;
|
321
|
+
int status;
|
322
|
+
|
323
|
+
rb_scan_args(argc, argv, "1*", &arg, &rest);
|
324
|
+
Check_Type(arg, T_STRING);
|
325
|
+
path = malloc(sizeof(char *) * (RARRAY_LEN(rest) + 2));
|
326
|
+
|
327
|
+
TypedData_Get_Struct(self,
|
328
|
+
struct MMDB_lookup_result_s,
|
329
|
+
&rb_lookup_result_type,
|
330
|
+
result);
|
331
|
+
|
332
|
+
path[i] = StringValueCStr(arg);
|
333
|
+
while (RARRAY_LEN(rest) != 0) {
|
334
|
+
++i;
|
335
|
+
e = rb_ary_shift(rest);
|
336
|
+
tmp = StringValueCStr(e);
|
337
|
+
path[i] = tmp;
|
338
|
+
}
|
339
|
+
|
340
|
+
path[i+1] = NULL;
|
341
|
+
|
342
|
+
entry = result->entry;
|
343
|
+
|
344
|
+
status = MMDB_aget_value(&entry, &entry_data, (const char *const *const)path);
|
345
|
+
|
346
|
+
if (status != MMDB_SUCCESS) {
|
347
|
+
free(path);
|
348
|
+
fprintf(stderr, "%s\n", MMDB_strerror(status));
|
349
|
+
return Qnil;
|
350
|
+
}
|
351
|
+
|
352
|
+
if (!entry_data.has_data) {
|
353
|
+
free(path);
|
354
|
+
return Qnil;
|
355
|
+
}
|
356
|
+
|
357
|
+
if (entry_data.type == MMDB_DATA_TYPE_MAP ||
|
358
|
+
entry_data.type == MMDB_DATA_TYPE_ARRAY) {
|
359
|
+
// FIXME optimize below code
|
360
|
+
VALUE array = rb_ary_new();
|
361
|
+
VALUE hash;
|
362
|
+
VALUE val;
|
363
|
+
for (int j = 0; path[j] != NULL; j++) {
|
364
|
+
rb_ary_push(array, rb_str_new_cstr(path[j]));
|
365
|
+
}
|
366
|
+
hash = rb_funcall(self, rb_intern("to_h"), 0);
|
367
|
+
val = rb_apply(hash, rb_intern("dig"), array);
|
368
|
+
free(path);
|
369
|
+
return val;
|
370
|
+
}
|
371
|
+
|
372
|
+
free(path);
|
373
|
+
return mmdb_entry_data_decode(&entry_data);
|
374
|
+
}
|
375
|
+
|
376
|
+
static VALUE
|
377
|
+
rb_geoip2_lr_to_h(VALUE self)
|
378
|
+
{
|
379
|
+
MMDB_lookup_result_s *result = NULL;
|
380
|
+
MMDB_entry_data_list_s *entry_data_list = NULL;
|
381
|
+
VALUE hash;
|
382
|
+
int status = 0;
|
383
|
+
int exception = 0;
|
384
|
+
|
385
|
+
TypedData_Get_Struct(self,
|
386
|
+
struct MMDB_lookup_result_s,
|
387
|
+
&rb_lookup_result_type,
|
388
|
+
result);
|
389
|
+
status = MMDB_get_entry_data_list(&result->entry, &entry_data_list);
|
390
|
+
if (status != MMDB_SUCCESS) {
|
391
|
+
rb_raise(rb_eGeoIP2Error, "%s", MMDB_strerror(status));
|
392
|
+
}
|
393
|
+
|
394
|
+
hash = rb_protect(mmdb_guard_parse_entry_data_list, (VALUE)entry_data_list, &exception);
|
395
|
+
MMDB_free_entry_data_list(entry_data_list);
|
396
|
+
|
397
|
+
if (exception != 0) {
|
398
|
+
rb_jump_tag(exception);
|
399
|
+
}
|
400
|
+
|
401
|
+
return hash;
|
402
|
+
}
|
403
|
+
|
404
|
+
void
|
405
|
+
Init_geoip2(void)
|
406
|
+
{
|
407
|
+
rb_mGeoIP2 = rb_define_module("GeoIP2");
|
408
|
+
rb_cGeoIP2Database = rb_define_class_under(rb_mGeoIP2, "Database", rb_cData);
|
409
|
+
rb_cGeoIP2LookupResult = rb_define_class_under(rb_mGeoIP2, "LookupResult", rb_cData);
|
410
|
+
rb_eGeoIP2Error = rb_define_class_under(rb_mGeoIP2, "Error", rb_eStandardError);
|
411
|
+
|
412
|
+
rb_define_alloc_func(rb_cGeoIP2Database, rb_geoip2_db_alloc);
|
413
|
+
rb_define_method(rb_cGeoIP2Database, "initialize", rb_geoip2_db_initialize, 1);
|
414
|
+
rb_define_method(rb_cGeoIP2Database, "close", rb_geoip2_db_close, 0);
|
415
|
+
rb_define_method(rb_cGeoIP2Database, "lookup", rb_geoip2_db_lookup, 1);
|
416
|
+
|
417
|
+
rb_define_alloc_func(rb_cGeoIP2LookupResult, rb_geoip2_lr_alloc);
|
418
|
+
rb_define_method(rb_cGeoIP2LookupResult, "initialize", rb_geoip2_lr_initialize, 0);
|
419
|
+
rb_define_method(rb_cGeoIP2LookupResult, "get_value", rb_geoip2_lr_get_value, -1);
|
420
|
+
rb_define_method(rb_cGeoIP2LookupResult, "to_h", rb_geoip2_lr_to_h, 0);
|
421
|
+
}
|
data/geoip2_c.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'geoip2/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "geoip2_c"
|
8
|
+
spec.version = GeoIP2::VERSION
|
9
|
+
spec.authors = ["okkez"]
|
10
|
+
spec.email = ["okkez000@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Write a short summary, because Rubygems requires one.}
|
13
|
+
spec.description = %q{Write a longer description or delete this line.}
|
14
|
+
spec.homepage = ""
|
15
|
+
spec.license = "Apache-2.0"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "bin"
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
spec.extensions = ["ext/geoip2/extconf.rb"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
26
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
27
|
+
spec.add_development_dependency "rake-compiler"
|
28
|
+
spec.add_development_dependency "test-unit", "~> 3.2"
|
29
|
+
end
|
data/lib/geoip2.rb
ADDED
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geoip2_c
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- okkez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '11.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '11.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake-compiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: test-unit
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.2'
|
69
|
+
description: Write a longer description or delete this line.
|
70
|
+
email:
|
71
|
+
- okkez000@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions:
|
74
|
+
- ext/geoip2/extconf.rb
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".gitmodules"
|
79
|
+
- ".travis.yml"
|
80
|
+
- Dockerfile
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- docker-compose.yml
|
86
|
+
- ext/geoip2/extconf.rb
|
87
|
+
- ext/geoip2/geoip2.c
|
88
|
+
- geoip2_c.gemspec
|
89
|
+
- lib/geoip2.rb
|
90
|
+
- lib/geoip2/database.rb
|
91
|
+
- lib/geoip2/lookup_result.rb
|
92
|
+
- lib/geoip2/version.rb
|
93
|
+
homepage: ''
|
94
|
+
licenses:
|
95
|
+
- Apache-2.0
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.6.4
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Write a short summary, because Rubygems requires one.
|
117
|
+
test_files: []
|