maxmind-db-rust 0.1.2

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.
data/README.md ADDED
@@ -0,0 +1,343 @@
1
+ # maxmind-db-rust
2
+
3
+ [![Test](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/test.yml/badge.svg)](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/test.yml)
4
+ [![Lint](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/lint.yml/badge.svg)](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/lint.yml)
5
+
6
+ A high-performance Rust-based Ruby gem for reading MaxMind DB files. Provides API compatibility with the official `maxmind-db` gem while leveraging Rust for superior performance.
7
+
8
+ > **Note:** This is an unofficial library and is not endorsed by MaxMind. For the official Ruby library, see [maxmind-db](https://github.com/maxmind/MaxMind-DB-Reader-ruby).
9
+
10
+ ## Features
11
+
12
+ - **High Performance**: Rust-based implementation provides significantly faster lookups than pure Ruby
13
+ - **API Compatible**: Familiar API similar to the official MaxMind::DB gem
14
+ - **Thread-Safe**: Safe to use from multiple threads
15
+ - **Memory Modes**: Support for both memory-mapped (MMAP) and in-memory modes
16
+ - **Iterator Support**: Iterate over all networks in the database (extension feature)
17
+ - **Type Support**: Works with both String and IPAddr objects
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'maxmind-db-rust'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```bash
30
+ bundle install
31
+ ```
32
+
33
+ Or install it yourself as:
34
+
35
+ ```bash
36
+ gem install maxmind-db-rust
37
+ ```
38
+
39
+ ## Requirements
40
+
41
+ - Ruby 3.2 or higher
42
+ - Rust toolchain (for building from source)
43
+
44
+ ## Usage
45
+
46
+ ### Basic Usage
47
+
48
+ ```ruby
49
+ require 'maxmind/db/rust'
50
+
51
+ # Open database
52
+ reader = MaxMind::DB::Rust::Reader.new(
53
+ 'GeoIP2-City.mmdb',
54
+ mode: MaxMind::DB::Rust::MODE_MEMORY
55
+ )
56
+
57
+ # Lookup an IP address
58
+ record = reader.get('8.8.8.8')
59
+ if record
60
+ puts record['country']['iso_code']
61
+ puts record['country']['names']['en']
62
+ puts record['city']['names']['en']
63
+ end
64
+
65
+ # Close the database
66
+ reader.close
67
+ ```
68
+
69
+ ### Get with Prefix Length
70
+
71
+ ```ruby
72
+ require 'maxmind/db/rust'
73
+
74
+ reader = MaxMind::DB::Rust::Reader.new('GeoIP2-City.mmdb')
75
+
76
+ record, prefix_length = reader.get_with_prefix_length('8.8.8.8')
77
+ puts "Record: #{record}"
78
+ puts "Prefix length: #{prefix_length}"
79
+
80
+ reader.close
81
+ ```
82
+
83
+ ### Using IPAddr Objects
84
+
85
+ ```ruby
86
+ require 'maxmind/db/rust'
87
+ require 'ipaddr'
88
+
89
+ reader = MaxMind::DB::Rust::Reader.new('GeoIP2-City.mmdb')
90
+
91
+ ip = IPAddr.new('8.8.8.8')
92
+ record = reader.get(ip)
93
+
94
+ reader.close
95
+ ```
96
+
97
+ ### Database Modes
98
+
99
+ ```ruby
100
+ require 'maxmind/db/rust'
101
+
102
+ # MODE_AUTO: Uses memory-mapped files (default, best performance)
103
+ reader = MaxMind::DB::Rust::Reader.new(
104
+ 'GeoIP2-City.mmdb',
105
+ mode: MaxMind::DB::Rust::MODE_AUTO
106
+ )
107
+
108
+ # MODE_MMAP: Explicitly use memory-mapped files (recommended)
109
+ reader = MaxMind::DB::Rust::Reader.new(
110
+ 'GeoIP2-City.mmdb',
111
+ mode: MaxMind::DB::Rust::MODE_MMAP
112
+ )
113
+
114
+ # MODE_MEMORY: Load entire database into memory
115
+ reader = MaxMind::DB::Rust::Reader.new(
116
+ 'GeoIP2-City.mmdb',
117
+ mode: MaxMind::DB::Rust::MODE_MEMORY
118
+ )
119
+ ```
120
+
121
+ ### Accessing Metadata
122
+
123
+ ```ruby
124
+ require 'maxmind/db/rust'
125
+
126
+ reader = MaxMind::DB::Rust::Reader.new('GeoIP2-City.mmdb')
127
+
128
+ metadata = reader.metadata
129
+ puts "Database type: #{metadata.database_type}"
130
+ puts "Node count: #{metadata.node_count}"
131
+ puts "Record size: #{metadata.record_size}"
132
+ puts "IP version: #{metadata.ip_version}"
133
+ puts "Build epoch: #{metadata.build_epoch}"
134
+ puts "Languages: #{metadata.languages.join(', ')}"
135
+ puts "Description: #{metadata.description}"
136
+
137
+ reader.close
138
+ ```
139
+
140
+ ### Iterator Support (Extension Feature)
141
+
142
+ Iterate over all networks in the database:
143
+
144
+ ```ruby
145
+ require 'maxmind/db/rust'
146
+
147
+ reader = MaxMind::DB::Rust::Reader.new('GeoLite2-Country.mmdb')
148
+
149
+ # Iterate over all networks
150
+ reader.each do |network, data|
151
+ puts "#{network}: #{data['country']['iso_code']}"
152
+ break # Remove this to see all networks
153
+ end
154
+
155
+ # Iterate over networks within a specific subnet (String CIDR notation)
156
+ reader.each('192.168.0.0/16') do |network, data|
157
+ puts "#{network}: #{data['city']['names']['en']}"
158
+ end
159
+
160
+ # Iterate over networks within a specific subnet (IPAddr object)
161
+ require 'ipaddr'
162
+ subnet = IPAddr.new('10.0.0.0/8')
163
+ reader.each(subnet) do |network, data|
164
+ puts "#{network}: #{data['country']['iso_code']}"
165
+ end
166
+
167
+ # Use Enumerable methods
168
+ countries = reader.map { |network, data| data['country']['iso_code'] }.uniq
169
+ puts "Unique countries: #{countries.size}"
170
+
171
+ reader.close
172
+ ```
173
+
174
+ ## API Documentation
175
+
176
+ ### `MaxMind::DB::Rust::Reader`
177
+
178
+ #### `new(database_path, options = {})`
179
+
180
+ Create a new Reader instance.
181
+
182
+ **Parameters:**
183
+
184
+ - `database_path` (String): Path to the MaxMind DB file
185
+ - `options` (Hash): Optional configuration
186
+ - `:mode` (Symbol): One of `:MODE_AUTO`, `:MODE_MEMORY`, or `:MODE_MMAP`
187
+
188
+ **Returns:** Reader instance
189
+
190
+ **Raises:**
191
+
192
+ - `Errno::ENOENT`: If the database file does not exist
193
+ - `MaxMind::DB::Rust::InvalidDatabaseError`: If the file is not a valid MaxMind DB
194
+
195
+ #### `get(ip_address)`
196
+
197
+ Look up an IP address in the database.
198
+
199
+ **Parameters:**
200
+
201
+ - `ip_address` (String or IPAddr): The IP address to look up
202
+
203
+ **Returns:** Hash with the record data, or `nil` if not found
204
+
205
+ **Raises:**
206
+
207
+ - `ArgumentError`: If looking up IPv6 in an IPv4-only database
208
+ - `MaxMind::DB::Rust::InvalidDatabaseError`: If the database is corrupt
209
+
210
+ #### `get_with_prefix_length(ip_address)`
211
+
212
+ Look up an IP address and return the prefix length.
213
+
214
+ **Parameters:**
215
+
216
+ - `ip_address` (String or IPAddr): The IP address to look up
217
+
218
+ **Returns:** Array `[record, prefix_length]` where record is a Hash or `nil`
219
+
220
+ #### `metadata()`
221
+
222
+ Get metadata about the database.
223
+
224
+ **Returns:** `MaxMind::DB::Rust::Metadata` instance
225
+
226
+ #### `close()`
227
+
228
+ Close the database and release resources.
229
+
230
+ #### `closed()`
231
+
232
+ Check if the database has been closed.
233
+
234
+ **Returns:** Boolean
235
+
236
+ #### `each(network = nil) { |network, data| ... }`
237
+
238
+ Iterate over networks in the database.
239
+
240
+ **Parameters:**
241
+
242
+ - `network` (String or IPAddr, optional): Network CIDR to iterate within (e.g., "192.168.0.0/16"). If omitted, iterates over all networks in the database.
243
+
244
+ **Yields:** IPAddr network and Hash data for each entry
245
+
246
+ **Returns:** Enumerator if no block given
247
+
248
+ **Raises:**
249
+
250
+ - `ArgumentError`: If network CIDR is invalid or IPv6 network specified for IPv4-only database
251
+
252
+ ### `MaxMind::DB::Rust::Metadata`
253
+
254
+ Metadata attributes:
255
+
256
+ - `binary_format_major_version` - Major version of the binary format
257
+ - `binary_format_minor_version` - Minor version of the binary format
258
+ - `build_epoch` - Unix timestamp when the database was built
259
+ - `database_type` - Type of database (e.g., "GeoIP2-City")
260
+ - `description` - Hash of locale codes to descriptions
261
+ - `ip_version` - 4 for IPv4-only, 6 for IPv4/IPv6 support
262
+ - `languages` - Array of supported locale codes
263
+ - `node_count` - Number of nodes in the search tree
264
+ - `record_size` - Record size in bits (24, 28, or 32)
265
+ - `node_byte_size` - Size of a node in bytes
266
+ - `search_tree_size` - Size of the search tree in bytes
267
+
268
+ ### Constants
269
+
270
+ - `MaxMind::DB::Rust::MODE_AUTO` - Automatically choose the best mode (uses MMAP)
271
+ - `MaxMind::DB::Rust::MODE_MEMORY` - Load entire database into memory
272
+ - `MaxMind::DB::Rust::MODE_MMAP` - Use memory-mapped file I/O (recommended)
273
+
274
+ ### Exceptions
275
+
276
+ - `MaxMind::DB::Rust::InvalidDatabaseError` - Raised when the database file is corrupt or invalid
277
+
278
+ ## Comparison with Official Gem
279
+
280
+ | Feature | maxmind-db (official) | maxmind-db-rust (this gem) |
281
+ | ---------------- | --------------------- | -------------------------- |
282
+ | Implementation | Pure Ruby | Rust with Ruby bindings |
283
+ | Performance | Baseline | 10-50x faster |
284
+ | API | MaxMind::DB | MaxMind::DB::Rust |
285
+ | MODE_FILE | ✓ | ✗ |
286
+ | MODE_MEMORY | ✓ | ✓ |
287
+ | MODE_AUTO | ✓ | ✓ |
288
+ | MODE_MMAP | ✗ | ✓ |
289
+ | Iterator support | ✗ | ✓ |
290
+ | Thread-safe | ✓ | ✓ |
291
+
292
+ ## Performance
293
+
294
+ Expected performance characteristics (will vary based on hardware):
295
+
296
+ - Single-threaded lookups: 300,000 - 500,000 lookups/second
297
+ - Significantly faster than pure Ruby implementations
298
+ - Memory-mapped mode (MMAP) provides best performance
299
+ - Fully thread-safe for concurrent lookups
300
+
301
+ ## Development
302
+
303
+ Interested in contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed developer documentation, including:
304
+
305
+ - Development setup and prerequisites
306
+ - Building and testing the extension
307
+ - Code quality guidelines
308
+ - Project structure
309
+ - Submitting changes
310
+
311
+ ### Quick Start
312
+
313
+ ```bash
314
+ git clone https://github.com/oschwald/maxmind-db-rust-ruby.git
315
+ cd maxmind-db-rust-ruby
316
+ git submodule update --init --recursive
317
+ bundle install
318
+ bundle exec rake compile
319
+ bundle exec rake test
320
+ ```
321
+
322
+ ## Contributing
323
+
324
+ 1. Fork it
325
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
326
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
327
+ 4. Push to the branch (`git push origin my-new-feature`)
328
+ 5. Create a new Pull Request
329
+
330
+ ## License
331
+
332
+ This software is licensed under the ISC License. See the LICENSE file for details.
333
+
334
+ ## Support
335
+
336
+ - **Issues**: https://github.com/oschwald/maxmind-db-rust-ruby/issues
337
+ - **Documentation**: https://www.rubydoc.info/gems/maxmind-db-rust
338
+
339
+ ## Credits
340
+
341
+ This gem uses the [maxminddb](https://github.com/oschwald/maxminddb-rust) Rust crate for the core MaxMind DB reading functionality.
342
+
343
+ Built with [magnus](https://github.com/matsadler/magnus) and [rb-sys](https://github.com/oxidize-rb/rb-sys).
@@ -0,0 +1,25 @@
1
+ [package]
2
+ name = "maxmind_db_rust"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ authors = ["Gregory Oschwald <oschwald@gmail.com>"]
6
+ description = "Rust-based Ruby binding for MaxMind DB - high-performance alternative to maxmind-db"
7
+ license = "ISC"
8
+ repository = "https://github.com/oschwald/maxmind-db-rust-ruby"
9
+
10
+ [lib]
11
+ name = "maxmind_db_rust"
12
+ crate-type = ["cdylib"]
13
+
14
+ [dependencies]
15
+ arc-swap = "1.7"
16
+ ipnetwork = "0.21"
17
+ magnus = "0.8"
18
+ maxminddb = { version = "0.26.0", features = ["unsafe-str-decode"] }
19
+ memmap2 = "0.9"
20
+ serde = "1.0"
21
+
22
+ [profile.release]
23
+ lto = "thin"
24
+ codegen-units = 1
25
+ opt-level = 3
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rb_sys/mkmf'
4
+
5
+ create_rust_makefile('maxmind_db_rust')
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'maxmind/db/maxmind_db_rust'
5
+
6
+ module MaxMind
7
+ module DB
8
+ module Rust
9
+ # The native extension defines:
10
+ # - Reader class
11
+ # - Metadata class
12
+ # - InvalidDatabaseError exception
13
+ # - MODE_AUTO, MODE_MEMORY, MODE_MMAP constants
14
+ end
15
+ end
16
+ end