UNPKG

ip2region-ts

Version:

node-ip2region written in typescript with esm support, latest xdb

184 lines (182 loc) 5.51 kB
// node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.3_typescript@5.9.2_yaml@2.8.1/node_modules/tsup/assets/esm_shims.js import path from "path"; import { fileURLToPath } from "url"; var getFilename = () => fileURLToPath(import.meta.url); var getDirname = () => path.dirname(getFilename()); var __dirname = /* @__PURE__ */ getDirname(); // src/index.ts import { Buffer } from "buffer"; import fs from "fs"; import path2 from "path"; import process from "process"; var VectorIndexSize = 8; var VectorIndexCols = 256; var VectorIndexLength = 256 * 256 * (4 + 4); var SegmentIndexSize = 14; var IP_REGEX = /^(?:(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/; var getStartEndPtr = Symbol("#getStartEndPtr"); var getBuffer = Symbol("#getBuffer"); var openFilePromise = Symbol("#openFilePromise"); var defaultDbFile = path2.resolve(__dirname, "../data/ip2region.xdb"); var Searcher = class { _dbFile; _vectorIndex; _buffer; constructor(dbFile, vectorIndex, buffer) { this._dbFile = dbFile; this._vectorIndex = vectorIndex; this._buffer = buffer; if (this._buffer) { this._vectorIndex = this._buffer.subarray(256, 256 + VectorIndexLength); } } async [getStartEndPtr](idx, fd, ioStatus) { if (this._vectorIndex) { const sPtr = this._vectorIndex.readUInt32LE(idx); const ePtr = this._vectorIndex.readUInt32LE(idx + 4); return { sPtr, ePtr }; } else { const buf = await this[getBuffer](256 + idx, 8, fd, ioStatus); const sPtr = buf.readUInt32LE(); const ePtr = buf.readUInt32LE(4); return { sPtr, ePtr }; } } async [getBuffer](offset, length, fd, ioStatus) { if (this._buffer) { return this._buffer.subarray(offset, offset + length); } else { const buf = Buffer.alloc(length); return await new Promise((resolve, reject) => { ioStatus.ioCount += 1; fs.read(fd, buf, 0, length, offset, (err) => { if (err) { reject(err); } else { resolve(buf); } }); }); } } [openFilePromise](fileName) { return new Promise((resolve, reject) => { fs.open(fileName, "r", (err, fd) => { if (err) { reject(err); } else { resolve(fd); } }); }); } async search(ip) { const startTime = process.hrtime(); const ioStatus = { ioCount: 0 }; if (!isValidIp(ip)) { throw new Error(`IP: ${ip} is invalid`); } let fd = 0; if (!this._buffer && this._dbFile) { fd = await this[openFilePromise](this._dbFile); } const ps = ip.split("."); const i0 = Number.parseInt(ps[0]); const i1 = Number.parseInt(ps[1]); const i2 = Number.parseInt(ps[2]); const i3 = Number.parseInt(ps[3]); const ipInt = i0 * 256 * 256 * 256 + i1 * 256 * 256 + i2 * 256 + i3; const idx = i0 * VectorIndexCols * VectorIndexSize + i1 * VectorIndexSize; const { sPtr, ePtr } = await this[getStartEndPtr](idx, fd, ioStatus); let l = 0; let h = (ePtr - sPtr) / SegmentIndexSize; let result = null; while (l <= h) { const m = l + h >> 1; const p = sPtr + m * SegmentIndexSize; const buff = await this[getBuffer](p, SegmentIndexSize, fd, ioStatus); const sip = buff.readUInt32LE(0); if (ipInt < sip) { h = m - 1; } else { const eip = buff.readUInt32LE(4); if (ipInt > eip) { l = m + 1; } else { const dataLen = buff.readUInt16LE(8); const dataPtr = buff.readUInt32LE(10); const data = await this[getBuffer](dataPtr, dataLen, fd, ioStatus); result = data.toString("utf8"); break; } } } if (fd) { fs.close(fd, () => { }); } const diff = process.hrtime(startTime); const took = (diff[0] * 1e9 + diff[1]) / 1e3; return { region: result, ioCount: ioStatus.ioCount, took }; } }; function _checkFile(dbPath) { try { fs.accessSync(dbPath, fs.constants.F_OK); } catch (error) { throw new Error(`${dbPath} ${error ? "does not exist" : "exists"}`); } try { fs.accessSync(dbPath, fs.constants.R_OK); } catch (error) { throw new Error(`${dbPath} ${error ? "is not readable" : "is readable"}`); } } function isValidIp(ip) { return IP_REGEX.test(ip); } function newWithFileOnly(dbPath) { _checkFile(dbPath); return new Searcher(dbPath, null, null); } function newWithVectorIndex(dbPath, vectorIndex) { _checkFile(dbPath); if (!Buffer.isBuffer(vectorIndex)) { throw new TypeError("vectorIndex is invalid"); } return new Searcher(dbPath, vectorIndex, null); } function newWithBuffer(buffer) { if (!Buffer.isBuffer(buffer)) { throw new TypeError("buffer is invalid"); } return new Searcher(null, null, buffer); } function loadVectorIndexFromFile(dbPath) { const fd = fs.openSync(dbPath, "r"); const buffer = Buffer.alloc(VectorIndexLength); fs.readSync(fd, buffer, 0, VectorIndexLength, 256); fs.close(fd, () => { }); return buffer; } function loadContentFromFile(dbPath) { const stats = fs.statSync(dbPath); const buffer = Buffer.alloc(stats.size); const fd = fs.openSync(dbPath, "r"); fs.readSync(fd, buffer, 0, stats.size, 0); fs.close(fd, () => { }); return buffer; } export { defaultDbFile, isValidIp, loadContentFromFile, loadVectorIndexFromFile, newWithBuffer, newWithFileOnly, newWithVectorIndex };