improve(api): cache geo
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { getClientIp, parseIp } from '@/utils/parseIp';
|
import { getClientIp, parseIp } from '@/utils/parse-ip';
|
||||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
|
|
||||||
import { generateDeviceId } from '@openpanel/common/server';
|
import { generateDeviceId } from '@openpanel/common/server';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getClientIp, parseIp } from '@/utils/parseIp';
|
import { getClientIp, parseIp } from '@/utils/parse-ip';
|
||||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
import { assocPath, pathOr } from 'ramda';
|
import { assocPath, pathOr } from 'ramda';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { GeoLocation } from '@/utils/parseIp';
|
import type { GeoLocation } from '@/utils/parse-ip';
|
||||||
import { getClientIp, parseIp } from '@/utils/parseIp';
|
import { getClientIp, parseIp } from '@/utils/parse-ip';
|
||||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
import { path, assocPath, pathOr, pick } from 'ramda';
|
import { path, assocPath, pathOr, pick } from 'ramda';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getClientIp } from '@/utils/parseIp';
|
import { getClientIp } from '@/utils/parse-ip';
|
||||||
import type {
|
import type {
|
||||||
FastifyReply,
|
FastifyReply,
|
||||||
FastifyRequest,
|
FastifyRequest,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import crypto from 'node:crypto';
|
||||||
|
import { getRedisCache } from '@openpanel/redis';
|
||||||
import type { FastifyRequest } from 'fastify';
|
import type { FastifyRequest } from 'fastify';
|
||||||
import requestIp from 'request-ip';
|
import requestIp from 'request-ip';
|
||||||
|
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
|
|
||||||
interface RemoteIpLookupResponse {
|
interface RemoteIpLookupResponse {
|
||||||
@@ -19,7 +20,7 @@ export interface GeoLocation {
|
|||||||
latitude: number | undefined;
|
latitude: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const geo: GeoLocation = {
|
const DEFAULT_GEO: GeoLocation = {
|
||||||
country: undefined,
|
country: undefined,
|
||||||
city: undefined,
|
city: undefined,
|
||||||
region: undefined,
|
region: undefined,
|
||||||
@@ -35,29 +36,45 @@ export function getClientIp(req: FastifyRequest) {
|
|||||||
|
|
||||||
export async function parseIp(ip?: string): Promise<GeoLocation> {
|
export async function parseIp(ip?: string): Promise<GeoLocation> {
|
||||||
if (!ip || ignore.includes(ip)) {
|
if (!ip || ignore.includes(ip)) {
|
||||||
return geo;
|
return DEFAULT_GEO;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash = crypto.createHash('sha256').update(ip).digest('hex');
|
||||||
|
const cached = await getRedisCache().get(`geo:${hash}`);
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
return JSON.parse(cached);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${process.env.GEO_IP_HOST}/${ip}`, {
|
const res = await fetch(`${process.env.GEO_IP_HOST}/${ip}`, {
|
||||||
signal: AbortSignal.timeout(2000),
|
signal: AbortSignal.timeout(4000),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
return geo;
|
return DEFAULT_GEO;
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = (await res.json()) as RemoteIpLookupResponse;
|
const json = (await res.json()) as RemoteIpLookupResponse;
|
||||||
|
|
||||||
return {
|
const geo = {
|
||||||
country: json.country,
|
country: json.country,
|
||||||
city: json.city,
|
city: json.city,
|
||||||
region: json.stateprov,
|
region: json.stateprov,
|
||||||
longitude: json.longitude,
|
longitude: json.longitude,
|
||||||
latitude: json.latitude,
|
latitude: json.latitude,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await getRedisCache().set(
|
||||||
|
`geo:${hash}`,
|
||||||
|
JSON.stringify(geo),
|
||||||
|
'EX',
|
||||||
|
60 * 30,
|
||||||
|
);
|
||||||
|
|
||||||
|
return geo;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to fetch geo location for ip', { error });
|
logger.error('Failed to fetch geo location for ip', { error });
|
||||||
return geo;
|
return DEFAULT_GEO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user