mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-24 23:12:34 +08:00
* chore(deps-dev): bump eslint-plugin-unicorn from 66.0.0 to 68.0.0 Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 66.0.0 to 68.0.0. - [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases) - [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v66.0.0...v68.0.0) --- updated-dependencies: - dependency-name: eslint-plugin-unicorn dependency-version: 68.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * style: fix no-useless-coercion * style: fix prefer-boolean-return * style: fix no-useless-logical-operand * style: fix prefer-single-replace * style: fix consistent-conditional-object-spread * style: fix no-useless-else * style: fix prefer-unicode-code-point-escapes * style: fix operator-assignment * style: fix prefer-continue * style: fix prefer-math-constants * style: fix prefer-hoisting-branch-code * style: fix prefer-array-slice * style: fix consistent-class-member-order * style: fix no-return-array-push * style: fix prefer-promise-with-resolvers * style: fix no-array-concat-in-loop * style: fix no-loop-iterable-mutation * style: fix no-invalid-argument-count * style: fix no-duplicate-if-branches * style: fix prefer-else-if * style: fix no-unreadable-for-of-expression * style: fix logical-assignment-operators * style: fix default-export-style * style: revert false positve in prefer-type-literal-last in #22274 * style: fix arrow-body-style * style: add v68 recommended preset * style: refactor GraphQL queries to use template literals for better readability --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tony <TonyRL@users.noreply.github.com>
143 lines
4.3 KiB
TypeScript
143 lines
4.3 KiB
TypeScript
import type { Config } from '@/config';
|
|
import logger from '@/utils/logger';
|
|
|
|
import unifyProxy from './unify-proxy';
|
|
|
|
export interface ProxyState {
|
|
uri: string;
|
|
isActive: boolean;
|
|
failureCount: number;
|
|
lastFailureTime?: number;
|
|
agent?: any;
|
|
dispatcher?: any;
|
|
urlHandler?: URL | null;
|
|
}
|
|
|
|
export interface MultiProxyResult {
|
|
currentProxy?: ProxyState | null;
|
|
allProxies: ProxyState[];
|
|
proxyObj: Config['proxy'];
|
|
getNextProxy: () => ProxyState | null;
|
|
markProxyFailed: (proxyUri: string) => void;
|
|
resetProxy: (proxyUri: string) => void;
|
|
}
|
|
|
|
const createMultiProxy = (proxyUris: string[], proxyObj: Config['proxy']): MultiProxyResult => {
|
|
const proxies: ProxyState[] = [];
|
|
let currentProxyIndex = 0;
|
|
|
|
for (const uri of proxyUris) {
|
|
const unifiedProxy = unifyProxy(uri, proxyObj);
|
|
if (unifiedProxy.proxyUri) {
|
|
proxies.push({
|
|
uri: unifiedProxy.proxyUri,
|
|
isActive: true,
|
|
failureCount: 0,
|
|
urlHandler: unifiedProxy.proxyUrlHandler,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (proxies.length === 0) {
|
|
logger.warn('No valid proxies found in the provided list');
|
|
return {
|
|
allProxies: [],
|
|
proxyObj: proxyObj || {},
|
|
getNextProxy: () => null,
|
|
markProxyFailed: () => {},
|
|
resetProxy: () => {},
|
|
};
|
|
}
|
|
|
|
const healthCheckInterval = proxyObj?.healthCheckInterval || 60000;
|
|
const maxFailures = 3;
|
|
|
|
const healthCheck = () => {
|
|
const now = Date.now();
|
|
for (const proxy of proxies) {
|
|
if (!(!proxy.isActive && proxy.lastFailureTime && now - proxy.lastFailureTime > healthCheckInterval)) {
|
|
continue;
|
|
}
|
|
|
|
proxy.isActive = true;
|
|
proxy.failureCount = 0;
|
|
delete proxy.lastFailureTime;
|
|
logger.info(`Proxy ${proxy.uri} marked as active again after health check`);
|
|
}
|
|
};
|
|
|
|
setInterval(healthCheck, healthCheckInterval);
|
|
|
|
const getNextProxy = (): ProxyState | null => {
|
|
const activeProxies = proxies.filter((p) => p.isActive);
|
|
if (activeProxies.length === 0) {
|
|
logger.warn('No active proxies available');
|
|
return null;
|
|
}
|
|
|
|
let nextProxy = activeProxies[currentProxyIndex % activeProxies.length];
|
|
let attempts = 0;
|
|
|
|
while (!nextProxy.isActive && attempts < activeProxies.length) {
|
|
currentProxyIndex = (currentProxyIndex + 1) % activeProxies.length;
|
|
nextProxy = activeProxies[currentProxyIndex];
|
|
attempts++;
|
|
}
|
|
|
|
if (!nextProxy.isActive) {
|
|
return null;
|
|
}
|
|
|
|
return nextProxy;
|
|
};
|
|
|
|
const markProxyFailed = (proxyUri: string) => {
|
|
const proxy = proxies.find((p) => p.uri === proxyUri);
|
|
if (proxy) {
|
|
proxy.failureCount++;
|
|
proxy.lastFailureTime = Date.now();
|
|
if (proxy.failureCount >= maxFailures) {
|
|
proxy.isActive = false;
|
|
logger.warn(`Proxy ${proxyUri} marked as inactive after ${maxFailures} failures`);
|
|
} else {
|
|
logger.warn(`Proxy ${proxyUri} failed (${proxy.failureCount}/${maxFailures})`);
|
|
}
|
|
|
|
const activeProxies = proxies.filter((p) => p.isActive);
|
|
if (activeProxies.length > 0) {
|
|
currentProxyIndex = (currentProxyIndex + 1) % activeProxies.length;
|
|
const nextProxy = getNextProxy();
|
|
if (nextProxy) {
|
|
logger.info(`Switching to proxy: ${nextProxy.uri}`);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const resetProxy = (proxyUri: string) => {
|
|
const proxy = proxies.find((p) => p.uri === proxyUri);
|
|
if (proxy) {
|
|
proxy.isActive = true;
|
|
proxy.failureCount = 0;
|
|
delete proxy.lastFailureTime;
|
|
logger.info(`Proxy ${proxyUri} manually reset`);
|
|
}
|
|
};
|
|
|
|
const currentProxy = getNextProxy();
|
|
if (currentProxy) {
|
|
logger.info(`Initial proxy selected: ${currentProxy.uri}`);
|
|
}
|
|
|
|
return {
|
|
currentProxy,
|
|
allProxies: proxies,
|
|
proxyObj: proxyObj || {},
|
|
getNextProxy,
|
|
markProxyFailed,
|
|
resetProxy,
|
|
};
|
|
};
|
|
|
|
export default createMultiProxy;
|