diff --git a/binding/javascript/index.d.ts b/binding/javascript/index.d.ts new file mode 100644 index 0000000..727fbe6 --- /dev/null +++ b/binding/javascript/index.d.ts @@ -0,0 +1,83 @@ +// Copyright 2022 The Ip2Region Authors. All rights reserved. +// Use of this source code is governed by a Apache2.0-style +// license that can be found in the LICENSE file. + +// Type definitions for ip2region +// @Author Lion + +export declare class Header { + version: number; + indexPolicy: number; + createdAt: number; + startIndexPtr: number; + endIndexPtr: number; + ipVersion: number; + runtimePtrBytes: number; + buff: Buffer; + + constructor(buff: Buffer); + toString(): string; +} + +export declare class Version { + id: number; + name: string; + bytes: number; + indexSize: number; + ipCompareFunc: (ip1: Buffer, ip2: Buffer, offset: number) => number; + + constructor(id: number, name: string, bytes: number, indexSize: number, ipCompareFunc: (ip1: Buffer, ip2: Buffer, offset: number) => number); + ipCompare(ip1: Buffer, ip2: Buffer): number; + ipSubCompare(ip1: Buffer, ip2: Buffer, offset: number): number; + toString(): string; +} + +export declare class Searcher { + ioCount: number; + version: Version; + handle: number | null; + vectorIndex: Buffer | null; + cBuffer: Buffer | null; + + constructor(version: Version, dbPath: string | null, vectorIndex: Buffer | null, cBuffer: Buffer | null); + getIOCount(): number; + search(ip: string | Buffer): string; + read(offset: number, buff: Buffer, stats?: any): void; + close(): void; +} + +// Constants +export declare const XdbStructure20: 2; +export declare const XdbStructure30: 3; +export declare const XdbIPv4Id: 4; +export declare const XdbIPv6Id: 6; +export declare const HeaderInfoLength: 256; +export declare const VectorIndexRows: 256; +export declare const VectorIndexCols: 256; +export declare const VectorIndexSize: 8; + +// Version instances +export declare const IPv4: Version; +export declare const IPv6: Version; + +// Utility functions +export declare function parseIP(ipString: string): Buffer; +export declare function ipToString(ipBytes: Buffer, compress?: boolean): string; +export declare function ipBytesString(ipBytes: Buffer): string; +export declare function ipSubCompare(ip1: Buffer, buff: Buffer, offset: number): number; +export declare function ipCompare(ip1: Buffer, ip2: Buffer): number; +export declare function versionFromName(name: string): Version | null; +export declare function versionFromHeader(h: Header): Version | null; + +// File operations +export declare function loadHeader(fd: number): Header; +export declare function loadHeaderFromFile(dbPath: string): Header; +export declare function loadVectorIndex(fd: number): Buffer; +export declare function loadVectorIndexFromFile(dbPath: string): Buffer; +export declare function loadContent(fd: number): Buffer; +export declare function loadContentFromFile(dbPath: string): Buffer; + +// Searcher factory functions +export declare function newWithFileOnly(version: Version, dbPath: string): Searcher; +export declare function newWithVectorIndex(version: Version, dbPath: string, vectorIndex: Buffer): Searcher; +export declare function newWithBuffer(version: Version, cBuffer: Buffer): Searcher; \ No newline at end of file diff --git a/binding/javascript/index.js b/binding/javascript/index.js new file mode 100644 index 0000000..5b40a81 --- /dev/null +++ b/binding/javascript/index.js @@ -0,0 +1,41 @@ +// Copyright 2022 The Ip2Region Authors. All rights reserved. +// Use of this source code is governed by a Apache2.0-style +// license that can be found in the LICENSE file. + +// ip2region JavaScript binding with IPv4 and IPv6 support. +// @Author Lion + +export { + Searcher, + newWithFileOnly, + newWithVectorIndex, + newWithBuffer +} from './searcher.js'; + +export { + Header, + Version, + IPv4, + IPv6, + XdbStructure20, + XdbStructure30, + XdbIPv4Id, + XdbIPv6Id, + HeaderInfoLength, + VectorIndexRows, + VectorIndexCols, + VectorIndexSize, + parseIP, + ipToString, + ipBytesString, + ipSubCompare, + ipCompare, + versionFromName, + versionFromHeader, + loadHeader, + loadHeaderFromFile, + loadVectorIndex, + loadVectorIndexFromFile, + loadContent, + loadContentFromFile +} from './util.js'; \ No newline at end of file diff --git a/binding/javascript/ip2region.js b/binding/javascript/ip2region.js deleted file mode 100644 index d130d28..0000000 --- a/binding/javascript/ip2region.js +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Ip2Region Authors. All rights reserved. -// Use of this source code is governed by a Apache2.0-style -// license that can be found in the LICENSE file. - -// ip2region.js -// @Author Lion - -// Re-export all utilities and searcher functions -export * from './util.js'; -export * from './searcher.js'; \ No newline at end of file diff --git a/binding/javascript/package.json b/binding/javascript/package.json index 0e526e8..5720739 100644 --- a/binding/javascript/package.json +++ b/binding/javascript/package.json @@ -3,7 +3,8 @@ "version": "3.0.0", "description": "javascript binding for ip2region with both IPv4 and IPv6 supported ", "type": "module", - "main": "ip2region.js", + "main": "index.js", + "types": "index.d.ts", "scripts": { "test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest" }, @@ -36,6 +37,9 @@ }, "homepage": "https://github.com/lionsoul2014/ip2region#readme", "devDependencies": { - "jest": "^30.2.0" + "@types/jest": "^30.0.0", + "jest": "^30.2.0", + "ts-jest": "^29.4.5", + "typescript": "^5.9.3" } } diff --git a/binding/javascript/searcher.js b/binding/javascript/searcher.js index 39c8192..9419825 100644 --- a/binding/javascript/searcher.js +++ b/binding/javascript/searcher.js @@ -31,7 +31,7 @@ export class Searcher { return this.ioCount; } - search(ip) { + async search(ip) { // check and parse the string ip const ipBytes = Buffer.isBuffer(ip) ? ip : parseIP(ip); diff --git a/binding/javascript/tests/search.test.js b/binding/javascript/tests/search.test.js index 38584f9..2083bd4 100644 --- a/binding/javascript/tests/search.test.js +++ b/binding/javascript/tests/search.test.js @@ -5,8 +5,7 @@ // searcher search tester // @Author Lion -import {IPv4, IPv6, parseIP, ipToString} from '../util.js'; -import {newWithFileOnly} from '../searcher.js'; +import {IPv4, IPv6, parseIP, ipToString, newWithFileOnly} from '../index.js'; import path from 'path'; import { fileURLToPath } from 'url'; @@ -16,28 +15,26 @@ const dbPath = { v6: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v6.xdb') } -test('ipv4 search test', () => { - try { - let searcher = newWithFileOnly(IPv4, dbPath.v4); - let ip_list = [ - '1.0.0.0', - parseIP('113.118.112.93'), - '240e:3b7::' - ]; +test('ipv4 search test', async () => { + let searcher = newWithFileOnly(IPv4, dbPath.v4); + let ip_list = [ + '1.0.0.0', + parseIP('113.118.112.93'), + '240e:3b7::' + ]; - for (var i = 0; i < ip_list.length; i++) { - let ip = ip_list[i]; - let region = searcher.search(ip); + for (var i = 0; i < ip_list.length; i++) { + let ip = ip_list[i]; + searcher.search(ip).then((region)=>{ let ipStr = Buffer.isBuffer(ip) ? ipToString(ip) : ip; console.log(`search(${ipStr}): {region: ${region}, ioCount: ${searcher.getIOCount()}}`); - } - } catch (e) { - console.log(`${e.message}`); + }).catch((err) => { + console.log(`${err.message}`); + }); } }); test('ipv6 search test', async () => { - try { let searcher = newWithFileOnly(IPv6, dbPath.v6); let ip_list = [ '2a02:26f7:c409:4001::', @@ -48,11 +45,11 @@ test('ipv6 search test', async () => { for (var i = 0; i < ip_list.length; i++) { let ip = ip_list[i]; - let region = searcher.search(ip); - let ipStr = Buffer.isBuffer(ip) ? ipToString(ip) : ip; - console.log(`search(${ipStr}): {region: ${region}, ioCount: ${searcher.getIOCount()}}`); + searcher.search(ip).then((region)=>{ + let ipStr = Buffer.isBuffer(ip) ? ipToString(ip) : ip; + console.log(`search(${ipStr}): {region: ${region}, ioCount: ${searcher.getIOCount()}}`); + }).catch((err) => { + console.log(`${err.message}`); + }); } - } catch (e) { - console.log(`${e.message}`); - } }); \ No newline at end of file diff --git a/binding/javascript/tests/searcher.test.js b/binding/javascript/tests/searcher.test.js index 14d880e..ac17a0c 100644 --- a/binding/javascript/tests/searcher.test.js +++ b/binding/javascript/tests/searcher.test.js @@ -5,10 +5,13 @@ // searcher new tester // @Author Lion -import {IPv4, IPv6, loadVectorIndexFromFile, XdbIPv4Id, loadContentFromFile} from '../util.js'; -import {newWithFileOnly, newWithVectorIndex, newWithBuffer} from '../searcher.js'; import path from 'path'; import { fileURLToPath } from 'url'; +import { + IPv4, IPv6, XdbIPv4Id, + loadVectorIndexFromFile, loadContentFromFile, + newWithFileOnly, newWithVectorIndex, newWithBuffer +} from '../index.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const dbPath = { @@ -29,14 +32,14 @@ function _get_creater_list(version) { }]; } -test('ipv4 searcher test', () => { +test('ipv4 searcher test', async () => { const ip_Str = '120.229.45.92'; const c_list = _get_creater_list(IPv4); try { let bRegion = null; for (var i = 0; i < c_list.length; i++) { const meta = c_list[i](); - const region = meta[1].search(ip_Str); + const region = await meta[1].search(ip_Str); if (bRegion != null) { expect(region).toBe(region); } @@ -55,7 +58,7 @@ test('ipv6 searcher test', async () => { let bRegion = null; for (var i = 0; i < c_list.length; i++) { const meta = c_list[i](); - const region = meta[1].search(ip_Str); + const region = await meta[1].search(ip_Str); if (bRegion != null) { expect(region).toBe(region); } diff --git a/binding/javascript/tsconfig.json b/binding/javascript/tsconfig.json new file mode 100644 index 0000000..e3bff5e --- /dev/null +++ b/binding/javascript/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "allowJs": true, + "checkJs": false, + "declaration": true, + "outDir": "./dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true + }, + "include": [ + "*.js", + "*.d.ts", + "tests/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file