Skip to content

Commit

Permalink
No longer use a binary file. (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
roim authored May 11, 2021
1 parent 1bafc37 commit 2f43bc3
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 68 deletions.
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is a zero-dependency, super small, IP address to 2-letter [country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) lookup library. There are already several libraries available, but none met our requirements for binary size and speed.

This project in its entirety is <450KB, compared to most alternatives out there that are north of 40MB (but they provide a lot more features).
This project in its entirety is <500KB, compared to most alternatives out there that are north of 40MB (but might provide more than just countries).

The database used in this project is compacted from [IP2Location](https://lite.ip2location.com/database/ip-country). Their DB1.LITE edition is provided under CCA, with the attribution below:

Expand All @@ -24,10 +24,7 @@ $ npm install ip3country
// Setup
const ip3country = require("ip3country");

await ip3country.init();

// Or if you want sync
// ip3country.initSync();
ip3country.init();

// Lookup using ip4 str
ip3country.lookupStr("123.45.67.8"); // 'KR'.
Expand Down
Binary file removed bin/ip_supalite.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ip3country",
"version": "2.0.0",
"version": "3.0.0",
"description": "This is a no-dependency, super lite version of IP2Location LITE lookup.",
"main": "src/ip3country.js",
"types": "types/ip3country.d.ts",
Expand Down
60 changes: 15 additions & 45 deletions src/ip3country.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,21 @@
const fs = require("fs/promises");
const fsSync = require("fs");
const path = require("path");

const ip3country = {
countryCodes: [],
ipRanges: [],
countryTable: [],

/*
The binary is packed as follows:
c1.c2.c3.....**: Country code look up table, terminated by **
n1.c: if n is < 240, c is country code index
242.n2.n3.c: if n >= 240 but < 65536. n2 being lower order byte
243.n2.n3.n4.c: if n >= 65536. n2 being lower order byte
*/
init: async function () {
init: function () {
if (this._initCalled) {
console.warn("You can call init just once");
return;
}

this._initCalled = true;
const ip_supalite = require("./ip_supalite");

const buffer = await fs.readFile(
path.resolve("../bin/ip_supalite.bin")
);
this.initWithBuffer(buffer);
},

initSync: function () {
if (this._initCalled) {
console.warn("You can call init just once");
return;
}

this._initCalled = true;

const buffer = fsSync.readFileSync(
path.resolve(__dirname, "../bin/ip_supalite.bin")
);
this.initWithBuffer(buffer);
},

initWithBuffer: function (buffer) {
let index = 0;
while (index < buffer.length) {
const c1 = buffer[index++];
const c2 = buffer[index++];
while (index < ip_supalite.length) {
const c1 = ip_supalite[index++];
const c2 = ip_supalite[index++];
this.countryTable.push(
"" + String.fromCharCode(c1) + String.fromCharCode(c2)
);
Expand All @@ -57,27 +25,29 @@ const ip3country = {
}

let lastEndRange = 0;
while (index < buffer.length) {
while (index < ip_supalite.length) {
let count = 0;
const n1 = buffer[index++];
const n1 = ip_supalite[index++];
if (n1 < 240) {
count = n1;
} else if (n1 == 242) {
const n2 = buffer[index++];
const n3 = buffer[index++];
const n2 = ip_supalite[index++];
const n3 = ip_supalite[index++];
count = n2 | (n3 << 8);
} else if (n1 == 243) {
const n2 = buffer[index++];
const n3 = buffer[index++];
const n4 = buffer[index++];
const n2 = ip_supalite[index++];
const n3 = ip_supalite[index++];
const n4 = ip_supalite[index++];
count = n2 | (n3 << 8) | (n4 << 16);
}

lastEndRange += count * 256;
const cc = buffer[index++];
const cc = ip_supalite[index++];
this.ipRanges.push(lastEndRange);
this.countryCodes.push(this.countryTable[cc]);
}

delete require.cache[require.resolve("./ip_supalite")];
},

lookupStr: function (ipaddrstr) {
Expand Down
Binary file added src/ip_supalite.js
Binary file not shown.
12 changes: 7 additions & 5 deletions tests/lookupTest.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const ip3country = require('../src/ip3country');
const ip3country = require("../src/ip3country");

async function runExhaustiveTests() {
await ip3country.init();
Expand All @@ -11,7 +11,7 @@ async function runExhaustiveTests() {

let failed = false;
for (var jj = min; jj < max; jj++) {
const result = ip3country.lookupNumeric(jj);
const result = ip3country.lookupNumeric(jj);
failed = verify(result, expected, jj);
if (failed) {
break;
Expand All @@ -25,7 +25,7 @@ async function runExhaustiveTests() {
}

function runRandomTests() {
ip3country.initSync();
ip3country.init();
console.dir(ip3country);

let failed = false;
Expand All @@ -42,12 +42,14 @@ function runRandomTests() {
}
}

console.log(failed ? "---Random tests failed---" : "---Random tests passed---")
console.log(
failed ? "---Random tests failed---" : "---Random tests passed---"
);
}

function verify(result, expected, index) {
if (result === null) {
result = '--';
result = "--";
}
if (expected === result) {
return true;
Expand Down
16 changes: 4 additions & 12 deletions types/ip3country.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,12 @@ export = ip3country;

declare namespace ip3country {
/**
* Initializes ip3country asynchronously.
* Must be called once before any lookups.
*/
function init(): Promise<void>;

/**
* Initializes ip3country synchronously.
* Must be called once before any lookups.
* Initializes ip3country. Must be called once before any lookups.
*
* `init` is preferred. This synchronous version is provided as an utility in
* cases where you can't run asynchronous code. It is not simply a synchronous
* wrapper--it replaces all async calls with sync calls.
* This is relatively CPU intensive so call it during application startup if
* possible.
*/
function initSync(): void;
function init(): void;

/**
* Returns a 2-digit country code for the given IP Address. Returns `null` if
Expand Down

0 comments on commit 2f43bc3

Please sign in to comment.