refactoring continuing

This commit is contained in:
Boki 2025-06-22 08:27:54 -04:00
parent 742e590382
commit a0a3b26177
20 changed files with 394 additions and 798 deletions

View file

@ -1,37 +1,21 @@
/**
* Centralized Proxy Manager - Handles proxy storage, retrieval, and caching
*/
import { createCache, type CacheProvider } from '@stock-bot/cache';
import { getDatabaseConfig } from '@stock-bot/config';
import { getLogger } from '@stock-bot/logger';
import type { CacheProvider } from '@stock-bot/cache';
import type { ProxyInfo, ProxyManagerConfig, ProxyStats } from './types';
const logger = getLogger('proxy-manager');
export class ProxyManager {
private static instance: ProxyManager | null = null;
private cache: CacheProvider;
private proxies: ProxyInfo[] = [];
private proxyIndex: number = 0;
private lastUpdate: Date | null = null;
private isInitialized = false;
private config: ProxyManagerConfig;
private logger: any;
private constructor(config: ProxyManagerConfig = {}) {
this.config = {
cachePrefix: 'proxies:',
ttl: 86400, // 24 hours
enableMetrics: true,
...config
};
const databaseConfig = getDatabaseConfig();
this.cache = createCache({
redisConfig: databaseConfig.dragonfly,
keyPrefix: this.config.cachePrefix,
ttl: this.config.ttl,
enableMetrics: this.config.enableMetrics,
});
constructor(cache: CacheProvider, _config: ProxyManagerConfig = {}, logger?: any) {
this.cache = cache;
this.logger = logger || console;
// Config can be used in the future for customization
}
/**
@ -43,27 +27,27 @@ export class ProxyManager {
}
try {
logger.info('Initializing proxy manager...');
this.logger.info('Initializing proxy manager...');
// Wait for cache to be ready
await this.cache.waitForReady(10000); // Wait up to 10 seconds
logger.debug('Cache is ready');
this.logger.debug('Cache is ready');
await this.loadFromCache();
this.isInitialized = true;
logger.info('Proxy manager initialized', {
this.logger.info('Proxy manager initialized', {
proxiesLoaded: this.proxies.length,
lastUpdate: this.lastUpdate,
});
} catch (error) {
logger.error('Failed to initialize proxy manager', { error });
this.logger.error('Failed to initialize proxy manager', { error });
this.isInitialized = true; // Set to true anyway to avoid infinite retries
}
}
getProxy(): string | null {
if (this.proxies.length === 0) {
logger.warn('No proxies available in memory');
this.logger.warn('No proxies available in memory');
return null;
}
@ -97,7 +81,7 @@ export class ProxyManager {
// Return null if no proxies available
if (this.proxies.length === 0) {
logger.warn('No proxies available in memory');
this.logger.warn('No proxies available in memory');
return null;
}
@ -105,7 +89,7 @@ export class ProxyManager {
const workingProxies = this.proxies.filter(proxy => proxy.isWorking !== false);
if (workingProxies.length === 0) {
logger.warn('No working proxies available');
this.logger.warn('No working proxies available');
return null;
}
@ -122,11 +106,11 @@ export class ProxyManager {
const selectedProxy = topProxies[Math.floor(Math.random() * topProxies.length)];
if (!selectedProxy) {
logger.warn('No proxy selected from available pool');
this.logger.warn('No proxy selected from available pool');
return null;
}
logger.debug('Selected proxy', {
this.logger.debug('Selected proxy', {
host: selectedProxy.host,
port: selectedProxy.port,
successRate: selectedProxy.successRate,
@ -178,8 +162,13 @@ export class ProxyManager {
* Update the proxy pool with new proxies
*/
async updateProxies(proxies: ProxyInfo[]): Promise<void> {
// Ensure manager is initialized before updating
if (!this.isInitialized) {
await this.initializeInternal();
}
try {
logger.info('Updating proxy pool', { newCount: proxies.length, existingCount: this.proxies.length });
this.logger.info('Updating proxy pool', { newCount: proxies.length, existingCount: this.proxies.length });
this.proxies = proxies;
this.lastUpdate = new Date();
@ -189,13 +178,13 @@ export class ProxyManager {
await this.cache.set('last-update', this.lastUpdate.toISOString());
const workingCount = proxies.filter(p => p.isWorking !== false).length;
logger.info('Proxy pool updated successfully', {
this.logger.info('Proxy pool updated successfully', {
totalProxies: proxies.length,
workingProxies: workingCount,
lastUpdate: this.lastUpdate,
});
} catch (error) {
logger.error('Failed to update proxy pool', { error });
this.logger.error('Failed to update proxy pool', { error });
throw error;
}
}
@ -210,10 +199,10 @@ export class ProxyManager {
if (existingIndex >= 0) {
this.proxies[existingIndex] = { ...this.proxies[existingIndex], ...proxy };
logger.debug('Updated existing proxy', { host: proxy.host, port: proxy.port });
this.logger.debug('Updated existing proxy', { host: proxy.host, port: proxy.port });
} else {
this.proxies.push(proxy);
logger.debug('Added new proxy', { host: proxy.host, port: proxy.port });
this.logger.debug('Added new proxy', { host: proxy.host, port: proxy.port });
}
// Update cache
@ -231,7 +220,7 @@ export class ProxyManager {
if (this.proxies.length < initialLength) {
await this.updateProxies(this.proxies);
logger.debug('Removed proxy', { host, port, protocol });
this.logger.debug('Removed proxy', { host, port, protocol });
}
}
@ -245,7 +234,7 @@ export class ProxyManager {
await this.cache.del('active-proxies');
await this.cache.del('last-update');
logger.info('Cleared all proxies');
this.logger.info('Cleared all proxies');
}
/**
@ -267,79 +256,29 @@ export class ProxyManager {
this.proxies = cachedProxies;
this.lastUpdate = lastUpdateStr ? new Date(lastUpdateStr) : null;
logger.debug('Loaded proxies from cache', {
this.logger.debug('Loaded proxies from cache', {
count: this.proxies.length,
lastUpdate: this.lastUpdate,
});
} else {
logger.debug('No cached proxies found');
this.logger.debug('No cached proxies found');
}
} catch (error) {
logger.error('Failed to load proxies from cache', { error });
this.logger.error('Failed to load proxies from cache', { error });
}
}
/**
* Initialize the singleton instance
* Initialize the proxy manager
*/
static async initialize(config?: ProxyManagerConfig): Promise<void> {
if (!ProxyManager.instance) {
ProxyManager.instance = new ProxyManager(config);
await ProxyManager.instance.initializeInternal();
// Perform initial sync with proxy:active:* storage
try {
const { syncProxiesOnce } = await import('./proxy-sync');
await syncProxiesOnce();
logger.info('Initial proxy sync completed');
} catch (error) {
logger.error('Failed to perform initial proxy sync', { error });
}
}
}
/**
* Get the singleton instance (must be initialized first)
*/
static getInstance(): ProxyManager {
if (!ProxyManager.instance) {
throw new Error('ProxyManager not initialized. Call ProxyManager.initialize() first.');
}
return ProxyManager.instance;
}
/**
* Reset the singleton instance (for testing)
*/
static reset(): void {
ProxyManager.instance = null;
async initialize(): Promise<void> {
await this.initializeInternal();
// Note: Initial proxy sync should be handled by the container or application
// that creates ProxyManager instance
this.logger.info('ProxyManager initialized - proxy sync should be handled externally');
}
}
// Export the class as default
export default ProxyManager;
// Convenience functions for easier imports
export function getProxy(): string | null {
return ProxyManager.getInstance().getProxy();
}
export function getRandomProxy(): ProxyInfo | null {
return ProxyManager.getInstance().getRandomProxy();
}
export function getAllProxies(): ProxyInfo[] {
return ProxyManager.getInstance().getAllProxies();
}
export function getWorkingProxies(): ProxyInfo[] {
return ProxyManager.getInstance().getWorkingProxies();
}
export async function updateProxies(proxies: ProxyInfo[]): Promise<void> {
return ProxyManager.getInstance().updateProxies(proxies);
}
export function getProxyStats(): ProxyStats {
return ProxyManager.getInstance().getStats();
}
export default ProxyManager;