efficiencize redis and parsing cidr

This commit is contained in:
localhost 2026-06-29 08:49:49 +02:00
parent 23d3cb7036
commit 3b54b2e13c
2 changed files with 56 additions and 18 deletions

View File

@ -1,4 +1,4 @@
import { readdir } from 'node:fs/promises' import { readdir, stat } from 'node:fs/promises'
import * as path from 'node:path' import * as path from 'node:path'
export interface BlockedIpResult { export interface BlockedIpResult {
@ -62,6 +62,35 @@ let networkRefreshPromise: Promise<void> | null = null
let networksCheckedAt = 0 let networksCheckedAt = 0
let networksEtag: string | null = null let networksEtag: string | null = null
interface BlockedListCache {
mtimeMs: number;
parsedCidrs: { cidr: string, parsed: ParsedCidr }[];
}
const blockedCache = new Map<string, BlockedListCache>();
async function getBlockedCidrs(fileName: string, filePath: string) {
const fileStat = await stat(filePath).catch(() => null);
if (!fileStat) return [];
const cached = blockedCache.get(fileName);
if (cached && cached.mtimeMs === fileStat.mtimeMs) {
return cached.parsedCidrs;
}
const content = await Bun.file(filePath).text();
const cidrs = extractCidrs(content);
const parsedCidrs = [];
for (const cidr of cidrs) {
const parsed = parseCidr(cidr);
if (parsed) {
parsedCidrs.push({ cidr, parsed });
}
}
blockedCache.set(fileName, { mtimeMs: fileStat.mtimeMs, parsedCidrs });
return parsedCidrs;
}
function ipv4ToInt(ip: string): number | null { function ipv4ToInt(ip: string): number | null {
const parts = ip.trim().split('.') const parts = ip.trim().split('.')
if (parts.length !== 4) return null if (parts.length !== 4) return null
@ -326,11 +355,19 @@ export async function checkIpRanges(ip: string): Promise<BlockedIpResult> {
for (const fileName of files) { for (const fileName of files) {
const filePath = path.join(BLOCKED_DIR, fileName) const filePath = path.join(BLOCKED_DIR, fileName)
const content = await Bun.file(filePath).text() const cachedCidrs = await getBlockedCidrs(fileName, filePath)
const cidrs = extractCidrs(content)
for (const cidr of cidrs) { for (const item of cachedCidrs) {
if (isIpInCidr(parsedIp, cidr)) { const { cidr, parsed } = item;
let matched = false;
if (parsedIp.version === 4 && parsed.version === 4) {
matched = (parsedIp.value & parsed.mask) === parsed.network
} else if (parsedIp.version === 6 && parsed.version === 6) {
matched = (parsedIp.value & parsed.mask) === parsed.network
}
if (matched) {
return { return {
blocked: path.basename(fileName, '.txt') != 'cloudflare', blocked: path.basename(fileName, '.txt') != 'cloudflare',
list: path.basename(fileName, '.txt'), list: path.basename(fileName, '.txt'),

View File

@ -8,8 +8,10 @@ const redis = new Redis({
redis.on('ready', async function () { redis.on('ready', async function () {
console.log('connected to redis') console.log('connected to redis')
})
setInterval(async () => { setInterval(async () => {
if (redis.status !== 'ready') return;
const files = fs.readdirSync('videos') const files = fs.readdirSync('videos')
const targetFiles = files.filter((file) => file.endsWith('.webm') || file.endsWith('.mp4') || file.endsWith('.m4a')) const targetFiles = files.filter((file) => file.endsWith('.webm') || file.endsWith('.mp4') || file.endsWith('.m4a'))
targetFiles.forEach(async (f) => { targetFiles.forEach(async (f) => {
@ -20,7 +22,6 @@ redis.on('ready', async function () {
console.log(`deleted file ${f} because there is no active download of it`) console.log(`deleted file ${f} because there is no active download of it`)
} }
}) })
}, 5 * 60000) }, 5 * 60000)
})
export default redis export default redis