This commit is contained in:
Boki 2025-06-25 11:38:23 -04:00
parent 3a7254708e
commit b63e58784c
41 changed files with 5762 additions and 4477 deletions

View file

@ -1,133 +1,135 @@
import type { ProxyInfo } from './types';
export interface ProxyConfig {
protocol: string;
host: string;
port: number;
auth?: {
username: string;
password: string;
};
}
/**
* Simple proxy manager for testing
*/
export class SimpleProxyManager {
private proxies: Array<ProxyInfo & { id: string; active: boolean }> = [];
private currentIndex = 0;
private activeProxyIndex = 0;
addProxy(proxy: ProxyInfo & { id: string; active: boolean }): void {
this.proxies.push(proxy);
}
removeProxy(id: string): void {
this.proxies = this.proxies.filter(p => p.id !== id);
}
updateProxyStatus(id: string, active: boolean): void {
const proxy = this.proxies.find(p => p.id === id);
if (proxy) {
proxy.active = active;
}
}
getProxies(): Array<ProxyInfo & { id: string; active: boolean }> {
return [...this.proxies];
}
getActiveProxies(): Array<ProxyInfo & { id: string; active: boolean }> {
return this.proxies.filter(p => p.active);
}
getNextProxy(): (ProxyInfo & { id: string; active: boolean }) | null {
const activeProxies = this.getActiveProxies();
if (activeProxies.length === 0) {
return null;
}
const proxy = activeProxies[this.activeProxyIndex % activeProxies.length];
this.activeProxyIndex++;
return proxy || null;
}
getProxyConfig(proxy: ProxyInfo & { id: string; active: boolean }): ProxyConfig {
const config: ProxyConfig = {
protocol: proxy.protocol,
host: proxy.host,
port: proxy.port,
};
if (proxy.username && proxy.password) {
config.auth = {
username: proxy.username,
password: proxy.password,
};
}
return config;
}
formatProxyUrl(proxy: ProxyInfo): string {
let url = `${proxy.protocol}://`;
if (proxy.username && proxy.password) {
url += `${proxy.username}:${proxy.password}@`;
}
url += `${proxy.host}:${proxy.port}`;
return url;
}
async validateProxy(id: string): Promise<boolean> {
const proxy = this.proxies.find(p => p.id === id);
if (!proxy) return false;
try {
const proxyUrl = this.formatProxyUrl(proxy);
const response = await fetch('https://httpbin.org/ip', {
// @ts-ignore - proxy option might not be in types
proxy: proxyUrl,
signal: AbortSignal.timeout(5000),
});
return response.ok;
} catch {
return false;
}
}
async validateAllProxies(): Promise<Record<string, boolean>> {
const results: Record<string, boolean> = {};
for (const proxy of this.proxies) {
const isValid = await this.validateProxy(proxy.id);
results[proxy.id] = isValid;
// Disable invalid proxies
if (!isValid) {
this.updateProxyStatus(proxy.id, false);
}
}
return results;
}
getStatistics() {
const stats = {
total: this.proxies.length,
active: this.proxies.filter(p => p.active).length,
inactive: this.proxies.filter(p => !p.active).length,
byProtocol: {} as Record<string, number>,
};
this.proxies.forEach(proxy => {
stats.byProtocol[proxy.protocol] = (stats.byProtocol[proxy.protocol] || 0) + 1;
});
return stats;
}
clear(): void {
this.proxies = [];
this.currentIndex = 0;
}
}
import type { ProxyInfo } from './types';
export interface ProxyConfig {
protocol: string;
host: string;
port: number;
auth?: {
username: string;
password: string;
};
}
/**
* Simple proxy manager for testing
*/
export class SimpleProxyManager {
private proxies: Array<ProxyInfo & { id: string; active: boolean }> = [];
private currentIndex = 0;
private activeProxyIndex = 0;
addProxy(proxy: ProxyInfo & { id: string; active: boolean }): void {
this.proxies.push(proxy);
}
removeProxy(id: string): void {
this.proxies = this.proxies.filter(p => p.id !== id);
}
updateProxyStatus(id: string, active: boolean): void {
const proxy = this.proxies.find(p => p.id === id);
if (proxy) {
proxy.active = active;
}
}
getProxies(): Array<ProxyInfo & { id: string; active: boolean }> {
return [...this.proxies];
}
getActiveProxies(): Array<ProxyInfo & { id: string; active: boolean }> {
return this.proxies.filter(p => p.active);
}
getNextProxy(): (ProxyInfo & { id: string; active: boolean }) | null {
const activeProxies = this.getActiveProxies();
if (activeProxies.length === 0) {
return null;
}
const proxy = activeProxies[this.activeProxyIndex % activeProxies.length];
this.activeProxyIndex++;
return proxy || null;
}
getProxyConfig(proxy: ProxyInfo & { id: string; active: boolean }): ProxyConfig {
const config: ProxyConfig = {
protocol: proxy.protocol,
host: proxy.host,
port: proxy.port,
};
if (proxy.username && proxy.password) {
config.auth = {
username: proxy.username,
password: proxy.password,
};
}
return config;
}
formatProxyUrl(proxy: ProxyInfo): string {
let url = `${proxy.protocol}://`;
if (proxy.username && proxy.password) {
url += `${proxy.username}:${proxy.password}@`;
}
url += `${proxy.host}:${proxy.port}`;
return url;
}
async validateProxy(id: string): Promise<boolean> {
const proxy = this.proxies.find(p => p.id === id);
if (!proxy) {
return false;
}
try {
const proxyUrl = this.formatProxyUrl(proxy);
const response = await fetch('https://httpbin.org/ip', {
// @ts-ignore - proxy option might not be in types
proxy: proxyUrl,
signal: AbortSignal.timeout(5000),
});
return response.ok;
} catch {
return false;
}
}
async validateAllProxies(): Promise<Record<string, boolean>> {
const results: Record<string, boolean> = {};
for (const proxy of this.proxies) {
const isValid = await this.validateProxy(proxy.id);
results[proxy.id] = isValid;
// Disable invalid proxies
if (!isValid) {
this.updateProxyStatus(proxy.id, false);
}
}
return results;
}
getStatistics() {
const stats = {
total: this.proxies.length,
active: this.proxies.filter(p => p.active).length,
inactive: this.proxies.filter(p => !p.active).length,
byProtocol: {} as Record<string, number>,
};
this.proxies.forEach(proxy => {
stats.byProtocol[proxy.protocol] = (stats.byProtocol[proxy.protocol] || 0) + 1;
});
return stats;
}
clear(): void {
this.proxies = [];
this.currentIndex = 0;
}
}