Comparing version 0.1.7 to 0.2.0
@@ -14,3 +14,3 @@ | ||
ls.init('./test/dbs/GeoLiteCity.dat', { memoryCache: true }); | ||
ls.init('./test/dbs/GeoIPCity.dat', { memoryCache: true }); | ||
var ips = fs.readFileSync('./test/dbs/ips.txt'); | ||
@@ -17,0 +17,0 @@ ips = ips.toString().split("\n").map(function(line) { |
@@ -1,36 +0,154 @@ | ||
module.exports = function(info) { | ||
var _info = info.toString(); | ||
this.getType = function() { | ||
if (!_info) | ||
return module.exports.COUNTRY_EDITION; | ||
// Get the type code from the database info string and then | ||
// subtract 105 from the value to preserve compatability with | ||
// databases from April 2003 and earlier. | ||
return parseInt(_info.substring(4, 7), 10) - 105; | ||
}; | ||
this.isPremium = function() { | ||
return _info.indexOf("FREE") < 0; | ||
}; | ||
this.getDate = function() { | ||
for (var i = 0; i < _info.length - 9; i++) { | ||
if (_info.charCodeAt(i) === 0x20) | ||
return new Date( | ||
_info.substring(i+1, i+9) | ||
.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3') | ||
); | ||
const DATABASE_INFO_MAX_SIZE = 100; | ||
const COUNTRY_BEGIN = 16776960; | ||
const STATE_BEGIN_REV0 = 16700000; | ||
const STATE_BEGIN_REV1 = 16000000; | ||
const STRUCTURE_INFO_MAX_SIZE = 20; | ||
const SEGMENT_RECORD_LENGTH = 3; | ||
const STANDARD_RECORD_LENGTH = 3; | ||
const ORG_RECORD_LENGTH = 4; | ||
module.exports = function(file) { | ||
var i, j; | ||
var delim = new Buffer(3); | ||
var buf = new Buffer(SEGMENT_RECORD_LENGTH); | ||
var self = module.exports; | ||
this.type = self.COUNTRY_EDITION; | ||
this.segment = null; | ||
this.recordLength = 0; | ||
file.seek(file.length() - 3); | ||
for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) { | ||
file.readFully(delim); | ||
if (delim.readInt8(0) === -1 && delim.readInt8(1) === -1 && delim.readInt8(2) === -1) { | ||
this.type = file.readByte(); | ||
if (this.type >= 106) { | ||
// Backward compatibility with databases from April 2003 and earlier | ||
this.type -= 105; | ||
} | ||
// Determine the database type. | ||
if (this.type === self.REGION_EDITION_REV0) { | ||
this.segment = STATE_BEGIN_REV0; | ||
this.recordLength = STANDARD_RECORD_LENGTH; | ||
} else if (this.type === self.REGION_EDITION_REV1){ | ||
this.segment = STATE_BEGIN_REV1; | ||
this.recordLength = STANDARD_RECORD_LENGTH; | ||
} else if (this.type === self.CITY_EDITION_REV0 || | ||
this.type === self.CITY_EDITION_REV1 || | ||
this.type === self.ORG_EDITION || | ||
this.type === self.ORG_EDITION_V6 || | ||
this.type === self.ISP_EDITION || | ||
this.type === self.ISP_EDITION_V6 || | ||
this.type === self.DOMAIN_EDITION || | ||
this.type === self.DOMAIN_EDITION_V6 || | ||
this.type === self.ASNUM_EDITION || | ||
this.type === self.ASNUM_EDITION_V6 || | ||
this.type === self.NETSPEED_EDITION_REV1 || | ||
this.type === self.NETSPEED_EDITION_REV1_V6 || | ||
this.type === self.CITY_EDITION_REV0_V6 || | ||
this.type === self.CITY_EDITION_REV1_V6 | ||
) { | ||
this.segment = 0; | ||
if (this.type === self.CITY_EDITION_REV0 || | ||
this.type === self.CITY_EDITION_REV1 || | ||
this.type === self.ASNUM_EDITION_V6 || | ||
this.type === self.NETSPEED_EDITION_REV1 || | ||
this.type === self.NETSPEED_EDITION_REV1_V6 || | ||
this.type === self.CITY_EDITION_REV0_V6 || | ||
this.type === self.CITY_EDITION_REV1_V6 || | ||
this.type === self.ASNUM_EDITION | ||
) { | ||
this.recordLength = STANDARD_RECORD_LENGTH; | ||
} else { | ||
this.recordLength = ORG_RECORD_LENGTH; | ||
} | ||
file.readFully(buf); | ||
for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) { | ||
this.segment += buf.readUInt8(j) << (j * 8); | ||
} | ||
} | ||
break; | ||
} else { | ||
file.seek(file.getFilePointer() - 4); | ||
} | ||
}; | ||
this.toString = function() { | ||
return _info; | ||
}; | ||
} | ||
if (this.type === self.COUNTRY_EDITION || | ||
this.type === self.COUNTRY_EDITION_V6 || | ||
this.type === self.PROXY_EDITION || | ||
this.type === self.NETSPEED_EDITION | ||
) { | ||
this.segment = COUNTRY_BEGIN; | ||
this.recordLength = STANDARD_RECORD_LENGTH; | ||
} | ||
var hasStructureInfo = false; | ||
delim = new Buffer(3); | ||
// Advance to part of file where database info is stored. | ||
file.seek(file.length() - 3); | ||
for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) { | ||
file.readFully(delim); | ||
if (delim[0] === 255 && delim[1] === 255 && delim[2] === 255) { | ||
hasStructureInfo = true; | ||
break; | ||
} | ||
file.seek(file.getFilePointer() - 4); | ||
} | ||
if (hasStructureInfo) { | ||
file.seek(file.getFilePointer() - 6); | ||
} else { | ||
// No structure info, must be pre Sep 2002 database, go back to end. | ||
file.seek(file.length() - 3); | ||
} | ||
this.info = null; | ||
// Find the database info string. | ||
for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) { | ||
file.readFully(delim); | ||
if (delim[0] + delim[1] + delim[2] === 0) { | ||
this.info = new Buffer(i); | ||
file.readFully(this.info); | ||
this.info = this.info.toString(); | ||
} | ||
file.seek(file.getFilePointer() - 4); | ||
} | ||
if (!this.info) | ||
throw new Error('Unable to find database info'); | ||
this.isPremium = this.info.indexOf('FREE') < 0 && this.info.indexOf('LITE') < 0; | ||
this.date = null; | ||
for (i = 0; i < this.info.length - 9; i++) { | ||
if (this.info.charCodeAt(i) === 0x20) { | ||
this.date = new Date( | ||
this.info.substring(i+1, i+9).replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3') | ||
); | ||
break; | ||
} | ||
} | ||
}; | ||
// constDatabase types | ||
module.exports.COUNTRY_EDITION = 1; | ||
module.exports.REGION_EDITION_REV0 = 7; | ||
module.exports.REGION_EDITION_REV1 = 3; | ||
module.exports.CITY_EDITION_REV0 = 6; | ||
module.exports.CITY_EDITION_REV1 = 2; | ||
module.exports.ORG_EDITION = 5; | ||
module.exports.ISP_EDITION = 4; | ||
module.exports.CITY_EDITION_REV1 = 2; | ||
module.exports.REGION_EDITION_REV1 = 3; | ||
module.exports.PROXY_EDITION = 8; | ||
@@ -41,2 +159,10 @@ module.exports.ASNUM_EDITION = 9; | ||
module.exports.COUNTRY_EDITION_V6 = 12; | ||
module.exports.LOCATIONA_EDITION = 13; | ||
module.exports.ACCURACYRADIUS_EDITION = 14; | ||
module.exports.CITYCONFIDENCE_EDITION = 15; /* unsupported */ | ||
module.exports.CITYCONFIDENCEDIST_EDITION = 16; /* unsupported */ | ||
module.exports.LARGE_COUNTRY_EDITION = 17; | ||
module.exports.LARGE_COUNTRY_EDITION_V6 = 18; | ||
module.exports.CITYCONFIDENCEDIST_ISP_ORG_EDITION = 19; /* unsued, but gaps are not allowed */ | ||
module.exports.CCM_COUNTRY_EDITION = 20; /* unsued, but gaps are not allowed */ | ||
module.exports.ASNUM_EDITION_V6 = 21; | ||
@@ -46,2 +172,7 @@ module.exports.ISP_EDITION_V6 = 22; | ||
module.exports.DOMAIN_EDITION_V6 = 24; | ||
module.exports.LOCATIONA_EDITION_V6 = 25; | ||
module.exports.REGISTRAR_EDITION = 26; | ||
module.exports.REGISTRAR_EDITION_V6 = 27; | ||
module.exports.USERTYPE_EDITION = 28; | ||
module.exports.USERTYPE_EDITION_V6 = 29; | ||
module.exports.CITY_EDITION_REV1_V6 = 30; | ||
@@ -51,1 +182,6 @@ module.exports.CITY_EDITION_REV0_V6 = 31; | ||
module.exports.NETSPEED_EDITION_REV1_V6 = 33; | ||
module.exports.COUNTRYCONF_EDITION = 34; | ||
module.exports.CITYCONF_EDITION = 35; | ||
module.exports.REGIONCONF_EDITION = 36; | ||
module.exports.POSTALCONF_EDITION = 37; | ||
module.exports.ACCURACYRADIUS_EDITION_V6 = 38; |
@@ -1,2 +0,2 @@ | ||
var Buff = require('./buff'), | ||
var Database = require('./database'), | ||
DatabaseInfo = require('./database_info'), | ||
@@ -9,3 +9,2 @@ Country = require('./country'), | ||
const US_OFFSET = 1; | ||
@@ -18,4 +17,2 @@ const CANADA_OFFSET = 677; | ||
const STATE_BEGIN_REV1 = 16000000; | ||
const STRUCTURE_INFO_MAX_SIZE = 20; | ||
const DATABASE_INFO_MAX_SIZE = 100; | ||
const GEOIP_STANDARD = 0; | ||
@@ -29,5 +26,2 @@ const GEOIP_MEMORY_CACHE = 1; | ||
const GEOIP_CORPORATE_SPEED = 3; | ||
const SEGMENT_RECORD_LENGTH = 3; | ||
const STANDARD_RECORD_LENGTH = 3; | ||
const ORG_RECORD_LENGTH = 4; | ||
const MAX_RECORD_LENGTH = 4; | ||
@@ -38,46 +32,54 @@ const MAX_ORG_RECORD_LENGTH = 300; | ||
var _dbs = []; | ||
var _inited = false; | ||
var _paths = []; | ||
var dboptions = null; | ||
var databaseType = DatabaseInfo.COUNTRY_EDITION; | ||
var databaseSegment = null; | ||
var recordLength = 0; | ||
var indexCache = new Buffer(0); | ||
var lastNetmask; | ||
var file; | ||
var dbbuffer; | ||
function _getDb(types) { | ||
for (var i = _dbs.length - 1; i >= 0; i--) { | ||
if (types.indexOf(_dbs[i].type) > -1) | ||
return _dbs[i]; | ||
} | ||
var available = _dbs.map(function(d) { | ||
return d.type; | ||
}).join(','); | ||
throw new Error('Required DB not available. Possible types: "' + available + '"'); | ||
} | ||
function _getDatabaseInfo() { | ||
function _makeCache(db) { | ||
var buf = new Buffer(2 * MAX_RECORD_LENGTH); | ||
var hasStructureInfo = false; | ||
var delim = new Buffer(3); | ||
function _buildIndex(depth, offset) { | ||
// Advance to part of file where database info is stored. | ||
file.seek(file.length() - 3); | ||
for (var i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) { | ||
var read = file.readFully(delim); | ||
if (read === 3 && (delim[0]&0xFF) === 255 && (delim[1]&0xFF) === 255 && (delim[2]&0xFF) === 255) { | ||
hasStructureInfo = true; | ||
break; | ||
db.dbbuffer.copy(buf, 0, 2 * db.recordLength * offset, | ||
(2 * db.recordLength * offset) + (2 * MAX_RECORD_LENGTH)); | ||
var x0 = 0, | ||
x1 = 0, | ||
y = 0; | ||
for (var j = 0; j < db.recordLength; j++) { | ||
y = buf[0 * db.recordLength + j]; | ||
x0 += (y << (j * 8)); | ||
y = buf[1 * db.recordLength + j]; | ||
x1 += (y << (j * 8)); | ||
} | ||
file.seek(file.getFilePointer() - 4); | ||
} | ||
if (hasStructureInfo) { | ||
file.seek(file.getFilePointer() - 6); | ||
} else { | ||
// No structure info, must be pre Sep 2002 database, go back to end. | ||
file.seek(file.length() - 3); | ||
db.cache[offset] = [ x0, x1 ]; | ||
depth--; | ||
// cache 10 levels only | ||
if (depth === 31 - 10) | ||
return null; | ||
if ((x0 * 2 * db.recordLength) + (2 * MAX_RECORD_LENGTH) < db.dbbuffer.length) | ||
_buildIndex(depth, x0); | ||
if ((x1 * 2 * db.recordLength) + (2 * MAX_RECORD_LENGTH)< db.dbbuffer.length) | ||
_buildIndex(depth, x1); | ||
} | ||
// Find the database info string. | ||
for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) { | ||
file.readFully(delim); | ||
if (delim[0] + delim[1] + delim[2] === 0) { | ||
var dbInfo = new Buffer(i); | ||
file.readFully(dbInfo); | ||
return new DatabaseInfo(dbInfo); | ||
} | ||
file.seek(file.getFilePointer() -4); | ||
} | ||
return null; | ||
db.cache = {}; | ||
_buildIndex(31, 0); | ||
} | ||
@@ -101,179 +103,31 @@ | ||
module.exports.databaseInfo = null; | ||
module.exports.inited = false; | ||
module.exports.path = null; | ||
module.exports.init = function(path, opts) { | ||
module.exports.init = function(paths, opts) { | ||
// already initialized | ||
if (path === this.path && this.inited) | ||
return true; | ||
if (typeof paths === 'string') | ||
paths = [ paths ]; | ||
dboptions = GEOIP_STANDARD; | ||
for (var i = 0; i < paths.length; i++) { | ||
var path = paths[i]; | ||
// already initialized | ||
if (_paths.indexOf(path) > -1) | ||
continue; | ||
if (opts !== undefined && opts.indexCache) | ||
dboptions |= GEOIP_INDEX_CACHE; | ||
if (opts !== undefined && opts.memoryCache) | ||
dboptions |= GEOIP_MEMORY_CACHE; | ||
file = new Buff(path); | ||
_cache = null; | ||
var i, j, l; | ||
var delim = new Buffer(3); | ||
var buf = new Buffer(SEGMENT_RECORD_LENGTH); | ||
if (!file) | ||
throw new Error('Invalid file'); | ||
file.seek(file.length() - 3); | ||
for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) { | ||
file.readFully(delim); | ||
if (delim.readInt8(0) === -1 && delim.readInt8(1) === -1 && delim.readInt8(2) === -1) { | ||
databaseType = file.readByte(); | ||
if (databaseType >= 106) { | ||
// Backward compatibility with databases from April 2003 and earlier | ||
databaseType -= 105; | ||
} | ||
// Determine the database type. | ||
if (databaseType === DatabaseInfo.REGION_EDITION_REV0) { | ||
databaseSegment = STATE_BEGIN_REV0; | ||
recordLength = STANDARD_RECORD_LENGTH; | ||
} else if (databaseType === DatabaseInfo.REGION_EDITION_REV1){ | ||
databaseSegment = STATE_BEGIN_REV1; | ||
recordLength = STANDARD_RECORD_LENGTH; | ||
} else if (databaseType === DatabaseInfo.CITY_EDITION_REV0 || | ||
databaseType === DatabaseInfo.CITY_EDITION_REV1 || | ||
databaseType === DatabaseInfo.ORG_EDITION || | ||
databaseType === DatabaseInfo.ORG_EDITION_V6 || | ||
databaseType === DatabaseInfo.ISP_EDITION || | ||
databaseType === DatabaseInfo.ISP_EDITION_V6 || | ||
databaseType === DatabaseInfo.DOMAIN_EDITION || | ||
databaseType === DatabaseInfo.DOMAIN_EDITION_V6 || | ||
databaseType === DatabaseInfo.ASNUM_EDITION || | ||
databaseType === DatabaseInfo.ASNUM_EDITION_V6 || | ||
databaseType === DatabaseInfo.NETSPEED_EDITION_REV1 || | ||
databaseType === DatabaseInfo.NETSPEED_EDITION_REV1_V6 || | ||
databaseType === DatabaseInfo.CITY_EDITION_REV0_V6 || | ||
databaseType === DatabaseInfo.CITY_EDITION_REV1_V6 | ||
) { | ||
databaseSegment = 0; | ||
if (databaseType === DatabaseInfo.CITY_EDITION_REV0 || | ||
databaseType === DatabaseInfo.CITY_EDITION_REV1 || | ||
databaseType === DatabaseInfo.ASNUM_EDITION_V6 || | ||
databaseType === DatabaseInfo.NETSPEED_EDITION_REV1 || | ||
databaseType === DatabaseInfo.NETSPEED_EDITION_REV1_V6 || | ||
databaseType === DatabaseInfo.CITY_EDITION_REV0_V6 || | ||
databaseType === DatabaseInfo.CITY_EDITION_REV1_V6 || | ||
databaseType === DatabaseInfo.ASNUM_EDITION | ||
) { | ||
recordLength = STANDARD_RECORD_LENGTH; | ||
} else { | ||
recordLength = ORG_RECORD_LENGTH; | ||
} | ||
file.readFully(buf); | ||
for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) { | ||
databaseSegment += buf.readUInt8(j) << (j * 8); | ||
} | ||
} | ||
break; | ||
} else { | ||
file.seek(file.getFilePointer() - 4); | ||
} | ||
_dbs.push(new Database(path, opts)); | ||
} | ||
if (databaseType === DatabaseInfo.COUNTRY_EDITION || | ||
databaseType === DatabaseInfo.COUNTRY_EDITION_V6 || | ||
databaseType === DatabaseInfo.PROXY_EDITION || | ||
databaseType === DatabaseInfo.NETSPEED_EDITION | ||
) { | ||
databaseSegment = COUNTRY_BEGIN; | ||
recordLength = STANDARD_RECORD_LENGTH; | ||
} | ||
_inited = true; | ||
_paths = paths; | ||
this.databaseInfo = _getDatabaseInfo(); | ||
if ((dboptions & GEOIP_MEMORY_CACHE) !== 0) { | ||
l = file.length(); | ||
dbbuffer = new Buffer(l); | ||
file.seek(0); | ||
file.readFully(dbbuffer, 0, l); | ||
file.close(); | ||
} | ||
if ((dboptions & GEOIP_INDEX_CACHE) !== 0) { | ||
l = databaseSegment * recordLength * 2; | ||
indexCache = new Buffer(l); | ||
if (indexCache !== null) { | ||
file.seek(0); | ||
file.readFully(indexCache, 0, l); | ||
} | ||
} else { | ||
indexCache = null; | ||
} | ||
this.inited = true; | ||
this.path = path; | ||
return true; | ||
}; | ||
var _cache = null; | ||
module.exports.seekCountry = function(db, ipAddress) { | ||
function _makeCache() { | ||
var buf = new Buffer(2 * MAX_RECORD_LENGTH); | ||
function _buildIndex(depth, offset) { | ||
dbbuffer.copy(buf, 0, 2 * recordLength * offset, (2 * recordLength * offset) + (2 * MAX_RECORD_LENGTH)); | ||
var x0 = 0, | ||
x1 = 0, | ||
y = 0; | ||
for (var j = 0; j<recordLength; j++) { | ||
y = buf[0*recordLength+j]; | ||
x0 += (y << (j * 8)); | ||
y = buf[1*recordLength+j]; | ||
x1 += (y << (j * 8)); | ||
} | ||
_cache[offset] = [ x0, x1 ]; | ||
depth--; | ||
// cache 10 levels only | ||
if (depth === 31 - 10) | ||
return null; | ||
if ((x0 * 2 * recordLength) + (2 * MAX_RECORD_LENGTH) < dbbuffer.length) | ||
_buildIndex(depth, x0); | ||
if ((x1 * 2 * recordLength) + (2 * MAX_RECORD_LENGTH)< dbbuffer.length) | ||
_buildIndex(depth, x1); | ||
} | ||
_cache = {}; | ||
_buildIndex(31, 0); | ||
} | ||
module.exports.seekCountry = function(ipAddress) { | ||
var buf = new Buffer(2 * MAX_RECORD_LENGTH); | ||
if (_cache === null) { | ||
if ((dboptions & GEOIP_MEMORY_CACHE) !== 0) | ||
_makeCache(); | ||
if (db.cache === null) { | ||
if ((db.dboptions & GEOIP_MEMORY_CACHE) !== 0) | ||
_makeCache(db); | ||
else | ||
_cache = {}; | ||
db.cache = {}; | ||
} | ||
@@ -288,3 +142,3 @@ | ||
for (var depth = 31; depth >= 0; depth--) { | ||
var cache = _cache[offset]; | ||
var cache = db.cache[offset]; | ||
@@ -297,8 +151,8 @@ if (cache !== undefined) { | ||
// read from memory | ||
if ((dboptions & GEOIP_MEMORY_CACHE) !== 0) { | ||
buf = new DynBuffer(dbbuffer, 2 * recordLength * offset, 2 * MAX_RECORD_LENGTH); | ||
if ((db.dboptions & GEOIP_MEMORY_CACHE) !== 0) { | ||
buf = new DynBuffer(db.dbbuffer, 2 * db.recordLength * offset, 2 * MAX_RECORD_LENGTH); | ||
// read from index cache | ||
} else if ((dboptions & GEOIP_INDEX_CACHE) !== 0) { | ||
buf = new DynBuffer(indexCache, 2 * recordLength * offset, 2 * MAX_RECORD_LENGTH); | ||
} else if ((db.dboptions & GEOIP_INDEX_CACHE) !== 0) { | ||
buf = new DynBuffer(db.indexCache, 2 * db.recordLength * offset, 2 * MAX_RECORD_LENGTH); | ||
@@ -308,4 +162,4 @@ // read from disk | ||
buf = new DynBuffer(new Buffer(2 * MAX_RECORD_LENGTH), 0, 2 * MAX_RECORD_LENGTH); | ||
file.seek(2 * recordLength * offset); | ||
file.readFully(buf.source); | ||
db.file.seek(2 * db.recordLength * offset); | ||
db.file.readFully(buf.source); | ||
} | ||
@@ -316,7 +170,7 @@ | ||
for (var j = 0; j<recordLength; j++) { | ||
y = buf.at(0*recordLength+j); | ||
for (var j = 0; j<db.recordLength; j++) { | ||
y = buf.at(0*db.recordLength+j); | ||
x0 += (y << (j * 8)); | ||
y = buf.at(1*recordLength+j); | ||
y = buf.at(1*db.recordLength+j); | ||
x1 += (y << (j * 8)); | ||
@@ -329,4 +183,4 @@ } | ||
if (Math.abs(ipAddress & (1 << depth)) > 0) { | ||
if (x1 >= databaseSegment) { | ||
lastNetmask = 32 - depth; | ||
if (x1 >= db.segment) { | ||
db.lastNetmask = 32 - depth; | ||
return x1; | ||
@@ -336,4 +190,4 @@ } | ||
} else { | ||
if (x0 >= databaseSegment) { | ||
lastNetmask = 32 - depth; | ||
if (x0 >= db.segment) { | ||
db.lastNetmask = 32 - depth; | ||
return x0; | ||
@@ -350,6 +204,14 @@ } | ||
module.exports.getCountry = function(ipAddress) { | ||
var db = _getDb([ | ||
DatabaseInfo.COUNTRY_EDITION, | ||
DatabaseInfo.LARGE_COUNTRY_EDITION, | ||
DatabaseInfo.PROXY_EDITION, | ||
DatabaseInfo.NETSPEED_EDITION | ||
]); | ||
if (typeof ipAddress === "string") | ||
ipAddress = this.ip2Long(ipAddress); | ||
var ret = this.seekCountry(ipAddress) - COUNTRY_BEGIN; | ||
var ret = this.seekCountry(db, ipAddress) - COUNTRY_BEGIN; | ||
@@ -364,2 +226,7 @@ if (ret === 0) | ||
var db = _getDb([ | ||
DatabaseInfo.CITY_EDITION_REV0, | ||
DatabaseInfo.CITY_EDITION_REV1 | ||
]); | ||
if (typeof ipnum === "string") | ||
@@ -379,20 +246,19 @@ ipnum = this.ip2Long(ipnum); | ||
seekCountry = this.seekCountry(ipnum); | ||
seekCountry = this.seekCountry(db, ipnum); | ||
if (seekCountry === databaseSegment) | ||
if (seekCountry === db.segment) | ||
return null; | ||
recordPointer = seekCountry + (2 * recordLength - 1) * databaseSegment; | ||
recordPointer = seekCountry + (2 * db.recordLength - 1) * db.segment; | ||
if ((dboptions & GEOIP_MEMORY_CACHE) !== 0) { | ||
recordBuf = new DynBuffer(dbbuffer, recordPointer, | ||
Math.min(dbbuffer.length - recordPointer, FULL_RECORD_LENGTH)); | ||
if ((db.dboptions & GEOIP_MEMORY_CACHE) !== 0) { | ||
recordBuf = new DynBuffer(db.dbbuffer, recordPointer, | ||
Math.min(db.dbbuffer.length - recordPointer, FULL_RECORD_LENGTH)); | ||
} else { | ||
//read from disk | ||
recordBuf = new DynBuffer(new Buffer(FULL_RECORD_LENGTH), 0, FULL_RECORD_LENGTH); | ||
file.seek(recordPointer); | ||
file.readFully(recordBuf.source); | ||
db.file.seek(recordPointer); | ||
db.file.readFully(recordBuf.source); | ||
} | ||
// get country | ||
@@ -403,3 +269,2 @@ record.countryCode = countries.codes[recordBuf.readUInt8(0)]; | ||
// get region | ||
@@ -415,3 +280,2 @@ while (recordBuf.at(recordBufOffset + pointer) !== 0x00) | ||
// get city | ||
@@ -427,3 +291,2 @@ while (recordBuf.at(recordBufOffset + pointer) !== 0x00) | ||
// get postal code | ||
@@ -456,3 +319,3 @@ while (recordBuf.at(recordBufOffset + pointer) !== 0x00) | ||
if (databaseType === DatabaseInfo.CITY_EDITION_REV1) { | ||
if (db.type === DatabaseInfo.CITY_EDITION_REV1) { | ||
// get DMA code | ||
@@ -476,2 +339,7 @@ var metroareaCombo = 0; | ||
var db = _getDb([ | ||
DatabaseInfo.REGION_EDITION_REV0, | ||
DatabaseInfo.REGION_EDITION_REV1 | ||
]); | ||
if (typeof ipnum === "string") | ||
@@ -483,4 +351,4 @@ ipnum = this.ip2Long(ipnum); | ||
if (databaseType === DatabaseInfo.REGION_EDITION_REV0) { | ||
seekRegion = this.seekCountry(ipnum) - STATE_BEGIN_REV0; | ||
if (db.type === DatabaseInfo.REGION_EDITION_REV0) { | ||
seekRegion = this.seekCountry(db, ipnum) - STATE_BEGIN_REV0; | ||
@@ -501,4 +369,4 @@ if (seekRegion >= 1000) { | ||
} else if (databaseType === DatabaseInfo.REGION_EDITION_REV1) { | ||
seekRegion = this.seekCountry(ipnum) - STATE_BEGIN_REV1; | ||
} else if (db.type === DatabaseInfo.REGION_EDITION_REV1) { | ||
seekRegion = this.seekCountry(db, ipnum) - STATE_BEGIN_REV1; | ||
@@ -538,2 +406,18 @@ if (seekRegion < US_OFFSET) { | ||
var db = _getDb([ | ||
DatabaseInfo.ORG_EDITION, | ||
DatabaseInfo.ISP_EDITION, | ||
DatabaseInfo.DOMAIN_EDITION, | ||
DatabaseInfo.ASNUM_EDITION, | ||
DatabaseInfo.ACCURACYRADIUS_EDITION, | ||
DatabaseInfo.NETSPEED_EDITION_REV1, | ||
DatabaseInfo.USERTYPE_EDITION, | ||
DatabaseInfo.REGISTRAR_EDITION, | ||
DatabaseInfo.LOCATIONA_EDITION, | ||
DatabaseInfo.CITYCONF_EDITION, | ||
DatabaseInfo.COUNTRYCONF_EDITION, | ||
DatabaseInfo.REGIONCONF_EDITION, | ||
DatabaseInfo.POSTALCONF_EDITION | ||
]); | ||
if (typeof ipnum === "string") | ||
@@ -547,16 +431,16 @@ ipnum = this.ip2Long(ipnum); | ||
seekCountry = this.seekCountry(ipnum); | ||
seekCountry = this.seekCountry(db, ipnum); | ||
if (seekCountry === databaseSegment) | ||
if (seekCountry === db.segment) | ||
return null; | ||
recordPointer = seekCountry + (2 * recordLength - 1) * databaseSegment; | ||
if ((dboptions & GEOIP_MEMORY_CACHE) !== 0) { | ||
recordBuf = new DynBuffer(dbbuffer, recordPointer, | ||
Math.min(dbbuffer.length - recordPointer, MAX_ORG_RECORD_LENGTH)); | ||
recordPointer = seekCountry + (2 * db.recordLength - 1) * db.segment; | ||
if ((db.dboptions & GEOIP_MEMORY_CACHE) !== 0) { | ||
recordBuf = new DynBuffer(db.dbbuffer, recordPointer, | ||
Math.min(db.dbbuffer.length - recordPointer, MAX_ORG_RECORD_LENGTH)); | ||
} else { | ||
//read from disk | ||
recordBuf = new DynBuffer(new Buffer(MAX_ORG_RECORD_LENGTH), 0, MAX_ORG_RECORD_LENGTH); | ||
file.seek(recordPointer); | ||
file.readFully(recordBuf.source); | ||
db.file.seek(recordPointer); | ||
db.file.readFully(recordBuf.source); | ||
} | ||
@@ -570,13 +454,14 @@ | ||
module.exports.uninit = function() { | ||
this.databaseInfo = null; | ||
this.inited = false; | ||
dboptions = GEOIP_STANDARD; | ||
if (file) { | ||
file.close(); | ||
file = null; | ||
for (var i = _dbs.length - 1; i >= 0; i--) { | ||
var db = _dbs[i]; | ||
if (db.file) { | ||
db.file.close(); | ||
db.file = null; | ||
} | ||
} | ||
_cache = null; | ||
_dbs = []; | ||
_paths = []; | ||
_inited = false; | ||
return true; | ||
}; |
{ | ||
"name": "maxmind", | ||
"version": "0.1.7", | ||
"version": "0.2.0", | ||
"homepage": "https://github.com/runk/node-maxmind", | ||
@@ -5,0 +5,0 @@ "description": "IP lookup using Maxmind databases", |
@@ -53,2 +53,13 @@ | ||
You can initialize module with several databases, and they will be automatically selected for lookup requests. | ||
If any options were given they apply for all databases you want to initialize. | ||
```js | ||
var maxmind = require('maxmind'); | ||
maxmind.init(['/path/to/GeoLiteCity.dat', '/path/to/GeoIPASNum.dat']); | ||
// not both org and location lookups will work | ||
console.log(maxmind.getOrganization("66.6.44.4")); | ||
console.log(maxmind.getLocation("66.6.44.4")); | ||
``` | ||
## Caching | ||
@@ -55,0 +66,0 @@ |
var assert = require('assert'), | ||
ls = require('../lib/lookup_service'), | ||
DatabaseInfo = require('../lib/database_info'), | ||
Country = require('../lib/Country'), | ||
Location = require('../lib/Location'); | ||
Database = require('../lib/database'); | ||
const GEO_CITY = __dirname + '/dbs/GeoLiteCity.dat'; | ||
const GEO_CITY = __dirname + '/dbs/GeoIPCity.dat'; | ||
const GEO_CITY_FULL = __dirname + '/dbs/GeoIPCity_FULL.dat'; | ||
@@ -18,19 +15,11 @@ const GEO_COUNTRY = __dirname + '/dbs/GeoIP.dat'; | ||
it('inited prop should be false', function() { | ||
assert.equal(ls.inited, false); | ||
}); | ||
it('should initialize', function() { | ||
it('should initialize with single db', function() { | ||
ls.uninit(); | ||
assert.equal(ls.init(GEO_CITY), true); | ||
}); | ||
it('should throw error for invalid path', function() { | ||
assert.throws(function() { | ||
ls.init(__dirname + '/dbs/blah') | ||
}); | ||
it('should initialize with multiply dbs', function() { | ||
ls.uninit(); | ||
assert.equal(ls.init([GEO_CITY, GEO_ASN]), true); | ||
}); | ||
it('inited prop should be true', function() { | ||
assert.equal(ls.inited, true); | ||
}); | ||
}); | ||
@@ -45,26 +34,8 @@ | ||
assert.equal(result, 3276048658); | ||
}); | ||
}); | ||
describe('.databaseInfo', function() { | ||
it('inited prop should be true', function() { | ||
assert.equal(ls.inited, true); | ||
}); | ||
it('should return proper DatabaseInfo', function() { | ||
var info = ls.databaseInfo; | ||
assert.ok(info instanceof DatabaseInfo); | ||
assert.equal(info.getType(), 428); | ||
assert.equal(info.isPremium(), true); | ||
assert.equal(info.getDate().getTime(), 1361232000000); | ||
assert.equal(info.toString(), "GEO-533LITE 20130219 Build 1 Copyright (c) 2012 MaxMind Inc All Rights Reserved"); | ||
}); | ||
}); | ||
describe('#getCountry', function() { | ||
it('should init with country db', function() { | ||
assert.equal(ls.init(GEO_COUNTRY), true); | ||
assert.equal(ls.inited, true); | ||
}); | ||
@@ -95,8 +66,8 @@ | ||
it("should perform binary search", function() { | ||
assert.equal(ls.init(GEO_CITY_FULL), true); | ||
var db = new Database(GEO_CITY_FULL); | ||
var iplong = ls.ip2Long('195.68.137.18'); | ||
assert.equal(ls.seekCountry(iplong), 9150727); | ||
assert.equal(ls.seekCountry(db, iplong), 9150727); | ||
iplong = ls.ip2Long('210.250.100.200'); | ||
assert.equal(ls.seekCountry(iplong), 8067695); | ||
assert.equal(ls.seekCountry(db, iplong), 8067695); | ||
}); | ||
@@ -108,3 +79,2 @@ }); | ||
assert.equal(ls.init(GEO_CITY_FULL), true); | ||
assert.equal(ls.inited, true); | ||
}); | ||
@@ -170,3 +140,2 @@ | ||
assert.equal(ls.init(GEO_ASN), true); | ||
assert.equal(ls.inited, true); | ||
}); | ||
@@ -173,0 +142,0 @@ |
@@ -5,7 +5,28 @@ | ||
const GEO_CITY = __dirname + '/dbs/GeoLiteCity.dat'; | ||
const GEO_CITY = __dirname + '/dbs/GeoIPCity.dat'; | ||
const GEO_COUNTRY = __dirname + '/dbs/GeoIP.dat'; | ||
const GEO_ASN = __dirname + '/dbs/GeoIPASNum.dat'; | ||
describe('lib/lookup_service', function() { | ||
describe('* multi mode * ', function() { | ||
it('should return correct country with default opts', function() { | ||
assert.equal(ls.uninit(), true); | ||
assert.equal(ls.init([GEO_COUNTRY, GEO_ASN]), true); | ||
var c = ls.getCountry('109.60.171.33'); | ||
assert.equal(c.getName(), 'Russian Federation'); | ||
assert.equal(c.getCode(), 'RU'); | ||
var org = ls.getOrganization('109.60.171.33'); | ||
assert.equal(org, 'AS47241 CJSC "Ivtelecom"'); | ||
}); | ||
it('should throw exception for unavailable dbs', function() { | ||
assert.throws(function() { | ||
ls.getRegion('109.60.171.33'); | ||
}); | ||
}); | ||
}); | ||
describe('* modes * ', function() { | ||
@@ -40,3 +61,2 @@ | ||
it('should return correct country with default opts', function() { | ||
@@ -43,0 +63,0 @@ assert.equal(ls.uninit(), true); |
@@ -6,3 +6,3 @@ | ||
const GEO_CITY = __dirname + '/dbs/GeoLiteCity.dat'; | ||
const GEO_CITY = __dirname + '/dbs/GeoIPCity.dat'; | ||
@@ -13,3 +13,2 @@ describe('lib/region_name', function() { | ||
assert.equal(ls.init(GEO_CITY), true); | ||
assert.equal(ls.inited, true); | ||
}); | ||
@@ -16,0 +15,0 @@ |
@@ -6,3 +6,3 @@ | ||
const GEO_CITY = __dirname + '/dbs/GeoLiteCity.dat'; | ||
const GEO_CITY = __dirname + '/dbs/GeoIPCity.dat'; | ||
@@ -13,3 +13,2 @@ describe('lib/time_zone', function() { | ||
assert.equal(ls.init(GEO_CITY), true); | ||
assert.equal(ls.inited, true); | ||
}); | ||
@@ -16,0 +15,0 @@ |
179506
33
6981
98