import { loadEncryptedJson, saveEncryptedJson } from './cryptoUtils.js'; const REQUESTS_FILE = '/data/guest_request_counts.json'; const WINDOW_MS = 24 * 60 * 60 * 1000; const MAX_LOGGED_OUT_REQUESTS = 50; const ipCounters = new Map(); let loaded = false; async function loadGuestCounters() { if (loaded) return; loaded = true; const data = await loadEncryptedJson(REQUESTS_FILE); if (!data) return; for (const [ip, entry] of Object.entries(data)) { ipCounters.set(ip, { count: typeof entry.count === 'number' ? entry.count : 0, resetAt: typeof entry.resetAt === 'number' ? entry.resetAt : Date.now() + WINDOW_MS, }); } } async function saveGuestCounters() { const data = {}; for (const [ip, entry] of ipCounters) { data[ip] = { count: entry.count, resetAt: entry.resetAt }; } await saveEncryptedJson(REQUESTS_FILE, data); } function cleanupExpired() { const now = Date.now(); for (const [ip, entry] of ipCounters) { if (entry.resetAt <= now) { ipCounters.delete(ip); } } } export async function initGuestRequestLimiter() { await loadGuestCounters().catch(err => console.error('Failed to load guest request counters:', err)); cleanupExpired(); setInterval(() => { cleanupExpired(); }, 60 * 60 * 1000); } export async function consumeGuestRequest(ip) { await loadGuestCounters(); const now = Date.now(); let entry = ipCounters.get(ip); if (!entry || entry.resetAt <= now) { entry = { count: 0, resetAt: now + WINDOW_MS }; ipCounters.set(ip, entry); } if (entry.count >= MAX_LOGGED_OUT_REQUESTS) { return false; } entry.count += 1; await saveGuestCounters().catch(err => console.error('Failed to save guest request counters:', err)); return true; } export function getGuestRequestsRemaining(ip) { const now = Date.now(); const entry = ipCounters.get(ip); if (!entry || entry.resetAt <= now) return MAX_LOGGED_OUT_REQUESTS; return Math.max(0, MAX_LOGGED_OUT_REQUESTS - entry.count); }