/** * 网络代理应用工具(v0.6.4 P4-5) * * 目标:为 Electron 侧的全部网络出口提供统一的代理配置入口: * * 1. Chromium session 栈(session.setProxy): * - defaultSession(渲染页面自身请求) * - persist:metona-agent-browser(web_fetch 浏览器回退 / web_browser 隐藏窗口) * 该分区由 BrowserWindowManager 在首次使用时创建 —— 本工具在启动期与配置 * 变更时直接 fromPartition 预配置,先于任何窗口创建生效。 * * 2. 主进程 Node fetch(LLM adapters / web_fetch HTTP 阶段 / SearXNG 测试 / * 更新检查):Node 的 global fetch 与 undici 通过 globalThis 上的 * Symbol.for('undici.globalDispatcher.1') 共享调度器 —— 这里用 npm 安装的 * undici 调 setGlobalDispatcher 即可令原生 fetch 走 ProxyAgent(连接池首次 * 触发后对全部后续请求生效)。 * * 配置来源:app_config 的 `network.proxyUrl`;未配置时回退环境变量 * HTTPS_PROXY/HTTP_PROXY;两者皆空则显式恢复直连。 * * 失败语义:任一通道设置失败仅记录警告并继续,绝不阻断主流程 —— 网络不可达类 * 故障由各调用方的既有超时/重试机制兜底。 */ import { session } from 'electron'; import log from 'electron-log'; const AGENT_BROWSER_PARTITION = 'persist:metona-agent-browser'; export async function applySessionProxy(proxyUrl: string | null | undefined): Promise { const envProxy = process.env['HTTPS_PROXY'] || process.env['HTTP_PROXY'] || ''; const rules = (typeof proxyUrl === 'string' ? proxyUrl.trim() : '') || envProxy; // ===== 通道一:Chromium sessions ===== try { const config = rules !== '' ? { proxyRules: rules } : ({ mode: 'direct' as const }); await session.defaultSession.setProxy(config); await session.fromPartition(AGENT_BROWSER_PARTITION).setProxy(config); log.info( `[Network] Chromium sessions proxy ${rules === '' ? 'set to direct (no proxy)' : `rules: ${rules}`}`, ); } catch (err) { log.warn(`[Network] Failed to apply Chromium session proxy "${rules}": ${(err as Error).message}`); } // ===== 通道二:主进程 Node fetch(undici 全局 dispatcher)===== // 动态 import:主进程所有 fetch 出口共享该调度器;setGlobalDispatcher 写入的 // 全局符号对所有引用同一 undici registry 的 fetch 实例生效。失败不阻断主流程。 await (async () => { try { const { Agent, ProxyAgent, setGlobalDispatcher } = await import('undici'); if (rules !== '') { setGlobalDispatcher(new ProxyAgent({ uri: rules, connectTimeout: 15_000 })); log.info(`[Network] Node fetch dispatcher → ProxyAgent(${rules})`); } else { setGlobalDispatcher(new Agent()); log.info('[Network] Node fetch dispatcher → direct Agent'); } } catch (err) { // 理论仅在 undici 原生绑定异常时发生;fetch 将保持默认直连行为 log.warn(`[Network] Failed to set undici dispatcher for proxy "${rules}": ${(err as Error).message}`); } })(); }