Team Ai
Apppublic

agenticworkflowsspace/proxyvault

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
api.py189 linesDownload Raw Back to root
1"""2FastAPI backend for ProxyUtility WebApp.3Streams proxy results in real-time via WebSocket.4Filters by country (location substring match) and ip_type.5Sends progress updates after every proxy test.6"""7import os, sys, asyncio, json, time8 9from fastapi import FastAPI, WebSocket, WebSocketDisconnect10from fastapi.middleware.cors import CORSMiddleware11from fastapi.staticfiles import StaticFiles12 13sys.path.insert(0, os.path.dirname(__file__))14 15from proxy_scraper import scrape_proxies16from proxy_tester import get_whoer_info, TEST_URL, TIMEOUT_SECONDS17 18import aiohttp19 20app = FastAPI()21 22app.add_middleware(23    CORSMiddleware,24    allow_origins=["*"],25    allow_credentials=True,26    allow_methods=["*"],27    allow_headers=["*"],28)29 30 31def parse_ip(proxy: str):32    if "@" in proxy:33        return proxy.split("@")[-1].split(":")[0]34    return proxy.split(":")[0]35 36 37def proxy_url_and_auth(proxy: str):38    if "@" in proxy:39        return f"http://{proxy}", None40    elif proxy.count(":") == 3:41        parts = proxy.split(":")42        auth = aiohttp.BasicAuth(parts[2], parts[3])43        return f"http://{parts[0]}:{parts[1]}", auth44    return f"http://{proxy}", None45 46 47async def test_and_enrich(48    session: aiohttp.ClientSession,49    proxy: str,50    semaphore: asyncio.Semaphore,51    country_filter: str,52    type_filter: str,53    counters: dict,54    ws: WebSocket,55):56    """Test one proxy, enrich with Whoer, stream progress + result."""57    async with semaphore:58        ip = parse_ip(proxy)59        purl, auth = proxy_url_and_auth(proxy)60        start = time.time()61        try:62            timeout = aiohttp.ClientTimeout(total=TIMEOUT_SECONDS)63            async with session.get(TEST_URL, proxy=purl, proxy_auth=auth, timeout=timeout) as resp:64                if resp.status != 200:65                    async with counters["lock"]:66                        counters["tested"] += 167                        counters["unmatched"] += 168                    await _send_progress(ws, counters)69                    return70                speed_ms = round((time.time() - start) * 1000, 1)71        except Exception:72            async with counters["lock"]:73                counters["tested"] += 174                counters["unmatched"] += 175            await _send_progress(ws, counters)76            return77 78        # Enrich with Whoer79        whoer = await get_whoer_info(session, ip)80 81        result = {82            "proxy": proxy,83            "speed_ms": speed_ms,84            "location": whoer.get("location", "N/A"),85            "ip_type": whoer.get("ip_type", "N/A"),86            "fraud_score": whoer.get("fraud_score", "N/A"),87        }88 89        # Apply filters90        loc_lower = result["location"].lower()91        type_lower = result["ip_type"].lower()92        country_ok = (not country_filter) or (country_filter.lower() in loc_lower)93        type_ok = (not type_filter) or (type_filter.lower() in type_lower)94 95        async with counters["lock"]:96            counters["tested"] += 197            if country_ok and type_ok:98                counters["matched"] += 199            else:100                counters["unmatched"] += 1101 102        await _send_progress(ws, counters)103 104        if country_ok and type_ok:105            try:106                await ws.send_text(json.dumps({"type": "proxy", "data": result}))107            except Exception:108                pass109 110 111async def _send_progress(ws: WebSocket, counters: dict):112    try:113        await ws.send_text(json.dumps({114            "type": "progress",115            "tested": counters["tested"],116            "total": counters["total"],117            "matched": counters["matched"],118            "unmatched": counters["unmatched"],119        }))120    except Exception:121        pass122 123 124@app.websocket("/ws/scan")125async def scan_proxies(ws: WebSocket):126    await ws.accept()127 128    try:129        data = await ws.receive_text()130        params = json.loads(data)131        country_filter = params.get("country", "").strip()132        type_filter = params.get("ip_type", "").strip()133 134        await ws.send_text(json.dumps({"type": "status", "message": "Scraping proxy sources..."}))135 136        proxies = scrape_proxies()137 138        counters = {139            "tested": 0,140            "total": len(proxies),141            "matched": 0,142            "unmatched": 0,143            "lock": asyncio.Lock(),144        }145 146        await ws.send_text(json.dumps({147            "type": "status",148            "message": f"Testing {len(proxies)} proxies...",149        }))150        await ws.send_text(json.dumps({151            "type": "progress",152            "tested": 0,153            "total": len(proxies),154            "matched": 0,155            "unmatched": 0,156        }))157 158        MAX_CONCURRENT = 80159        semaphore = asyncio.Semaphore(MAX_CONCURRENT)160        connector = aiohttp.TCPConnector(ssl=False, limit=MAX_CONCURRENT)161 162        async with aiohttp.ClientSession(connector=connector) as session:163            tasks = [164                asyncio.create_task(165                    test_and_enrich(session, proxy, semaphore, country_filter, type_filter, counters, ws)166                )167                for proxy in proxies168            ]169            await asyncio.gather(*tasks, return_exceptions=True)170 171        await ws.send_text(json.dumps({172            "type": "done",173            "message": f"Done. {counters['matched']} matched out of {counters['total']} proxies tested.",174        }))175 176    except WebSocketDisconnect:177        pass178    except Exception as e:179        try:180            await ws.send_text(json.dumps({"type": "error", "message": str(e)}))181        except Exception:182            pass183 184 185# Serve the Next.js static export — must come LAST (after all API routes)186_static_dir = os.path.join(os.path.dirname(__file__), "webapp", "out")187if os.path.isdir(_static_dir):188    app.mount("/", StaticFiles(directory=_static_dir, html=True), name="frontend")189