Skip to content

Commit e1d20b0

Browse files
committed
✨ geoip to redis (NGC-1726)
1 parent c687180 commit e1d20b0

File tree

6 files changed

+84
-0
lines changed

6 files changed

+84
-0
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"multer": "^1.4.5-lts.1",
5555
"nanoid": "3.3.4",
5656
"nodemon": "^3.0.3",
57+
"papaparse": "^5.5.2",
5758
"publicodes": "1.1.1",
5859
"redis-mock": "^0.56.3",
5960
"request-ip": "^3.3.0",
@@ -83,6 +84,7 @@
8384
"@types/morgan": "^1.9.9",
8485
"@types/multer": "^1.4.12",
8586
"@types/node": "^20.11.7",
87+
"@types/papaparse": "^5.3.15",
8688
"@types/redis-mock": "^0.17.3",
8789
"@types/request-ip": "^0.0.41",
8890
"@types/supertest": "^6.0.2",

prisma/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const main = async () => {
88
await import('./scripts/grant-roles'),
99
await import('./scripts/add-integrations-api-scopes'),
1010
await import('./scripts/add-integrations-email-whitelist'),
11+
await import('./scripts/geolocation'),
1112
]
1213

1314
try {

prisma/scripts/geolocation.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import axios from 'axios'
2+
import { createGunzip } from 'node:zlib'
3+
import Papa from 'papaparse'
4+
import { redis } from '../../src/adapters/redis/client'
5+
import { KEYS } from '../../src/adapters/redis/constant'
6+
import { converIpToNumber } from '../../src/features/geolocation/geolocation.service'
7+
8+
export const exec = async () => {
9+
try {
10+
const geoipUrl = process.env.GEOIP_URL
11+
12+
if (!geoipUrl) {
13+
throw new Error('GEOIP_URL is required')
14+
}
15+
16+
const today = new Date()
17+
18+
const datasourceStream = (
19+
await axios.get(
20+
geoipUrl.replace(
21+
'{{YYYY-MM}}',
22+
`${today.getFullYear()}-${(today.getMonth() + 1).toString().padStart(2, '0')}`
23+
),
24+
{
25+
responseType: 'stream',
26+
}
27+
)
28+
).data.pipe(createGunzip())
29+
30+
const parseStream = Papa.parse(Papa.NODE_STREAM_INPUT, {
31+
header: false,
32+
})
33+
34+
datasourceStream.pipe(parseStream)
35+
36+
const sortedArray = []
37+
38+
for await (const chunk of parseStream) {
39+
const [ipStart, _, countryCode] = chunk
40+
41+
// Ignore IPv6 addresses
42+
if (!ipStart.includes('.')) {
43+
continue
44+
}
45+
46+
const ipStartNumber = converIpToNumber(ipStart)
47+
sortedArray.push({ ipStartNum: ipStartNumber, countryCode })
48+
}
49+
50+
await redis.set(KEYS.geolocation, JSON.stringify(sortedArray))
51+
await redis.persist(KEYS.geolocation)
52+
console.log(`Stored ${sortedArray.length} IP to redis`)
53+
} catch (err) {
54+
console.error('Geolocation error', err)
55+
throw err
56+
}
57+
}

src/adapters/redis/constant.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
export const CHANNELS = {
22
apiEvents: 'api-events',
33
}
4+
5+
export const KEYS = {
6+
geolocation: 'geolocation',
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const converIpToNumber = (ip: string) => {
2+
return ip
3+
.split('.')
4+
.reduce(
5+
(accumulator, octet) => (accumulator << 8) + Number.parseInt(octet, 10),
6+
0
7+
)
8+
}

yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4008,6 +4008,13 @@
40084008
dependencies:
40094009
undici-types "~5.26.4"
40104010

4011+
"@types/papaparse@^5.3.15":
4012+
version "5.3.15"
4013+
resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-5.3.15.tgz#7cafa16757a1d121422deefbb10b6310b224ecc4"
4014+
integrity sha512-JHe6vF6x/8Z85nCX4yFdDslN11d+1pr12E526X8WAfhadOeaOTx5AuIkvDKIBopfvlzpzkdMx4YyvSKCM9oqtw==
4015+
dependencies:
4016+
"@types/node" "*"
4017+
40114018
"@types/pg-pool@2.0.4":
40124019
version "2.0.4"
40134020
resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.4.tgz#b5c60f678094ff3acf3442628a7f708928fcf263"
@@ -8888,6 +8895,11 @@ package-json-from-dist@^1.0.0:
88888895
resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00"
88898896
integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==
88908897

8898+
papaparse@^5.5.2:
8899+
version "5.5.2"
8900+
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.5.2.tgz#fb67cc5a03ba8930cb435dc4641a25d6804bd4d7"
8901+
integrity sha512-PZXg8UuAc4PcVwLosEEDYjPyfWnTEhOrUfdv+3Bx+NuAb+5NhDmXzg5fHWmdCh1mP5p7JAZfFr3IMQfcntNAdA==
8902+
88918903
param-case@^3.0.4:
88928904
version "3.0.4"
88938905
resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"

0 commit comments

Comments
 (0)