diff --git a/jest.config.ts b/jest.config.ts index ee77ba4..12dd86c 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -13,6 +13,7 @@ const config: Config = { coverageDirectory: '/coverage', coveragePathIgnorePatterns: [ '/src/controller/', + '/src/utils/dispatcher.ts', ], coverageProvider: 'babel', coverageThreshold: { diff --git a/jest.setup.ts b/jest.setup.ts index 23ec0d0..6fb1507 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -1,6 +1,3 @@ -import { socksDispatcher } from 'fetch-socks'; -import { Agent, Dispatcher, interceptors, ProxyAgent, setGlobalDispatcher } from 'undici'; - process.env['CACHE_DIR'] = '/dev/null'; jest.mock('randomstring', () => ({ @@ -12,20 +9,3 @@ beforeEach(() => { }); console.log = console.warn = console.error = console.info = console.debug = () => { /* disable in favor of logger */ }; - -let dispatcher: Dispatcher; -if (process.env['ALL_PROXY']) { - const proxyUrl = new URL(process.env['ALL_PROXY']); - if (proxyUrl.protocol === 'socks5:') { - dispatcher = socksDispatcher({ type: 5, host: proxyUrl.hostname, port: parseInt(proxyUrl.port) }, { allowH2: true }); - } else { - dispatcher = new ProxyAgent({ uri: proxyUrl.href, allowH2: true }); - } -} else { - dispatcher = new Agent({ allowH2: true }); -} -dispatcher.compose( - interceptors.dns(), - interceptors.retry({ maxRetries: 3 }), -); -setGlobalDispatcher(dispatcher); diff --git a/src/index.ts b/src/index.ts index d18108b..85b85b0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,5 @@ import { randomUUID } from 'node:crypto'; import express, { NextFunction, Request, Response } from 'express'; -import { socksDispatcher } from 'fetch-socks'; -import { Agent, Dispatcher, interceptors, ProxyAgent, setGlobalDispatcher } from 'undici'; import winston from 'winston'; import { ConfigureController, ManifestController, StreamController } from './controller'; import { BlockedError, logErrorAndReturnNiceString } from './error'; @@ -36,23 +34,6 @@ process.on('unhandledRejection', (reason) => { logger.error('Unhandled rejection: ', reason); }); -let dispatcher: Dispatcher; -if (process.env['ALL_PROXY']) { - const proxyUrl = new URL(process.env['ALL_PROXY']); - if (proxyUrl.protocol === 'socks5:') { - dispatcher = socksDispatcher({ type: 5, host: proxyUrl.hostname, port: parseInt(proxyUrl.port) }, { allowH2: true }); - } else { - dispatcher = new ProxyAgent({ uri: proxyUrl.href, allowH2: true }); - } -} else { - dispatcher = new Agent({ allowH2: true }); -} -dispatcher.compose( - interceptors.dns(), - interceptors.retry({ maxRetries: 3 }), -); -setGlobalDispatcher(dispatcher); - const fetcher = new Fetcher(logger); const sources = createSources(fetcher); diff --git a/src/utils/Fetcher.ts b/src/utils/Fetcher.ts index 7be9e93..ec190fe 100644 --- a/src/utils/Fetcher.ts +++ b/src/utils/Fetcher.ts @@ -6,6 +6,7 @@ import { Cookie, CookieJar } from 'tough-cookie'; import winston from 'winston'; import { BlockedError, HttpError, NotFoundError, QueueIsFullError, TimeoutError, TooManyRequestsError, TooManyTimeoutsError } from '../error'; import { BlockedReason, Context } from '../types'; +import { createDispatcher } from './dispatcher'; import { envGet } from './env'; interface HttpCacheItem { @@ -282,7 +283,7 @@ export class Fetcher { finalUrl.username = ''; finalUrl.password = ''; - const finalInit = { ...init, keepalive: true, signal: controller.signal }; + const finalInit = { ...init, keepalive: true, signal: controller.signal, dispatcher: createDispatcher() }; response = await fetch(finalUrl, finalInit); } catch (error) { diff --git a/src/utils/dispatcher.ts b/src/utils/dispatcher.ts new file mode 100644 index 0000000..d5f0497 --- /dev/null +++ b/src/utils/dispatcher.ts @@ -0,0 +1,22 @@ +import { socksDispatcher } from 'fetch-socks'; +import { Agent, Dispatcher, interceptors, ProxyAgent } from 'undici'; + +const createBasicDispatcher = (): Dispatcher => { + if (process.env['ALL_PROXY']) { + const proxyUrl = new URL(process.env['ALL_PROXY']); + if (proxyUrl.protocol === 'socks5:') { + return socksDispatcher({ type: 5, host: proxyUrl.hostname, port: parseInt(proxyUrl.port) }, { allowH2: true }); + } else { + return new ProxyAgent({ uri: proxyUrl.href, allowH2: true }); + } + } else { + return new Agent({ allowH2: true }); + } +}; + +export const createDispatcher = (): Dispatcher => { + return createBasicDispatcher().compose( + interceptors.dns(), + interceptors.retry({ maxRetries: 3 }), + ); +};