Files
cannaiq/backend/dist/services/geolocation.js
Kelly 66e07b2009 fix(monitor): remove non-existent worker columns from job_run_logs query
The job_run_logs table tracks scheduled job orchestration, not individual
worker jobs. Worker info (worker_id, worker_hostname) belongs on
dispensary_crawl_jobs, not job_run_logs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 18:45:05 -07:00

126 lines
4.9 KiB
JavaScript

"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();
}
}
}