UNPKG

ip-china-location

Version:

通过 IPv4 地址获取用户的地理位置信息,精确到省。

124 lines (123 loc) 4.85 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadDatabase = exports.ipv4ToLong = exports.findOnVercel = exports.findIPv4 = void 0; const fs_1 = __importDefault(require("fs")); const path = __importStar(require("path")); let database; /** 查询指定 IP 的地址(仅支持国内) */ function findIPv4(ip, databasePath) { if (!database) loadDatabase(databasePath); const dist = ipv4ToLong(ip); let left = 0, right = database.length - 1; do { const mid = (left + right) >>> 1; const item = database[mid]; if (item.end < dist) left = mid + 1; else if (item.start > dist) right = mid - 1; else return item.loc; } while (left <= right); return undefined; } exports.findIPv4 = findIPv4; // noinspection JSUnusedGlobalSymbols /** 在 Vercel 上查找 IP 的地址(仅支持国内,优先使用 Vercel 定位) */ function findOnVercel(request, databasePath, ip) { const headers = request.headers; const country = headers['x-vercel-ip-country']; if (country != 'CN') return vercelMap[country]; const prov = headers['x-vercel-ip-country-region']; if (prov) return iso2strMap[prov]; if (!ip) { const value = request.headers['x-real-ip']; if (!value) return '中国'; ip = typeof value === 'string' ? value : value[0]; } if (ip.includes(':')) return '中国'; return findIPv4(ip, databasePath); } exports.findOnVercel = findOnVercel; /** 将字符串形式的 IPv4 地址转换为整数 */ function ipv4ToLong(ip) { let result = 0; ip.split('.') .map(it => Number.parseInt(it)) .forEach(it => result = (result << 8) | it); return result >>> 0; } exports.ipv4ToLong = ipv4ToLong; /** 加载数据库 */ function loadDatabase(databasePath) { if (database) return; const provList = [ '中国', '江西', '辽宁', '安徽', '北京', '福建', '甘肃', '广东', '广西', '贵州', '海南', '河南', '河北', '黑龙江', '湖北', '湖南', '吉林', '江苏', '内蒙古', '宁夏', '青海', '山东', '山西', '陕西', '上海', '四川', '天津', '西藏', '新疆', '云南', '浙江', '重庆', '澳门', '香港', '台湾' ]; if (!databasePath) { const rootPath = __dirname.substring(0, __dirname.length - 5); databasePath = path.resolve(rootPath, 'resources/region.bin'); } const buffer = fs_1.default.readFileSync(databasePath); const length = buffer.readUInt16LE(); const array = new Array(length); for (let i = 0; i != length; ++i) { const pos = 6 * i + 2; const start = buffer.readUInt32LE(pos); const mask = buffer.readUint8(pos + 4); const loc = buffer.readUint8(pos + 5); const end = start | ((1 << mask) - 1); array[i] = { start, end: end >>> 0, loc: provList[loc] }; } database = array; } exports.loadDatabase = loadDatabase; const iso2strMap = { JX: '江西', LN: '辽宁', AH: '安徽', BJ: '北京', FJ: '福建', GS: '甘肃', GD: '广东', GX: '广西', GZ: '贵州', HI: '海南', HA: '河南', HL: '黑龙江', HB: '湖北', HN: '湖南', JL: '吉林', JS: '江苏', NM: '内蒙古', NX: '宁夏', QH: '青海', SD: '山东', SX: '山西', SN: '陕西', SH: '上海', SC: '四川', TJ: '天津', XZ: '西藏', XJ: '新疆', YN: '云南', ZJ: '浙江', CQ: '重庆', MO: '澳门', HK: '香港', TW: '台湾', HE: '河北' }; const vercelMap = { HK: '香港', TW: '台湾', MO: '澳门' };