Rene Fichtmueller edc9311d7b feat: add proxy network, image backfill, and scraper improvements
- Add TIP Proxy Network (packages/proxy-agent): SOCKS5 proxy agent
  for residential IP bypass of CloudFront WAF blocks
- Add /api/proxy/* routes: node registration, heartbeat, load balancing
- Add image extraction to Flexoptix catalog scraper (GraphQL small_image)
- Add image extraction to Optcore scraper (Playwright gallery img)
- Fix Fluxlight price scraping (BigCommerce HTML structure: data-product-price-without-tax)
- Add SmartOptics scraper (8 DWDM/coherent products, og:image extraction)
- Fix findOrCreateScrapedTransceiver to update image_url for existing records
- Add image backfill script (backfill-images.ts): 178 Flexoptix images added
- Fix DB connection pool: max 5, idleTimeoutMillis 10s (was unlimited, caused >100 connections)
- Add proxy.ts utility for scraper proxy rotation
2026-04-03 21:13:03 +02:00

51 lines
1020 B
TypeScript

/**
* Bandwidth tracker — monitors usage and enforces limits
*/
export interface BandwidthStats {
bytesProxied: number;
requestsProxied: number;
bytesLimitHard: number;
limitReached: boolean;
}
export class BandwidthTracker {
private bytesProxied = 0;
private requestsProxied = 0;
private readonly bytesLimit: number;
constructor(maxGb: number) {
this.bytesLimit = maxGb * 1024 * 1024 * 1024;
}
addBytes(n: number): void {
this.bytesProxied += n;
}
incrementRequests(): void {
this.requestsProxied++;
}
isLimitReached(): boolean {
return this.bytesProxied >= this.bytesLimit;
}
getStats(): BandwidthStats {
return {
bytesProxied: this.bytesProxied,
requestsProxied: this.requestsProxied,
bytesLimitHard: this.bytesLimit,
limitReached: this.isLimitReached(),
};
}
getUsedGb(): number {
return this.bytesProxied / (1024 * 1024 * 1024);
}
reset(): void {
this.bytesProxied = 0;
this.requestsProxied = 0;
}
}