UNPKG

ip2region-ts

Version:

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

218 lines (216 loc) 7.57 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { defaultDbFile: () => defaultDbFile, isValidIp: () => isValidIp, loadContentFromFile: () => loadContentFromFile, loadVectorIndexFromFile: () => loadVectorIndexFromFile, newWithBuffer: () => newWithBuffer, newWithFileOnly: () => newWithFileOnly, newWithVectorIndex: () => newWithVectorIndex }); module.exports = __toCommonJS(index_exports); var import_node_buffer = require("buffer"); var import_node_fs = __toESM(require("fs"), 1); var import_node_path = __toESM(require("path"), 1); var import_node_process = __toESM(require("process"), 1); 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 = import_node_path.default.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 = import_node_buffer.Buffer.alloc(length); return await new Promise((resolve, reject) => { ioStatus.ioCount += 1; import_node_fs.default.read(fd, buf, 0, length, offset, (err) => { if (err) { reject(err); } else { resolve(buf); } }); }); } } [openFilePromise](fileName) { return new Promise((resolve, reject) => { import_node_fs.default.open(fileName, "r", (err, fd) => { if (err) { reject(err); } else { resolve(fd); } }); }); } async search(ip) { const startTime = import_node_process.default.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) { import_node_fs.default.close(fd, () => { }); } const diff = import_node_process.default.hrtime(startTime); const took = (diff[0] * 1e9 + diff[1]) / 1e3; return { region: result, ioCount: ioStatus.ioCount, took }; } }; function _checkFile(dbPath) { try { import_node_fs.default.accessSync(dbPath, import_node_fs.default.constants.F_OK); } catch (error) { throw new Error(`${dbPath} ${error ? "does not exist" : "exists"}`); } try { import_node_fs.default.accessSync(dbPath, import_node_fs.default.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 (!import_node_buffer.Buffer.isBuffer(vectorIndex)) { throw new TypeError("vectorIndex is invalid"); } return new Searcher(dbPath, vectorIndex, null); } function newWithBuffer(buffer) { if (!import_node_buffer.Buffer.isBuffer(buffer)) { throw new TypeError("buffer is invalid"); } return new Searcher(null, null, buffer); } function loadVectorIndexFromFile(dbPath) { const fd = import_node_fs.default.openSync(dbPath, "r"); const buffer = import_node_buffer.Buffer.alloc(VectorIndexLength); import_node_fs.default.readSync(fd, buffer, 0, VectorIndexLength, 256); import_node_fs.default.close(fd, () => { }); return buffer; } function loadContentFromFile(dbPath) { const stats = import_node_fs.default.statSync(dbPath); const buffer = import_node_buffer.Buffer.alloc(stats.size); const fd = import_node_fs.default.openSync(dbPath, "r"); import_node_fs.default.readSync(fd, buffer, 0, stats.size, 0); import_node_fs.default.close(fd, () => { }); return buffer; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { defaultDbFile, isValidIp, loadContentFromFile, loadVectorIndexFromFile, newWithBuffer, newWithFileOnly, newWithVectorIndex });