AI-optimized code

This commit is contained in:
DHR60 2025-06-20 13:22:14 +08:00
parent babf979342
commit ae41d2e15f
2 changed files with 268 additions and 159 deletions

View file

@ -954,101 +954,166 @@ public class CoreConfigSingboxService
{ {
try try
{ {
var proxyOutbounds = new List<Outbound4Sbox>(); // Get outbound template and initialize lists
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
var chainProxy = new Dictionary<string, (Outbound4Sbox?, Outbound4Sbox?)>(); if (txtOutbound.IsNullOrEmpty())
var proxyTags = new List<string>(); {
return 0;
}
var index = 0; var resultOutbounds = new List<Outbound4Sbox>();
var prevOutbounds = new List<Outbound4Sbox>(); // Separate list for prev outbounds
var proxyTags = new List<string>(); // For selector and urltest outbounds
// Cache for chain proxies to avoid duplicate generation
var chainProxyCache = new Dictionary<string, (string?, Outbound4Sbox?)>();
var prevProxyTags = new Dictionary<string, string>(); // Map from profile name to tag
int prevIndex = 0; // Index for prev outbounds
// Process each node
int index = 0;
foreach (var node in nodes) foreach (var node in nodes)
{ {
index++; index++;
Outbound4Sbox? prevOutbound = null;
Outbound4Sbox? nextOutbound = null;
if (node.Subid.IsNotEmpty())
{
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
if (chainProxy.ContainsKey(node.Subid))
{
(prevOutbound, nextOutbound) = chainProxy[node.Subid];
}
else if (subItem is not null)
{
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom)
{
prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(prevNode, prevOutbound);
}
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile); // Skip unsupported config types
if (nextNode is not null
&& nextNode.ConfigType != EConfigType.Custom)
{
nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(nextNode, nextOutbound);
}
chainProxy.TryAdd(node.Subid, (prevOutbound, nextOutbound));
if (prevOutbound is not null)
{
prevOutbound.tag = $"1-{Global.ProxyTag}-{index}";
proxyOutbounds.Add(prevOutbound);
}
}
}
if (node.ConfigType is EConfigType.Custom) if (node.ConfigType is EConfigType.Custom)
{ {
continue; continue;
} }
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(node, outbound);
outbound.tag = $"{Global.ProxyTag}-{index}";
proxyTags.Add(outbound.tag);
proxyOutbounds.Add(outbound);
if (prevOutbound is not null) // Handle proxy chain
string? prevTag = null;
Outbound4Sbox? nextOutbound = null;
if (node.Subid.IsNotEmpty())
{ {
outbound.detour = prevOutbound.tag; // Check if chain proxy is already cached
if (chainProxyCache.TryGetValue(node.Subid, out var chainProxy))
{
prevTag = chainProxy.Item1;
nextOutbound = chainProxy.Item2;
}
else
{
// Generate chain proxy and cache it
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
if (subItem != null)
{
// Process previous proxy
if (!subItem.PrevProfile.IsNullOrEmpty())
{
// Check if this previous proxy was already created
if (prevProxyTags.TryGetValue(subItem.PrevProfile, out var existingTag))
{
prevTag = existingTag;
}
else
{
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
if (prevNode != null && prevNode.ConfigType != EConfigType.Custom)
{
prevIndex++;
var prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(prevNode, prevOutbound);
prevTag = $"{Global.ProxyTag}-prev-{prevIndex}";
prevOutbound.tag = prevTag;
prevProxyTags[subItem.PrevProfile] = prevTag;
// Add to prev outbounds list (will be added at the end)
prevOutbounds.Add(prevOutbound);
}
}
}
// Process next proxy
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
if (nextNode != null && nextNode.ConfigType != EConfigType.Custom)
{
nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(nextNode, nextOutbound);
}
// Cache the chain proxy
chainProxyCache[node.Subid] = (prevTag, nextOutbound);
}
}
} }
if (nextOutbound is not null) // Create main outbound
{ var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
var nextOutboundCopy = JsonUtils.DeepCopy(nextOutbound);
nextOutboundCopy.tag = outbound.tag; await GenOutbound(node, outbound);
outbound.tag = $"3-{Global.ProxyTag}-{index}"; outbound.tag = $"{Global.ProxyTag}-{index}";
nextOutboundCopy.detour = outbound.tag;
proxyOutbounds.Add(nextOutboundCopy); // Configure proxy chain relationships
if (nextOutbound != null)
{
// If there's a next proxy, it should be the final outbound in the chain
var originalTag = outbound.tag;
outbound.tag = $"mid-{Global.ProxyTag}-{index}";
var nextOutboundCopy = JsonUtils.DeepCopy(nextOutbound);
nextOutboundCopy.tag = originalTag;
nextOutboundCopy.detour = outbound.tag; // Use detour instead of sockopt
if (prevTag != null)
{
outbound.detour = prevTag;
}
// Add to proxy tags for selector/urltest
proxyTags.Add(originalTag);
// Add in reverse order to ensure final outbound is added first
resultOutbounds.Add(nextOutboundCopy); // Final outbound (exposed to internet)
resultOutbounds.Add(outbound); // Middle outbound
}
else
{
// If no next proxy, the main outbound is the final one
if (prevTag != null)
{
outbound.detour = prevTag;
}
// Add to proxy tags for selector/urltest
proxyTags.Add(outbound.tag);
resultOutbounds.Add(outbound);
} }
} }
//add urltest outbound // Add urltest outbound (auto selection based on latency)
var outUrltest = new Outbound4Sbox if (proxyTags.Count > 0)
{ {
type = "urltest", var outUrltest = new Outbound4Sbox
tag = $"{Global.ProxyTag}-auto", {
outbounds = proxyTags, type = "urltest",
interrupt_exist_connections = false, tag = $"{Global.ProxyTag}-auto",
}; outbounds = proxyTags,
proxyOutbounds.Insert(0, outUrltest); interrupt_exist_connections = false,
};
//add selector outbound // Add selector outbound (manual selection)
var outSelector = new Outbound4Sbox var outSelector = new Outbound4Sbox
{ {
type = "selector", type = "selector",
tag = Global.ProxyTag, tag = Global.ProxyTag,
outbounds = JsonUtils.DeepCopy(proxyTags), outbounds = JsonUtils.DeepCopy(proxyTags),
interrupt_exist_connections = false, interrupt_exist_connections = false,
}; };
outSelector.outbounds.Insert(0, outUrltest.tag); outSelector.outbounds.Insert(0, outUrltest.tag);
proxyOutbounds.Insert(0, outSelector);
proxyOutbounds.AddRange(singboxConfig.outbounds); // Insert these at the beginning
singboxConfig.outbounds = proxyOutbounds; resultOutbounds.Insert(0, outUrltest);
resultOutbounds.Insert(0, outSelector);
}
// Merge results: first the selector/urltest/proxies, then other outbounds, and finally prev outbounds
resultOutbounds.AddRange(prevOutbounds);
resultOutbounds.AddRange(singboxConfig.outbounds);
singboxConfig.outbounds = resultOutbounds;
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -1365,17 +1365,24 @@ public class CoreConfigV2rayService
{ {
try try
{ {
var proxyOutbounds = new List<Outbounds4Ray>(); // Get template and initialize list
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
var chainProxy = new Dictionary<string, (Outbounds4Ray?, Outbounds4Ray?)>(); if (txtOutbound.IsNullOrEmpty())
{
return 0;
}
var resultOutbounds = new List<Outbounds4Ray>();
var prevOutbounds = new List<Outbounds4Ray>(); // Separate list for prev outbounds and fragment
// Handle fragment outbound
Outbounds4Ray? fragmentOutbound = null; Outbounds4Ray? fragmentOutbound = null;
if (_config.CoreBasicItem.EnableFragment) if (_config.CoreBasicItem.EnableFragment)
{ {
fragmentOutbound = new Outbounds4Ray fragmentOutbound = new Outbounds4Ray
{ {
protocol = "freedom", protocol = "freedom",
tag = $"4-{Global.ProxyTag}", tag = $"fragment-{Global.ProxyTag}",
settings = new() settings = new()
{ {
fragment = new() fragment = new()
@ -1386,110 +1393,147 @@ public class CoreConfigV2rayService
} }
} }
}; };
// Add to prevOutbounds instead of v2rayConfig.outbounds
v2rayConfig.outbounds.Add(fragmentOutbound); prevOutbounds.Add(fragmentOutbound);
} }
var index = 0; // Cache for chain proxies to avoid duplicate generation
var chainProxyCache = new Dictionary<string, (string?, Outbounds4Ray?)>();
var prevProxyTags = new Dictionary<string, string>(); // Map from profile name to tag
int prevIndex = 0; // Index for prev outbounds
// Process nodes
int index = 0;
foreach (var node in nodes) foreach (var node in nodes)
{ {
index++; index++;
Outbounds4Ray? prevOutbound = null;
Outbounds4Ray? nextOutbound = null;
if (node.Subid.IsNotEmpty())
{
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
if (chainProxy.ContainsKey(node.Subid))
{
(prevOutbound, nextOutbound) = chainProxy[node.Subid];
}
else if (subItem is not null)
{
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2
&& prevNode.ConfigType != EConfigType.TUIC)
{
prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(prevNode, prevOutbound);
}
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile); // Skip unsupported config types
if (nextNode is not null if (node.ConfigType is EConfigType.Custom or EConfigType.Hysteria2 or EConfigType.TUIC)
&& nextNode.ConfigType != EConfigType.Custom
&& nextNode.ConfigType != EConfigType.Hysteria2
&& nextNode.ConfigType != EConfigType.TUIC)
{
nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(nextNode, nextOutbound);
}
chainProxy.TryAdd(node.Subid, (prevOutbound, nextOutbound));
if (prevOutbound is not null)
{
prevOutbound.tag = $"1-{Global.ProxyTag}-{index}";
proxyOutbounds.Add(prevOutbound);
if (fragmentOutbound != null
&& prevOutbound.streamSettings?.security.IsNullOrEmpty() == false)
{
prevOutbound.streamSettings.sockopt = new()
{
dialerProxy = fragmentOutbound.tag
};
}
}
}
}
if (node.ConfigType is EConfigType.Custom
or EConfigType.Hysteria2
or EConfigType.TUIC)
{ {
continue; continue;
} }
// Handle proxy chain
string? prevTag = null;
Outbounds4Ray? nextOutbound = null;
if (!node.Subid.IsNullOrEmpty())
{
// Check if chain proxy is already cached
if (chainProxyCache.TryGetValue(node.Subid, out var chainProxy))
{
prevTag = chainProxy.Item1;
nextOutbound = chainProxy.Item2;
}
else
{
// Generate chain proxy and cache it
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
if (subItem != null)
{
// Process previous proxy
if (!subItem.PrevProfile.IsNullOrEmpty())
{
// Check if this previous proxy was already created
if (prevProxyTags.TryGetValue(subItem.PrevProfile, out var existingTag))
{
prevTag = existingTag;
}
else
{
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
if (prevNode != null
&& prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2
&& prevNode.ConfigType != EConfigType.TUIC)
{
prevIndex++;
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(prevNode, prevOutbound);
prevTag = $"{Global.ProxyTag}-prev-{prevIndex}";
prevOutbound.tag = prevTag;
prevProxyTags[subItem.PrevProfile] = prevTag;
// Set fragment if needed
if (fragmentOutbound != null && prevOutbound.streamSettings?.security.IsNullOrEmpty() == false)
{
prevOutbound.streamSettings.sockopt = new()
{
dialerProxy = fragmentOutbound.tag
};
}
// Add to prev outbounds list (will be added at the end)
prevOutbounds.Add(prevOutbound);
}
}
}
// Process next proxy
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
if (nextNode != null
&& nextNode.ConfigType != EConfigType.Custom
&& nextNode.ConfigType != EConfigType.Hysteria2
&& nextNode.ConfigType != EConfigType.TUIC)
{
nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(nextNode, nextOutbound);
}
// Cache the chain proxy
chainProxyCache[node.Subid] = (prevTag, nextOutbound);
}
}
}
// Create main outbound
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound); var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(node, outbound); await GenOutbound(node, outbound);
outbound.tag = $"{Global.ProxyTag}-{index}"; outbound.tag = $"{Global.ProxyTag}-{index}";
proxyOutbounds.Add(outbound);
if (prevOutbound is not null) // Configure proxy chain relationships
if (nextOutbound != null)
{ {
outbound.streamSettings.sockopt = new() // If there's a next proxy, it should be the final outbound in the chain
{ var originalTag = outbound.tag;
dialerProxy = prevOutbound.tag outbound.tag = $"mid-{Global.ProxyTag}-{index}";
};
}
else if (fragmentOutbound != null
&& outbound.streamSettings?.security.IsNullOrEmpty() == false)
{
outbound.streamSettings.sockopt = new()
{
dialerProxy = fragmentOutbound.tag
};
}
if (nextOutbound is not null)
{
var nextOutboundCopy = JsonUtils.DeepCopy(nextOutbound); var nextOutboundCopy = JsonUtils.DeepCopy(nextOutbound);
nextOutboundCopy.tag = originalTag;
nextOutboundCopy.streamSettings.sockopt = new() { dialerProxy = outbound.tag };
nextOutboundCopy.tag = outbound.tag; if (prevTag != null)
outbound.tag = $"3-{Global.ProxyTag}-{index}";
nextOutboundCopy.streamSettings.sockopt = new()
{ {
dialerProxy = outbound.tag outbound.streamSettings.sockopt = new() { dialerProxy = prevTag };
}; }
proxyOutbounds.Add(nextOutboundCopy);
// Add in reverse order to ensure final outbound is added first
resultOutbounds.Add(nextOutboundCopy); // Final outbound (exposed to internet)
resultOutbounds.Add(outbound); // Middle outbound
}
else
{
// If no next proxy, the main outbound is the final one
if (prevTag != null)
{
outbound.streamSettings.sockopt = new() { dialerProxy = prevTag };
}
else if (fragmentOutbound != null && outbound.streamSettings?.security.IsNullOrEmpty() == false)
{
outbound.streamSettings.sockopt = new() { dialerProxy = fragmentOutbound.tag };
}
resultOutbounds.Add(outbound);
} }
} }
if (fragmentOutbound != null)
{ // Merge results: first the main chain outbounds, then other outbounds, and finally utility outbounds
proxyOutbounds.Add(fragmentOutbound); resultOutbounds.AddRange(prevOutbounds);
} resultOutbounds.AddRange(v2rayConfig.outbounds);
proxyOutbounds.AddRange(v2rayConfig.outbounds); v2rayConfig.outbounds = resultOutbounds;
v2rayConfig.outbounds = proxyOutbounds;
} }
catch (Exception ex) catch (Exception ex)
{ {