@@ -7,12 +7,39 @@ export class ClashClient {
77 try {
88 const configs = await Promise . all ( urls . map ( url => fetchWithRetry ( url , { retries : 3 } ) . then ( r => r . data . text ( ) ) ) ) ;
99 const clashConfigs = configs . map ( config => load ( config ) as ClashType ) ;
10- return this . mergeClashConfig ( clashConfigs ) ;
10+ const mergedConfig = this . mergeClashConfig ( clashConfigs ) ;
11+ return mergedConfig ;
1112 } catch ( error : any ) {
1213 throw new Error ( `Failed to get clash config: ${ error . message || error } ` ) ;
1314 }
1415 }
1516
17+ /**
18+ * 对比两个 proxies 数组是否完全相同
19+ * 使用 Set 对比,忽略顺序差异
20+ */
21+ private isSameProxies ( arr1 : string [ ] , arr2 : string [ ] ) : boolean {
22+ if ( arr1 . length !== arr2 . length ) return false ;
23+ const set1 = new Set ( arr1 ) ;
24+ return arr2 . every ( item => set1 . has ( item ) ) ;
25+ }
26+
27+ /**
28+ * 合并两个 proxies 数组,去重并保持顺序
29+ * 时间复杂度: O(n),使用 Set 优化查找
30+ */
31+ private mergeGroupProxies ( existing : string [ ] , incoming : string [ ] ) : string [ ] {
32+ const seen = new Set ( existing ) ;
33+ const result = [ ...existing ] ;
34+ for ( const proxy of incoming ) {
35+ if ( ! seen . has ( proxy ) ) {
36+ seen . add ( proxy ) ;
37+ result . push ( proxy ) ;
38+ }
39+ }
40+ return result ;
41+ }
42+
1643 /**
1744 * @description 合并配置
1845 * @param {ClashType[] } configs
@@ -24,74 +51,56 @@ export class ClashClient {
2451 return { } as ClashType ;
2552 }
2653
27- const baseConfig = structuredClone ( configs [ 0 ] ) ;
28-
2954 // 如果只有一个配置,直接返回
3055 if ( configs . length === 1 ) {
31- return baseConfig ;
56+ return configs [ 0 ] ;
3257 }
3358
34- const mergedConfig : ClashType = {
35- ...baseConfig ,
36- proxies : baseConfig . proxies || [ ] ,
37- 'proxy-groups' : baseConfig [ 'proxy-groups' ] || [ ]
38- } ;
39-
40- // 预计算总代理数量
41- const totalProxies = configs . reduce ( ( total , config ) => total + ( config . proxies ?. length || 0 ) , 0 ) ;
42-
43- // 使用 TypedArray 和 Set 提高性能
44- const proxyIndices = new Int32Array ( totalProxies ) ;
45- const existingProxies = new Set ( baseConfig . proxies ?. map ( p => p . name ) ) ;
46- let proxyIndex = baseConfig . proxies ?. length || 0 ;
47-
48- // 使用 Map 存储代理组
49- const groupMap = new Map ( mergedConfig [ 'proxy-groups' ] . map ( group => [ group . name , group ] ) ) ;
50-
51- // 批量处理配置
52- for ( let i = 1 ; i < configs . length ; i ++ ) {
53- const config = configs [ i ] ;
54-
55- // 批量处理代理
59+ // 合并 proxies: 直接展开所有配置的 proxies
60+ const mergedProxies : Array < Record < string , string > > = [ ] ;
61+ for ( const config of configs ) {
5662 if ( config . proxies ?. length ) {
57- for ( const proxy of config . proxies ) {
58- if ( ! existingProxies . has ( proxy . name ) ) {
59- mergedConfig . proxies [ proxyIndex ] = proxy ;
60- proxyIndices [ proxyIndex ] = proxyIndex ;
61- existingProxies . add ( proxy . name ) ;
62- proxyIndex ++ ;
63- }
64- }
63+ mergedProxies . push ( ...config . proxies ) ;
6564 }
65+ }
6666
67- // 批量处理代理组
68- if ( config [ 'proxy-groups' ] ?. length ) {
69- for ( const group of config [ 'proxy-groups' ] ) {
70- const existingGroup = groupMap . get ( group . name ) ;
71-
72- if ( existingGroup ) {
73- // 使用 Set 优化代理列表去重
74- const proxySet = new Set ( existingGroup . proxies ) ;
75- for ( const proxy of group . proxies || [ ] ) {
76- proxySet . add ( proxy ) ;
77- }
78- existingGroup . proxies = Array . from ( proxySet ) ;
79-
80- // 合并其他属性
81- Object . assign ( existingGroup , {
82- ...group ,
83- proxies : existingGroup . proxies
84- } ) ;
85- } else {
86- mergedConfig [ 'proxy-groups' ] . push ( group ) ;
87- groupMap . set ( group . name , group ) ;
67+ // 合并 proxy-groups: 使用 Map 存储,O(1) 查找
68+ const groupMap = new Map < string , ClashType [ 'proxy-groups' ] [ 0 ] > ( ) ;
69+ const groupOrder : string [ ] = [ ] ;
70+
71+ for ( const config of configs ) {
72+ if ( ! config [ 'proxy-groups' ] ?. length ) continue ;
73+
74+ for ( const group of config [ 'proxy-groups' ] ) {
75+ const existingGroup = groupMap . get ( group . name ) ;
76+
77+ if ( ! existingGroup ) {
78+ // Map 中不存在该组名,直接添加
79+ groupMap . set ( group . name , {
80+ ...group ,
81+ proxies : [ ...( group . proxies || [ ] ) ] // 浅拷贝数组
82+ } ) ;
83+ groupOrder . push ( group . name ) ;
84+ } else {
85+ // Map 中已存在该组名,判断 proxies 是否相同
86+ const existingProxies = existingGroup . proxies || [ ] ;
87+ const incomingProxies = group . proxies || [ ] ;
88+
89+ if ( ! this . isSameProxies ( existingProxies , incomingProxies ) ) {
90+ // proxies 不同,合并差异部分
91+ existingGroup . proxies = this . mergeGroupProxies ( existingProxies , incomingProxies ) ;
8892 }
93+ // proxies 相同则跳过,保持不变
8994 }
9095 }
9196 }
9297
93- // 清理无效代理
94- mergedConfig . proxies = mergedConfig . proxies . filter ( ( _ , i ) => proxyIndices [ i ] !== - 1 ) ;
98+ // 构建合并后的配置
99+ const mergedConfig : ClashType = {
100+ ...configs [ 0 ] , // 保留第一个配置的其他属性
101+ proxies : mergedProxies ,
102+ 'proxy-groups' : groupOrder . map ( name => groupMap . get ( name ) ! )
103+ } ;
95104
96105 return mergedConfig ;
97106 } catch ( error : any ) {
0 commit comments