"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.lookupProxyLocation = lookupProxyLocation; exports.updateProxyLocation = updateProxyLocation; exports.updateAllProxyLocations = updateAllProxyLocations; exports.queueProxyLocationUpdate = queueProxyLocationUpdate; const axios_1 = __importDefault(require("axios")); const migrate_1 = require("../db/migrate"); // Free API - 45 requests/minute limit const GEOLOCATION_API = 'http://ip-api.com/json/'; async function lookupProxyLocation(host) { try { const response = await axios_1.default.get(`${GEOLOCATION_API}${host}?fields=status,message,country,countryCode,regionName,city,query`); const data = response.data; if (data.status === 'fail') { console.log(`❌ Geolocation lookup failed for ${host}: ${data.message}`); return null; } return data; } catch (error) { console.error(`❌ Error looking up location for ${host}:`, error.message); return null; } } async function updateProxyLocation(proxyId, location) { await migrate_1.pool.query(` UPDATE proxies SET city = $1, state = $2, country = $3, country_code = $4, location_updated_at = CURRENT_TIMESTAMP WHERE id = $5 `, [ location.city, location.regionName, location.country, location.countryCode, proxyId ]); } async function updateAllProxyLocations(batchSize = 45) { console.log('🌍 Starting proxy location update job...'); // Get all proxies without location data const result = await migrate_1.pool.query(` SELECT id, host FROM proxies WHERE location_updated_at IS NULL OR location_updated_at < CURRENT_TIMESTAMP - INTERVAL '30 days' ORDER BY id `); const proxies = result.rows; console.log(`📊 Found ${proxies.length} proxies to update`); let updated = 0; let failed = 0; // Process in batches to respect rate limit (45 req/min) for (let i = 0; i < proxies.length; i += batchSize) { const batch = proxies.slice(i, i + batchSize); console.log(`🔄 Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(proxies.length / batchSize)} (${batch.length} proxies)`); // Process batch for (const proxy of batch) { const location = await lookupProxyLocation(proxy.host); if (location) { await updateProxyLocation(proxy.id, location); console.log(`✅ Updated ${proxy.id}: ${location.city}, ${location.regionName} - ${location.country}`); updated++; } else { console.log(`⚠️ Failed to get location for proxy ${proxy.id} (${proxy.host})`); failed++; } // Small delay between requests await new Promise(resolve => setTimeout(resolve, 100)); } // Wait 60 seconds before next batch to respect rate limit if (i + batchSize < proxies.length) { console.log(`⏳ Waiting 60s before next batch (rate limit: 45 req/min)...`); await new Promise(resolve => setTimeout(resolve, 60000)); } } console.log(`✅ Proxy location update complete!`); console.log(` Updated: ${updated}`); console.log(` Failed: ${failed}`); } // Queue for background processing const locationUpdateQueue = new Set(); let isProcessing = false; function queueProxyLocationUpdate(proxyId) { locationUpdateQueue.add(proxyId); processLocationQueue(); } async function processLocationQueue() { if (isProcessing || locationUpdateQueue.size === 0) return; isProcessing = true; try { const proxyIds = Array.from(locationUpdateQueue); locationUpdateQueue.clear(); console.log(`🌍 Processing ${proxyIds.length} proxy location updates from queue`); for (const proxyId of proxyIds) { const result = await migrate_1.pool.query('SELECT host FROM proxies WHERE id = $1', [proxyId]); if (result.rows.length === 0) continue; const host = result.rows[0].host; const location = await lookupProxyLocation(host); if (location) { await updateProxyLocation(proxyId, location); console.log(`✅ Queue: Updated ${proxyId}: ${location.city}, ${location.regionName} - ${location.country}`); } // Respect rate limit await new Promise(resolve => setTimeout(resolve, 1500)); // ~40 req/min } } finally { isProcessing = false; // Process any new items that were added while we were processing if (locationUpdateQueue.size > 0) { processLocationQueue(); } } }