diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 1c1d58a7..d81b0783 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -959,6 +959,7 @@ public class CoreConfigSingboxService var proxyTags = new List(); // For selector and urltest outbounds // Cache for chain proxies to avoid duplicate generation + var nextProxyCache = new Dictionary(); var prevProxyTags = new Dictionary(); // Map from profile name to tag int prevIndex = 0; // Index for prev outbounds @@ -971,19 +972,24 @@ public class CoreConfigSingboxService // Handle proxy chain string? prevTag = null; var currentOutbound = JsonUtils.Deserialize(txtOutbound); - Outbound4Sbox? nextOutbound = null; + var nextOutbound = nextProxyCache.GetValueOrDefault(node.Subid, null); + if (nextOutbound != null) + { + nextOutbound = JsonUtils.DeepCopy(nextOutbound); + } var subItem = await AppHandler.Instance.GetSubItem(node.Subid); // current proxy await GenOutbound(node, currentOutbound); currentOutbound.tag = $"{Global.ProxyTag}-{index}"; + proxyTags.Add(currentOutbound.tag); if (!node.Subid.IsNullOrEmpty()) { - if (prevProxyTags.ContainsKey(node.Subid)) + if (prevProxyTags.TryGetValue(node.Subid, out var value)) { - prevTag = prevProxyTags[node.Subid]; // maybe null + prevTag = value; // maybe null } else { @@ -1000,7 +1006,11 @@ public class CoreConfigSingboxService prevProxyTags[node.Subid] = prevTag; } - nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag); + nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag, nextOutbound); + if (!nextProxyCache.ContainsKey(node.Subid)) + { + nextProxyCache[node.Subid] = nextOutbound; + } } if (nextOutbound is not null) @@ -1057,10 +1067,11 @@ public class CoreConfigSingboxService /// The subscription item containing proxy chain information. /// The current outbound configuration. Its tag must be set before calling this method. /// The tag of the previous outbound in the chain, if any. + /// The outbound for the next proxy in the chain, if already created. If null, will be created inside. /// /// The outbound configuration for the next proxy in the chain, or null if no next proxy exists. /// - private async Task GenChainOutbounds(SubItem subItem, Outbound4Sbox outbound, string? prevOutboundTag) + private async Task GenChainOutbounds(SubItem subItem, Outbound4Sbox outbound, string? prevOutboundTag, Outbound4Sbox? nextOutbound = null) { try { @@ -1073,12 +1084,14 @@ public class CoreConfigSingboxService // Next proxy var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile); - Outbound4Sbox? nextOutbound = null; if (nextNode is not null && nextNode.ConfigType != EConfigType.Custom) { - nextOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(nextNode, nextOutbound); + if (nextOutbound == null) + { + nextOutbound = JsonUtils.Deserialize(txtOutbound); + await GenOutbound(nextNode, nextOutbound); + } nextOutbound.tag = outbound.tag; outbound.tag = $"mid-{outbound.tag}"; diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs index 2db69ca4..c181d426 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs @@ -1360,6 +1360,7 @@ public class CoreConfigV2rayService var prevOutbounds = new List(); // Separate list for prev outbounds and fragment // Cache for chain proxies to avoid duplicate generation + var nextProxyCache = new Dictionary(); var prevProxyTags = new Dictionary(); // Map from profile name to tag int prevIndex = 0; // Index for prev outbounds @@ -1372,7 +1373,11 @@ public class CoreConfigV2rayService // Handle proxy chain string? prevTag = null; var currentOutbound = JsonUtils.Deserialize(txtOutbound); - Outbounds4Ray? nextOutbound = null; + var nextOutbound = nextProxyCache.GetValueOrDefault(node.Subid, null); + if (nextOutbound != null) + { + nextOutbound = JsonUtils.DeepCopy(nextOutbound); + } var subItem = await AppHandler.Instance.GetSubItem(node.Subid); @@ -1382,9 +1387,9 @@ public class CoreConfigV2rayService if (!node.Subid.IsNullOrEmpty()) { - if (prevProxyTags.ContainsKey(node.Subid)) + if (prevProxyTags.TryGetValue(node.Subid, out var value)) { - prevTag = prevProxyTags[node.Subid]; // maybe null + prevTag = value; // maybe null } else { @@ -1403,7 +1408,11 @@ public class CoreConfigV2rayService prevProxyTags[node.Subid] = prevTag; } - nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag); + nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag, nextOutbound); + if (!nextProxyCache.ContainsKey(node.Subid)) + { + nextProxyCache[node.Subid] = nextOutbound; + } } if (nextOutbound is not null) @@ -1434,10 +1443,11 @@ public class CoreConfigV2rayService /// The subscription item containing proxy chain information. /// The current outbound configuration. Its tag must be set before calling this method. /// The tag of the previous outbound in the chain, if any. + /// The outbound for the next proxy in the chain, if already created. If null, will be created inside. /// /// The outbound configuration for the next proxy in the chain, or null if no next proxy exists. /// - private async Task GenChainOutbounds(SubItem subItem, Outbounds4Ray outbound, string? prevOutboundTag) + private async Task GenChainOutbounds(SubItem subItem, Outbounds4Ray outbound, string? prevOutboundTag, Outbounds4Ray? nextOutbound = null) { try { @@ -1453,14 +1463,16 @@ public class CoreConfigV2rayService // Next proxy var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile); - Outbounds4Ray? nextOutbound = null; if (nextNode is not null && nextNode.ConfigType != EConfigType.Custom && nextNode.ConfigType != EConfigType.Hysteria2 && nextNode.ConfigType != EConfigType.TUIC) { - nextOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(nextNode, nextOutbound); + if (nextOutbound == null) + { + nextOutbound = JsonUtils.Deserialize(txtOutbound); + await GenOutbound(nextNode, nextOutbound); + } nextOutbound.tag = outbound.tag; outbound.tag = $"mid-{outbound.tag}";