@@ -7,27 +7,27 @@ public static class CoreConfigHandler
77{
88 private static readonly string _tag = "CoreConfigHandler" ;
99
10- public static async Task < RetResult > GenerateClientConfig ( ProfileItem node , string ? fileName )
10+ public static async Task < RetResult > GenerateClientConfig ( CoreConfigContext context , string ? fileName )
1111 {
1212 var config = AppManager . Instance . Config ;
1313 var result = new RetResult ( ) ;
14+ var node = context . Node ;
1415
1516 if ( node . ConfigType == EConfigType . Custom )
1617 {
1718 result = node . CoreType switch
1819 {
1920 ECoreType . mihomo => await new CoreConfigClashService ( config ) . GenerateClientCustomConfig ( node , fileName ) ,
20- ECoreType . sing_box => await new CoreConfigSingboxService ( config ) . GenerateClientCustomConfig ( node , fileName ) ,
2121 _ => await GenerateClientCustomConfig ( node , fileName )
2222 } ;
2323 }
2424 else if ( AppManager . Instance . GetCoreType ( node , node . ConfigType ) == ECoreType . sing_box )
2525 {
26- result = await new CoreConfigSingboxService ( config ) . GenerateClientConfigContent ( node ) ;
26+ result = new CoreConfigSingboxService ( context ) . GenerateClientConfigContent ( ) ;
2727 }
2828 else
2929 {
30- result = await new CoreConfigV2rayService ( config ) . GenerateClientConfigContent ( node ) ;
30+ result = new CoreConfigV2rayService ( context ) . GenerateClientConfigContent ( ) ;
3131 }
3232 if ( result . Success != true )
3333 {
@@ -93,13 +93,21 @@ private static async Task<RetResult> GenerateClientCustomConfig(ProfileItem node
9393 public static async Task < RetResult > GenerateClientSpeedtestConfig ( Config config , string fileName , List < ServerTestItem > selecteds , ECoreType coreType )
9494 {
9595 var result = new RetResult ( ) ;
96+ var context = await BuildCoreConfigContext ( config , new ( ) ) ;
97+ var ids = selecteds . Where ( serverTestItem => ! serverTestItem . IndexId . IsNullOrEmpty ( ) )
98+ . Select ( serverTestItem => serverTestItem . IndexId ) ;
99+ var nodes = await AppManager . Instance . GetProfileItemsByIndexIds ( ids ) ;
100+ foreach ( var node in nodes )
101+ {
102+ await FillNodeContext ( context , node , false ) ;
103+ }
96104 if ( coreType == ECoreType . sing_box )
97105 {
98- result = await new CoreConfigSingboxService ( config ) . GenerateClientSpeedtestConfig ( selecteds ) ;
106+ result = new CoreConfigSingboxService ( context ) . GenerateClientSpeedtestConfig ( selecteds ) ;
99107 }
100108 else if ( coreType == ECoreType . Xray )
101109 {
102- result = await new CoreConfigV2rayService ( config ) . GenerateClientSpeedtestConfig ( selecteds ) ;
110+ result = new CoreConfigV2rayService ( context ) . GenerateClientSpeedtestConfig ( selecteds ) ;
103111 }
104112 if ( result . Success != true )
105113 {
@@ -109,20 +117,21 @@ public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config,
109117 return result ;
110118 }
111119
112- public static async Task < RetResult > GenerateClientSpeedtestConfig ( Config config , ProfileItem node , ServerTestItem testItem , string fileName )
120+ public static async Task < RetResult > GenerateClientSpeedtestConfig ( Config config , CoreConfigContext context , ServerTestItem testItem , string fileName )
113121 {
114122 var result = new RetResult ( ) ;
123+ var node = context . Node ;
115124 var initPort = AppManager . Instance . GetLocalPort ( EInboundProtocol . speedtest ) ;
116125 var port = Utils . GetFreePort ( initPort + testItem . QueueNum ) ;
117126 testItem . Port = port ;
118127
119128 if ( AppManager . Instance . GetCoreType ( node , node . ConfigType ) == ECoreType . sing_box )
120129 {
121- result = await new CoreConfigSingboxService ( config ) . GenerateClientSpeedtestConfig ( node , port ) ;
130+ result = new CoreConfigSingboxService ( context ) . GenerateClientSpeedtestConfig ( port ) ;
122131 }
123132 else
124133 {
125- result = await new CoreConfigV2rayService ( config ) . GenerateClientSpeedtestConfig ( node , port ) ;
134+ result = new CoreConfigV2rayService ( context ) . GenerateClientSpeedtestConfig ( port ) ;
126135 }
127136 if ( result . Success != true )
128137 {
@@ -132,4 +141,127 @@ public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config,
132141 await File . WriteAllTextAsync ( fileName , result . Data . ToString ( ) ) ;
133142 return result ;
134143 }
144+
145+ public static async Task < CoreConfigContext > BuildCoreConfigContext ( Config config , ProfileItem node )
146+ {
147+ var coreType = AppManager . Instance . GetCoreType ( node , node . ConfigType ) == ECoreType . sing_box ? ECoreType . sing_box : ECoreType . Xray ;
148+ var context = new CoreConfigContext ( )
149+ {
150+ Node = node ,
151+ AllProxiesMap = [ ] ,
152+ AppConfig = config ,
153+ FullConfigTemplate = await AppManager . Instance . GetFullConfigTemplateItem ( coreType ) ,
154+ IsTunEnabled = config . TunModeItem . EnableTun ,
155+ SimpleDnsItem = config . SimpleDNSItem ,
156+ ProtectDomainList = [ ] ,
157+ ProtectSocksPort = 0 ,
158+ RawDnsItem = await AppManager . Instance . GetDNSItem ( coreType ) ,
159+ RoutingItem = await ConfigHandler . GetDefaultRouting ( config ) ,
160+ } ;
161+ context = context with
162+ {
163+ Node = await FillNodeContext ( context , node )
164+ } ;
165+ if ( ! ( context . RoutingItem ? . RuleSet . IsNullOrEmpty ( ) ?? true ) )
166+ {
167+ var rules = JsonUtils . Deserialize < List < RulesItem > > ( context . RoutingItem ? . RuleSet ) ;
168+ foreach ( var ruleItem in rules . Where ( ruleItem => ! Global . OutboundTags . Contains ( ruleItem . OutboundTag ) ) )
169+ {
170+ var ruleOutboundNode = await AppManager . Instance . GetProfileItemViaRemarks ( ruleItem . OutboundTag ) ;
171+ if ( ruleOutboundNode != null )
172+ {
173+ var ruleOutboundNodeAct = await FillNodeContext ( context , ruleOutboundNode , false ) ;
174+ context . AllProxiesMap [ $ "remark:{ ruleItem . OutboundTag } "] = ruleOutboundNodeAct ;
175+ }
176+ }
177+ }
178+ return context ;
179+ }
180+
181+ private static async Task < ProfileItem > FillNodeContext ( CoreConfigContext context , ProfileItem node , bool includeSubChain = true )
182+ {
183+ if ( node . IndexId . IsNullOrEmpty ( ) )
184+ {
185+ return node ;
186+ }
187+ var newItems = new List < ProfileItem > { node } ;
188+ if ( node . ConfigType . IsGroupType ( ) )
189+ {
190+ var ( groupChildList , _) = await GroupProfileManager . GetChildProfileItems ( node ) ;
191+ foreach ( var childItem in groupChildList . Where ( childItem => ! context . AllProxiesMap . ContainsKey ( childItem . IndexId ) ) )
192+ {
193+ await FillNodeContext ( context , childItem , false ) ;
194+ }
195+ node . SetProtocolExtra ( node . GetProtocolExtra ( ) with
196+ {
197+ ChildItems = Utils . List2String ( groupChildList . Select ( n => n . IndexId ) . ToList ( ) ) ,
198+ } ) ;
199+ newItems . AddRange ( groupChildList ) ;
200+ }
201+ context . AllProxiesMap [ node . IndexId ] = node ;
202+
203+ foreach ( var item in newItems )
204+ {
205+ var address = item . Address ;
206+ if ( Utils . IsDomain ( address ) )
207+ {
208+ context . ProtectDomainList . Add ( address ) ;
209+ }
210+
211+ if ( item . EchConfigList . IsNullOrEmpty ( ) )
212+ {
213+ continue ;
214+ }
215+
216+ var echQuerySni = item . Sni ;
217+ if ( item . StreamSecurity == Global . StreamSecurity
218+ && item . EchConfigList ? . Contains ( "://" ) == true )
219+ {
220+ var idx = item . EchConfigList . IndexOf ( '+' ) ;
221+ echQuerySni = idx > 0 ? item . EchConfigList [ ..idx ] : item . Sni ;
222+ }
223+ if ( ! Utils . IsDomain ( echQuerySni ) )
224+ {
225+ continue ;
226+ }
227+ context . ProtectDomainList . Add ( echQuerySni ) ;
228+ }
229+
230+ if ( ! includeSubChain || node . Subid . IsNullOrEmpty ( ) )
231+ {
232+ return node ;
233+ }
234+
235+ var subItem = await AppManager . Instance . GetSubItem ( node . Subid ) ;
236+ if ( subItem == null )
237+ {
238+ return node ;
239+ }
240+ var prevNode = await AppManager . Instance . GetProfileItemViaRemarks ( subItem . PrevProfile ) ;
241+ var nextNode = await AppManager . Instance . GetProfileItemViaRemarks ( subItem . NextProfile ) ;
242+ if ( prevNode is null && nextNode is null )
243+ {
244+ return node ;
245+ }
246+
247+ var prevNodeAct = prevNode is null ? null : await FillNodeContext ( context , prevNode , false ) ;
248+ var nextNodeAct = nextNode is null ? null : await FillNodeContext ( context , nextNode , false ) ;
249+
250+ // Build new proxy chain node
251+ var chainNode = new ProfileItem ( )
252+ {
253+ IndexId = $ "inner-{ Utils . GetGuid ( false ) } ",
254+ ConfigType = EConfigType . ProxyChain ,
255+ CoreType = node . CoreType ?? ECoreType . Xray ,
256+ } ;
257+ List < string ? > childItems = [ prevNodeAct ? . IndexId , node . IndexId , nextNodeAct ? . IndexId ] ;
258+ var chainExtraItem = chainNode . GetProtocolExtra ( ) with
259+ {
260+ GroupType = chainNode . ConfigType . ToString ( ) ,
261+ ChildItems = string . Join ( "," , childItems . Where ( x => ! x . IsNullOrEmpty ( ) ) ) ,
262+ } ;
263+ chainNode . SetProtocolExtra ( chainExtraItem ) ;
264+ context . AllProxiesMap [ chainNode . IndexId ] = chainNode ;
265+ return chainNode ;
266+ }
135267}
0 commit comments