Comparing version 0.0.5 to 0.1.0
@@ -5,6 +5,13 @@ | ||
function randip() { | ||
return [ | ||
Math.floor(Math.random() * 255), | ||
Math.floor(Math.random() * 255), | ||
Math.floor(Math.random() * 255), | ||
Math.floor(Math.random() * 255) | ||
].join('.'); | ||
} | ||
ls.init('./test/dbs/GeoLiteCity.dat'); | ||
var ips = fs.readFileSync('./test/dbs/ips.txt'); | ||
ips = ips.toString().split("\n").map(function(line) { | ||
@@ -24,7 +31,1 @@ return line.trim(); | ||
console.log('speed:', Math.round(n / (new Date().getTime() - s) * 1000), 'per sec'); | ||
// console.log(ls.dump()) | ||
// var time = process.hrtime(); | ||
// var diff = process.hrtime(time); | ||
// console.log((diff[0] * 1e9 + diff[1]) / 1e9); |
@@ -13,2 +13,3 @@ var fs = require('fs'), | ||
Buff.prototype.pointer = 0; | ||
Buff.prototype.closed = false; | ||
Buff.prototype.length = function() { | ||
@@ -34,3 +35,5 @@ return this.meta.size; | ||
Buff.prototype.close = function() { | ||
fs.closeSync(this.ba); | ||
if (this.ba && !this.closed) | ||
fs.closeSync(this.ba); | ||
this.closed = true; | ||
}; | ||
@@ -37,0 +40,0 @@ |
@@ -96,9 +96,8 @@ | ||
var dboptions = GEOIP_MEMORY_CACHE; | ||
var dboptions = null; | ||
var databaseType = DatabaseInfo.COUNTRY_EDITION; | ||
var databaseSegments = []; | ||
var databaseSegment = null; | ||
var recordLength = 0; | ||
var index_cache = new Buffer(0); | ||
var databaseInfo = null; | ||
var mtime; | ||
var last_netmask; | ||
@@ -132,5 +131,5 @@ var file; | ||
// Find the database info string. | ||
for (var i=0; i<DATABASE_INFO_MAX_SIZE; i++) { | ||
for (var i = 0; i < DATABASE_INFO_MAX_SIZE; i++) { | ||
file.readFully(delim); | ||
if (delim[0]==0 && delim[1]==0 && delim[2]==0) { | ||
if (delim[0] == 0 && delim[1] == 0 && delim[2] == 0) { | ||
var dbInfo = new Buffer(i); | ||
@@ -145,6 +144,2 @@ file.readFully(dbInfo); | ||
function _check_mtime() { | ||
// do noting atm | ||
}; | ||
module.exports.ip2Long = function(ip) { | ||
@@ -169,7 +164,16 @@ ip = ip.split('.'); | ||
module.exports.path = null; | ||
module.exports.init = function(path) { | ||
module.exports.init = function(path, opts) { | ||
// already initialized | ||
if (path == this.path && this.inited) | ||
return true; | ||
dboptions = GEOIP_STANDARD; | ||
if (opts !== undefined && opts.indexCache) | ||
dboptions |= GEOIP_INDEX_CACHE; | ||
if (opts !== undefined && opts.memoryCache) | ||
dboptions |= GEOIP_MEMORY_CACHE; | ||
file = new Buff(path); | ||
@@ -183,10 +187,5 @@ | ||
if (file == null) { | ||
if (file == null) | ||
throw new Error('Invalid file'); | ||
} | ||
// if ((dboptions & GEOIP_CHECK_CACHE) != 0) { | ||
// mtime = databaseFile.lastModified(); | ||
// } | ||
file.seek(file.length() - 3); | ||
@@ -207,7 +206,7 @@ | ||
if (databaseType == DatabaseInfo.REGION_EDITION_REV0) { | ||
databaseSegments = [ STATE_BEGIN_REV0 ]; | ||
databaseSegment = STATE_BEGIN_REV0; | ||
recordLength = STANDARD_RECORD_LENGTH; | ||
} else if (databaseType == DatabaseInfo.REGION_EDITION_REV1){ | ||
databaseSegments = [ STATE_BEGIN_REV1 ]; | ||
databaseSegment = STATE_BEGIN_REV1; | ||
recordLength = STANDARD_RECORD_LENGTH; | ||
@@ -230,3 +229,3 @@ | ||
) { | ||
databaseSegments = [ 0 ]; | ||
databaseSegment = 0; | ||
@@ -249,3 +248,3 @@ if (databaseType == DatabaseInfo.CITY_EDITION_REV0 || | ||
for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) { | ||
databaseSegments[0] += buf.readUInt8(j) << (j * 8); | ||
databaseSegment += buf.readUInt8(j) << (j * 8); | ||
} | ||
@@ -264,7 +263,9 @@ } | ||
) { | ||
databaseSegments = [ COUNTRY_BEGIN ]; | ||
databaseSegment = COUNTRY_BEGIN; | ||
recordLength = STANDARD_RECORD_LENGTH; | ||
} | ||
if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { | ||
this.databaseInfo = _getDatabaseInfo(); | ||
if ((dboptions & GEOIP_MEMORY_CACHE) != 0) { | ||
var l = file.length(); | ||
@@ -274,3 +275,2 @@ dbbuffer = new Buffer(l); | ||
file.readFully(dbbuffer,0,l); | ||
this.databaseInfo = _getDatabaseInfo(); | ||
file.close(); | ||
@@ -280,3 +280,3 @@ } | ||
if ((dboptions & GEOIP_INDEX_CACHE) != 0) { | ||
var l = databaseSegments[0] * recordLength * 2; | ||
var l = databaseSegment * recordLength * 2; | ||
index_cache = new Buffer(l); | ||
@@ -339,9 +339,10 @@ if (index_cache != null) { | ||
_check_mtime(); | ||
var buf = new Buffer(2 * MAX_RECORD_LENGTH); | ||
var databaseSegment = databaseSegments[0]; | ||
if (_cache == null) | ||
_makeCache(); | ||
if (_cache == null) { | ||
if ((dboptions & GEOIP_MEMORY_CACHE) != 0) | ||
_makeCache(); | ||
else | ||
_cache = {}; | ||
} | ||
@@ -354,3 +355,2 @@ var x0 = 0, | ||
for (var depth = 31; depth >= 0; depth--) { | ||
@@ -365,3 +365,3 @@ | ||
if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { | ||
if ((dboptions & GEOIP_MEMORY_CACHE) != 0) { | ||
//read from memory | ||
@@ -376,5 +376,2 @@ dbbuffer.copy(buf, 0, 2 * recordLength * offset, (2 * recordLength * offset) + (2 * MAX_RECORD_LENGTH)); | ||
//read from disk | ||
// fs.readSync(fd, buffer, offset, length, position) | ||
try { | ||
@@ -388,3 +385,2 @@ file.seek(2 * recordLength * offset); | ||
x0 = 0; | ||
@@ -409,3 +405,2 @@ x1 = 0; | ||
} | ||
offset = x1; | ||
@@ -443,5 +438,5 @@ } else { | ||
var record_pointer; | ||
var record_buf = new Buffer(FULL_RECORD_LENGTH); | ||
var record_buf_offset = 0; | ||
var recordPointer; | ||
var recordBuf; | ||
var recordBufOffset = 0; | ||
@@ -451,3 +446,3 @@ var record = new Location(); | ||
var str_length = 0; | ||
var j, seek_country; | ||
var j, seekCountry; | ||
var latitude = 0, longitude = 0; | ||
@@ -457,31 +452,33 @@ | ||
seek_country = this.seekCountry(ipnum); | ||
seekCountry = this.seekCountry(ipnum); | ||
if (seek_country == databaseSegments[0]) | ||
if (seekCountry == databaseSegment) | ||
return null; | ||
record_pointer = seek_country + (2 * recordLength - 1) * databaseSegments[0]; | ||
recordPointer = seekCountry + (2 * recordLength - 1) * databaseSegment; | ||
if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { | ||
record_buf = new DynBuffer(dbbuffer, record_pointer, Math.min(dbbuffer.length - record_pointer, FULL_RECORD_LENGTH)); | ||
if ((dboptions & GEOIP_MEMORY_CACHE) != 0) { | ||
recordBuf = new DynBuffer(dbbuffer, recordPointer, Math.min(dbbuffer.length - recordPointer, FULL_RECORD_LENGTH)); | ||
} else { | ||
//read from disk | ||
file.seek(record_pointer); | ||
file.readFully(record_buf); | ||
recordBuf = new DynBuffer(new Buffer(FULL_RECORD_LENGTH), 0, FULL_RECORD_LENGTH); | ||
file.seek(recordPointer); | ||
file.readFully(recordBuf.source); | ||
} | ||
// get country | ||
record.countryCode = countryCode[record_buf.readUInt8(0)]; | ||
record.countryName = countryName[record_buf.readUInt8(0)]; | ||
record_buf_offset++; | ||
record.countryCode = countryCode[recordBuf.readUInt8(0)]; | ||
record.countryName = countryName[recordBuf.readUInt8(0)]; | ||
recordBufOffset++; | ||
// get region | ||
while (record_buf.at(record_buf_offset + str_length) != 0x00) | ||
while (recordBuf.at(recordBufOffset + str_length) != 0x00) | ||
str_length++; | ||
if (str_length > 0) | ||
record.region = record_buf.toString('utf8', record_buf_offset, record_buf_offset + str_length); | ||
record.region = recordBuf.toString('utf8', recordBufOffset, recordBufOffset + str_length); | ||
record_buf_offset += str_length + 1; | ||
recordBufOffset += str_length + 1; | ||
str_length = 0; | ||
@@ -491,9 +488,9 @@ | ||
// get city | ||
while (record_buf.at(record_buf_offset + str_length) != 0x00) | ||
while (recordBuf.at(recordBufOffset + str_length) != 0x00) | ||
str_length++; | ||
if (str_length > 0) | ||
record.city = record_buf.toString('utf8', record_buf_offset, record_buf_offset + str_length); | ||
record.city = recordBuf.toString('utf8', recordBufOffset, recordBufOffset + str_length); | ||
record_buf_offset += str_length + 1; | ||
recordBufOffset += str_length + 1; | ||
str_length = 0; | ||
@@ -503,22 +500,22 @@ | ||
// get postal code | ||
while (record_buf.at(record_buf_offset + str_length) != 0x00) | ||
while (recordBuf.at(recordBufOffset + str_length) != 0x00) | ||
str_length++; | ||
if (str_length > 0) | ||
record.postalCode = record_buf.toString('utf8', record_buf_offset, record_buf_offset + str_length); | ||
record.postalCode = recordBuf.toString('utf8', recordBufOffset, recordBufOffset + str_length); | ||
record_buf_offset += str_length + 1; | ||
recordBufOffset += str_length + 1; | ||
// get latitude | ||
latitude = (record_buf.readUInt8(record_buf_offset + 0) << (0 * 8)) | ||
+ (record_buf.readUInt8(record_buf_offset + 1) << (1 * 8)) | ||
+ (record_buf.readUInt8(record_buf_offset + 2) << (2 * 8)); | ||
latitude = (recordBuf.readUInt8(recordBufOffset + 0) << (0 * 8)) | ||
+ (recordBuf.readUInt8(recordBufOffset + 1) << (1 * 8)) | ||
+ (recordBuf.readUInt8(recordBufOffset + 2) << (2 * 8)); | ||
record.latitude = latitude/10000 - 180; | ||
record_buf_offset += 3; | ||
recordBufOffset += 3; | ||
// get longitude | ||
longitude = (record_buf.readUInt8(record_buf_offset + 0) << (0 * 8)) | ||
+ (record_buf.readUInt8(record_buf_offset + 1) << (1 * 8)) | ||
+ (record_buf.readUInt8(record_buf_offset + 2) << (2 * 8)); | ||
longitude = (recordBuf.readUInt8(recordBufOffset + 0) << (0 * 8)) | ||
+ (recordBuf.readUInt8(recordBufOffset + 1) << (1 * 8)) | ||
+ (recordBuf.readUInt8(recordBufOffset + 2) << (2 * 8)); | ||
@@ -534,6 +531,6 @@ record.longitude = longitude/10000 - 180; | ||
if (record.countryCode == "US") { | ||
record_buf_offset += 3; | ||
recordBufOffset += 3; | ||
for (j = 0; j < 3; j++) | ||
metroarea_combo += record_buf.readUInt8(record_buf_offset + j) << (j * 8); | ||
metroarea_combo += recordBuf.readUInt8(recordBufOffset + j) << (j * 8); | ||
@@ -608,2 +605,16 @@ record.metro_code = record.dma_code = metroarea_combo/1000; | ||
return record; | ||
}; | ||
module.exports.uninit = function() { | ||
this.databaseInfo = null; | ||
this.inited = false; | ||
dboptions = GEOIP_STANDARD; | ||
if (file) { | ||
file.close(); | ||
file = null; | ||
} | ||
_cache = null; | ||
return true; | ||
}; |
{ | ||
"name": "maxmind", | ||
"version": "0.0.5", | ||
"version": "0.1.0", | ||
"homepage": "https://github.com/runk/node-maxmind", | ||
"description": "IP lookup using Maxmind databases", | ||
"keywords": ["maxmind", "geo", "geobase", "geo lookup", "ip base", "geocode"], | ||
"keywords": ["maxmind", "geo", "geobase", "geo lookup", "ip base", "geocode", "timezone"], | ||
"author": "Shirokov Dmitry <deadrunk@gmail.com>", | ||
@@ -8,0 +8,0 @@ "dependencies": {}, |
@@ -30,17 +30,49 @@ | ||
```js | ||
var maxmind = require('maxmind'); | ||
maxmind.init('/path/to/GeoLiteCity.dat') | ||
maxmind.init('/path/to/GeoLiteCity.dat'); | ||
console.log(maxmind.getLocation("66.6.44.4")); | ||
``` | ||
Country Lookup | ||
```js | ||
var maxmind = require('maxmind'); | ||
maxmind.init('/path/to/GeoIP.dat') | ||
maxmind.init('/path/to/GeoIP.dat'); | ||
console.log(maxmind.getCountry("66.6.44.4")); | ||
``` | ||
## Caching | ||
By default module does not use cache, and works directly with file system. Enabling cache | ||
leads to better performance, howerver consumer more memory. Currently module supports two options: | ||
- `indexCache` saves in memory only the country index | ||
- `memoryCache` saves in memory full database file | ||
If you decided to enable caching you can pass it as a flag in `init` method: | ||
```js | ||
var maxmind = require('maxmind'); | ||
maxmind.init('/path/to/GeoIP.dat', { indexCache: true }); | ||
``` | ||
Caching could significantly increase performance, refer to this camparison which was made on average | ||
laptop: | ||
- default: 18,000 lookups / second | ||
- `indexCache`: 60,000 lookups / second | ||
- `memodyCache`: 100,000 lookups / second | ||
## Tests | ||
If you want ot run tests you will need `mocha` installed, then just run it: | ||
$ mocha | ||
## Disclaimer | ||
Module is quite young and some serious bugs are possible. Feel free to | ||
Module is quite young and serious bugs are possible. Feel free to | ||
send pull request / bug reports. | ||
Module currently work only in `MEMORY_CACHE` mode. |
164623
28
6613
78