import { Router } from 'express'; import { authMiddleware, requireRole } from '../auth/middleware'; import { pool } from '../db/pool'; import { testProxy, addProxy, addProxiesFromList } from '../services/proxy'; import { createProxyTestJob, getProxyTestJob, getActiveProxyTestJob, cancelProxyTestJob, ProxyTestMode } from '../services/proxyTestQueue'; const router = Router(); router.use(authMiddleware); // Get all proxies router.get('/', async (req, res) => { try { const result = await pool.query(` SELECT id, host, port, protocol, username, password, active, is_anonymous, last_tested_at, test_result, response_time_ms, created_at, city, state, country, country_code, location_updated_at, COALESCE(max_connections, 1) as max_connections FROM proxies ORDER BY created_at DESC `); res.json({ proxies: result.rows }); } catch (error) { console.error('Error fetching proxies:', error); res.status(500).json({ error: 'Failed to fetch proxies' }); } }); // Get active proxy test job (must be before /:id route) router.get('/test-job', async (req, res) => { try { const job = await getActiveProxyTestJob(); res.json({ job }); } catch (error) { console.error('Error fetching active job:', error); res.status(500).json({ error: 'Failed to fetch active job' }); } }); // Get proxy test job status (must be before /:id route) router.get('/test-job/:jobId', async (req, res) => { try { const { jobId } = req.params; const job = await getProxyTestJob(parseInt(jobId)); if (!job) { return res.status(404).json({ error: 'Job not found' }); } res.json({ job }); } catch (error) { console.error('Error fetching job status:', error); res.status(500).json({ error: 'Failed to fetch job status' }); } }); // Get single proxy router.get('/:id', async (req, res) => { try { const { id } = req.params; const result = await pool.query(` SELECT id, host, port, protocol, username, active, is_anonymous, last_tested_at, test_result, response_time_ms, created_at FROM proxies WHERE id = $1 `, [id]); if (result.rows.length === 0) { return res.status(404).json({ error: 'Proxy not found' }); } res.json({ proxy: result.rows[0] }); } catch (error) { console.error('Error fetching proxy:', error); res.status(500).json({ error: 'Failed to fetch proxy' }); } }); // Add single proxy router.post('/', requireRole('superadmin', 'admin'), async (req, res) => { try { const { host, port, protocol, username, password } = req.body; if (!host || !port || !protocol) { return res.status(400).json({ error: 'Host, port, and protocol required' }); } // Test and add proxy const proxyId = await addProxy(host, port, protocol, username, password); const result = await pool.query(` SELECT * FROM proxies WHERE id = $1 `, [proxyId]); res.status(201).json({ proxy: result.rows[0] }); } catch (error: any) { console.error('Error adding proxy:', error); res.status(400).json({ error: error.message || 'Failed to add proxy' }); } }); // Add multiple proxies router.post('/bulk', requireRole('superadmin', 'admin'), async (req, res) => { try { const { proxies } = req.body; if (!proxies || !Array.isArray(proxies)) { return res.status(400).json({ error: 'Proxies array required' }); } const result = await addProxiesFromList(proxies); res.status(201).json(result); } catch (error) { console.error('Error adding proxies:', error); res.status(500).json({ error: 'Failed to add proxies' }); } }); // Test single proxy router.post('/:id/test', requireRole('superadmin', 'admin'), async (req, res) => { try { const { id } = req.params; const proxyResult = await pool.query(` SELECT host, port, protocol, username, password FROM proxies WHERE id = $1 `, [id]); if (proxyResult.rows.length === 0) { return res.status(404).json({ error: 'Proxy not found' }); } const proxy = proxyResult.rows[0]; const testResult = await testProxy( proxy.host, proxy.port, proxy.protocol, proxy.username, proxy.password ); // Update proxy with test results await pool.query(` UPDATE proxies SET last_tested_at = CURRENT_TIMESTAMP, test_result = $1, response_time_ms = $2, is_anonymous = $3, active = $4 WHERE id = $5 `, [ testResult.success ? 'success' : 'failed', testResult.responseTimeMs, testResult.isAnonymous, testResult.success, id ]); res.json({ test_result: testResult }); } catch (error) { console.error('Error testing proxy:', error); res.status(500).json({ error: 'Failed to test proxy' }); } }); // Start proxy test job // Query params: mode=all|failed|inactive, concurrency=10 router.post('/test-all', requireRole('superadmin', 'admin'), async (req, res) => { try { const mode = (req.query.mode as ProxyTestMode) || 'all'; const concurrency = parseInt(req.query.concurrency as string) || 10; // Validate mode if (!['all', 'failed', 'inactive'].includes(mode)) { return res.status(400).json({ error: 'Invalid mode. Use: all, failed, or inactive' }); } // Validate concurrency (1-50) if (concurrency < 1 || concurrency > 50) { return res.status(400).json({ error: 'Concurrency must be between 1 and 50' }); } const jobId = await createProxyTestJob(mode, concurrency); res.json({ jobId, mode, concurrency, message: `Proxy test job started (mode: ${mode}, concurrency: ${concurrency})` }); } catch (error: any) { console.error('Error starting proxy test job:', error); res.status(500).json({ error: error.message || 'Failed to start proxy test job' }); } }); // Convenience endpoint: Test only failed proxies router.post('/test-failed', requireRole('superadmin', 'admin'), async (req, res) => { try { const concurrency = parseInt(req.query.concurrency as string) || 10; const jobId = await createProxyTestJob('failed', concurrency); res.json({ jobId, mode: 'failed', concurrency, message: 'Retesting failed proxies...' }); } catch (error: any) { console.error('Error starting failed proxy test:', error); res.status(500).json({ error: error.message || 'Failed to start proxy test job' }); } }); // Cancel proxy test job router.post('/test-job/:jobId/cancel', requireRole('superadmin', 'admin'), async (req, res) => { try { const { jobId } = req.params; const cancelled = await cancelProxyTestJob(parseInt(jobId)); if (!cancelled) { return res.status(404).json({ error: 'Job not found or already completed' }); } res.json({ message: 'Job cancelled successfully' }); } catch (error) { console.error('Error cancelling job:', error); res.status(500).json({ error: 'Failed to cancel job' }); } }); // Update proxy router.put('/:id', requireRole('superadmin', 'admin'), async (req, res) => { try { const { id } = req.params; const { host, port, protocol, username, password, active, max_connections } = req.body; const result = await pool.query(` UPDATE proxies SET host = COALESCE($1, host), port = COALESCE($2, port), protocol = COALESCE($3, protocol), username = COALESCE($4, username), password = COALESCE($5, password), active = COALESCE($6, active), max_connections = COALESCE($7, max_connections), updated_at = CURRENT_TIMESTAMP WHERE id = $8 RETURNING * `, [host, port, protocol, username, password, active, max_connections, id]); if (result.rows.length === 0) { return res.status(404).json({ error: 'Proxy not found' }); } res.json({ proxy: result.rows[0] }); } catch (error) { console.error('Error updating proxy:', error); res.status(500).json({ error: 'Failed to update proxy' }); } }); // Delete proxy router.delete('/:id', requireRole('superadmin'), async (req, res) => { try { const { id } = req.params; const result = await pool.query(` DELETE FROM proxies WHERE id = $1 RETURNING id `, [id]); if (result.rows.length === 0) { return res.status(404).json({ error: 'Proxy not found' }); } res.json({ message: 'Proxy deleted successfully' }); } catch (error) { console.error('Error deleting proxy:', error); res.status(500).json({ error: 'Failed to delete proxy' }); } }); // Update all proxy locations router.post('/update-locations', requireRole('superadmin', 'admin'), async (req, res) => { try { const { updateAllProxyLocations } = await import('../services/geolocation'); // Run in background updateAllProxyLocations().catch(err => { console.error('❌ Location update failed:', err); }); res.json({ message: 'Location update job started' }); } catch (error) { console.error('Error starting location update:', error); res.status(500).json({ error: 'Failed to start location update' }); } }); export default router;