| import { HttpsProxyAgent } from 'https-proxy-agent'; | |
| import { PacProxyAgent } from 'pac-proxy-agent'; | |
| import { SocksProxyAgent } from 'socks-proxy-agent'; | |
| import { ProxyAgent } from 'undici'; | |
| import { config } from '@/config'; | |
| import logger from '@/utils/logger'; | |
| import type { MultiProxyResult, ProxyState } from './multi-proxy'; | |
| import createMultiProxy from './multi-proxy'; | |
| import pacProxy from './pac-proxy'; | |
| import unifyProxy from './unify-proxy'; | |
| const proxyIsPAC = config.pacUri || config.pacScript; | |
| interface ProxyExport { | |
| agent: PacProxyAgent<string> | HttpsProxyAgent<string> | SocksProxyAgent | null; | |
| dispatcher: ProxyAgent | null; | |
| proxyUri?: string; | |
| proxyObj: Record<string, any>; | |
| proxyUrlHandler?: URL | null; | |
| multiProxy?: MultiProxyResult; | |
| getCurrentProxy: () => ProxyState | null; | |
| markProxyFailed: (proxyUri: string) => void; | |
| getAgentForProxy: (proxyState: ProxyState) => any; | |
| getDispatcherForProxy: (proxyState: ProxyState) => ProxyAgent | null; | |
| } | |
| let proxyUri: string | undefined; | |
| let proxyObj: Record<string, any> = {}; | |
| let proxyUrlHandler: URL | null = null; | |
| let multiProxy: MultiProxyResult | undefined; | |
| const createAgentForProxy = (uri: string, proxyObj: Record<string, any>): any => { | |
| if (uri.startsWith('http')) { | |
| return new HttpsProxyAgent(uri, { | |
| headers: { | |
| 'proxy-authorization': proxyObj?.auth ? `Basic ${proxyObj.auth}` : undefined, | |
| }, | |
| }); | |
| } else if (uri.startsWith('socks')) { | |
| return new SocksProxyAgent(uri); | |
| } | |
| return null; | |
| }; | |
| const createDispatcherForProxy = (uri: string, proxyObj: Record<string, any>): ProxyAgent | null => { | |
| if (uri.startsWith('http')) { | |
| return new ProxyAgent({ | |
| uri, | |
| token: proxyObj?.auth ? `Basic ${proxyObj.auth}` : undefined, | |
| requestTls: { | |
| rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== '0', | |
| }, | |
| }); | |
| } | |
| return null; | |
| }; | |
| if (proxyIsPAC) { | |
| const proxy = pacProxy(config.pacUri, config.pacScript, config.proxy); | |
| proxyUri = proxy.proxyUri; | |
| proxyObj = proxy.proxyObj; | |
| proxyUrlHandler = proxy.proxyUrlHandler; | |
| } else if (config.proxyUris && config.proxyUris.length > 0) { | |
| multiProxy = createMultiProxy(config.proxyUris, config.proxy); | |
| proxyObj = multiProxy.proxyObj; | |
| const currentProxy = multiProxy.getNextProxy(); | |
| if (currentProxy) { | |
| proxyUri = currentProxy.uri; | |
| proxyUrlHandler = currentProxy.urlHandler; | |
| } | |
| logger.info(`Multi-proxy initialized with ${config.proxyUris.length} proxies`); | |
| } else { | |
| const proxy = unifyProxy(config.proxyUri, config.proxy); | |
| proxyUri = proxy.proxyUri; | |
| proxyObj = proxy.proxyObj; | |
| proxyUrlHandler = proxy.proxyUrlHandler; | |
| } | |
| let agent: PacProxyAgent<string> | HttpsProxyAgent<string> | SocksProxyAgent | null = null; | |
| let dispatcher: ProxyAgent | null = null; | |
| if (proxyIsPAC && proxyUri) { | |
| agent = new PacProxyAgent(`pac+${proxyUri}`); | |
| } else if (proxyUri) { | |
| agent = createAgentForProxy(proxyUri, proxyObj); | |
| dispatcher = createDispatcherForProxy(proxyUri, proxyObj); | |
| } | |
| const getCurrentProxy = (): ProxyState | null => { | |
| if (multiProxy) { | |
| return multiProxy.getNextProxy(); | |
| } | |
| if (proxyUri) { | |
| return { | |
| uri: proxyUri, | |
| isActive: true, | |
| failureCount: 0, | |
| urlHandler: proxyUrlHandler, | |
| }; | |
| } | |
| return null; | |
| }; | |
| const markProxyFailed = (failedProxyUri: string) => { | |
| if (multiProxy) { | |
| multiProxy.markProxyFailed(failedProxyUri); | |
| const nextProxy = multiProxy.getNextProxy(); | |
| if (nextProxy) { | |
| proxyUri = nextProxy.uri; | |
| proxyUrlHandler = nextProxy.urlHandler || null; | |
| agent = createAgentForProxy(nextProxy.uri, proxyObj); | |
| dispatcher = createDispatcherForProxy(nextProxy.uri, proxyObj); | |
| logger.info(`Switched to proxy: ${nextProxy.uri}`); | |
| } else { | |
| logger.warn('No available proxies remaining'); | |
| agent = null; | |
| dispatcher = null; | |
| proxyUri = undefined; | |
| } | |
| } | |
| }; | |
| const getAgentForProxy = (proxyState: ProxyState) => createAgentForProxy(proxyState.uri, proxyObj); | |
| const getDispatcherForProxy = (proxyState: ProxyState) => createDispatcherForProxy(proxyState.uri, proxyObj); | |
| const proxyExport: ProxyExport = { | |
| agent, | |
| dispatcher, | |
| proxyUri, | |
| proxyObj, | |
| proxyUrlHandler, | |
| multiProxy, | |
| getCurrentProxy, | |
| markProxyFailed, | |
| getAgentForProxy, | |
| getDispatcherForProxy, | |
| }; | |
| export default proxyExport; | |