@blocklet/ui-react
Version:
Some useful front-end web components that can be used in Blocklets.
83 lines (75 loc) • 2.17 kB
text/typescript
const RESERVED_IP = 'Reserved IP';
const IP_REGION_CACHE = 'ip-region-cache';
async function getIpRegionFromIpApi(ip: string): Promise<string> {
const url = `https://ipapi.co/${ip}/json/`;
const result = await fetch(url);
const data = await result.json();
let region = '';
if (data.error) {
if (data.reserved) {
region = RESERVED_IP;
}
} else {
region = [data.country_name, data.region, data.city].filter(Boolean).join('/');
}
return region;
}
async function getIpRegionFromIpSb(ip: string): Promise<string> {
const url = `https://api.ip.sb/geoip/${ip}`;
const result = await fetch(url);
const data = await result.json();
let region = '';
if (data.error) {
if (data.reserved) {
region = RESERVED_IP;
}
} else {
region = [data.country, data.region, data.city].filter(Boolean).join('/');
}
return region;
}
export async function ip2Region(ip: string): Promise<string> {
let region = '';
let ipRegionCache: Record<string, string> = {};
try {
const tmpCache = localStorage.getItem(IP_REGION_CACHE);
if (tmpCache) {
ipRegionCache = JSON.parse(tmpCache);
}
} catch {
ipRegionCache = {};
}
if (ipRegionCache[ip]) {
region = ipRegionCache[ip];
} else {
try {
region = await getIpRegionFromIpSb(ip);
} catch {
console.warn('Fail to get ip region from ip.sb');
}
if (!region) {
try {
region = await getIpRegionFromIpApi(ip);
} catch {
console.warn('Fail to get ip region from ip-api.co');
}
}
}
if (region) {
// NOTICE: 为了防止 cache 过大,将在 size 超过 100 时,删除最旧的数据
const ipList = Object.keys(ipRegionCache);
if (ipList.length > 100) {
delete ipRegionCache[ipList[0]];
}
if (ipRegionCache[ip]) {
delete ipRegionCache[ip];
}
ipRegionCache[ip] = region;
localStorage.setItem(IP_REGION_CACHE, JSON.stringify(ipRegionCache));
}
return region;
}
// eslint-disable-next-line require-await
export async function batchIp2Region(ips: string[]): Promise<string[]> {
return Promise.all(ips.map((ip) => ip2Region(ip)));
}