mirror of
https://github.com/2dust/v2rayN.git
synced 2025-10-13 20:09:12 +00:00
Add group in traffic splitting support
This commit is contained in:
parent
c00b0b7c43
commit
ff6ce3334a
9 changed files with 115 additions and 17 deletions
|
@ -50,6 +50,7 @@ public class Global
|
||||||
public const string DirectTag = "direct";
|
public const string DirectTag = "direct";
|
||||||
public const string BlockTag = "block";
|
public const string BlockTag = "block";
|
||||||
public const string DnsTag = "dns-module";
|
public const string DnsTag = "dns-module";
|
||||||
|
public const string BalancerTagSuffix = "-round";
|
||||||
public const string StreamSecurity = "tls";
|
public const string StreamSecurity = "tls";
|
||||||
public const string StreamSecurityReality = "reality";
|
public const string StreamSecurityReality = "reality";
|
||||||
public const string Loopback = "127.0.0.1";
|
public const string Loopback = "127.0.0.1";
|
||||||
|
|
|
@ -398,12 +398,12 @@ public partial class CoreConfigSingboxService(Config config)
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
singboxConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
await GenLog(singboxConfig);
|
await GenLog(singboxConfig);
|
||||||
await GenInbounds(singboxConfig);
|
await GenInbounds(singboxConfig);
|
||||||
await GenRouting(singboxConfig);
|
await GenRouting(singboxConfig);
|
||||||
await GenExperimental(singboxConfig);
|
await GenExperimental(singboxConfig);
|
||||||
singboxConfig.outbounds.RemoveAt(0);
|
|
||||||
|
|
||||||
var proxyProfiles = new List<ProfileItem>();
|
var proxyProfiles = new List<ProfileItem>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
|
|
|
@ -368,6 +368,39 @@ public partial class CoreConfigSingboxService
|
||||||
}
|
}
|
||||||
|
|
||||||
var node = await AppManager.Instance.GetProfileItemViaRemarks(outboundTag);
|
var node = await AppManager.Instance.GetProfileItemViaRemarks(outboundTag);
|
||||||
|
|
||||||
|
if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
|
||||||
|
{
|
||||||
|
ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem);
|
||||||
|
if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
var childProfiles = (await Task.WhenAll(
|
||||||
|
Utils.String2List(profileGroupItem.ChildItems)
|
||||||
|
.Where(p => !p.IsNullOrEmpty())
|
||||||
|
.Select(AppManager.Instance.GetProfileItem)
|
||||||
|
)).Where(p => p != null).ToList();
|
||||||
|
if (childProfiles.Count <= 0)
|
||||||
|
{
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
var childBaseTagName = $"{Global.ProxyTag}-{node.IndexId}";
|
||||||
|
var ret = node.ConfigType switch
|
||||||
|
{
|
||||||
|
EConfigType.PolicyGroup =>
|
||||||
|
await GenOutboundsList(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName),
|
||||||
|
EConfigType.ProxyChain =>
|
||||||
|
await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName),
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
};
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
return childBaseTagName;
|
||||||
|
}
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
|
||||||
if (node == null
|
if (node == null
|
||||||
|| !Global.SingboxSupportConfigType.Contains(node.ConfigType))
|
|| !Global.SingboxSupportConfigType.Contains(node.ConfigType))
|
||||||
{
|
{
|
||||||
|
|
|
@ -126,13 +126,13 @@ public partial class CoreConfigV2rayService(Config config)
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
v2rayConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
await GenLog(v2rayConfig);
|
await GenLog(v2rayConfig);
|
||||||
await GenInbounds(v2rayConfig);
|
await GenInbounds(v2rayConfig);
|
||||||
await GenRouting(v2rayConfig);
|
await GenRouting(v2rayConfig);
|
||||||
await GenDns(null, v2rayConfig);
|
await GenDns(null, v2rayConfig);
|
||||||
await GenStatistic(v2rayConfig);
|
await GenStatistic(v2rayConfig);
|
||||||
v2rayConfig.outbounds.RemoveAt(0);
|
|
||||||
|
|
||||||
var proxyProfiles = new List<ProfileItem>();
|
var proxyProfiles = new List<ProfileItem>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
|
@ -183,18 +183,37 @@ public partial class CoreConfigV2rayService(Config config)
|
||||||
await GenOutboundsList(proxyProfiles, v2rayConfig);
|
await GenOutboundsList(proxyProfiles, v2rayConfig);
|
||||||
|
|
||||||
//add balancers
|
//add balancers
|
||||||
|
await GenObservatory(v2rayConfig, multipleLoad);
|
||||||
await GenBalancer(v2rayConfig, multipleLoad);
|
await GenBalancer(v2rayConfig, multipleLoad);
|
||||||
|
|
||||||
var balancer = v2rayConfig.routing.balancers.First();
|
var defaultBalancerTag = $"{Global.ProxyTag}{Global.BalancerTagSuffix}";
|
||||||
|
|
||||||
//add rule
|
//add rule
|
||||||
var rules = v2rayConfig.routing.rules.Where(t => t.outboundTag == Global.ProxyTag).ToList();
|
var rules = v2rayConfig.routing.rules;
|
||||||
if (rules?.Count > 0)
|
if (rules?.Count > 0)
|
||||||
{
|
{
|
||||||
|
var balancerTagSet = v2rayConfig.routing.balancers
|
||||||
|
.Select(b => b.tag)
|
||||||
|
.ToHashSet();
|
||||||
|
|
||||||
foreach (var rule in rules)
|
foreach (var rule in rules)
|
||||||
{
|
{
|
||||||
rule.outboundTag = null;
|
if (rule.outboundTag == null)
|
||||||
rule.balancerTag = balancer.tag;
|
continue;
|
||||||
|
|
||||||
|
if (balancerTagSet.Contains(rule.outboundTag))
|
||||||
|
{
|
||||||
|
rule.balancerTag = rule.outboundTag;
|
||||||
|
rule.outboundTag = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outboundWithSuffix = rule.outboundTag + Global.BalancerTagSuffix;
|
||||||
|
if (balancerTagSet.Contains(outboundWithSuffix))
|
||||||
|
{
|
||||||
|
rule.balancerTag = outboundWithSuffix;
|
||||||
|
rule.outboundTag = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch)
|
if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch)
|
||||||
|
@ -202,7 +221,7 @@ public partial class CoreConfigV2rayService(Config config)
|
||||||
v2rayConfig.routing.rules.Add(new()
|
v2rayConfig.routing.rules.Add(new()
|
||||||
{
|
{
|
||||||
ip = ["0.0.0.0/0", "::/0"],
|
ip = ["0.0.0.0/0", "::/0"],
|
||||||
balancerTag = balancer.tag,
|
balancerTag = defaultBalancerTag,
|
||||||
type = "field"
|
type = "field"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -211,7 +230,7 @@ public partial class CoreConfigV2rayService(Config config)
|
||||||
v2rayConfig.routing.rules.Add(new()
|
v2rayConfig.routing.rules.Add(new()
|
||||||
{
|
{
|
||||||
network = "tcp,udp",
|
network = "tcp,udp",
|
||||||
balancerTag = balancer.tag,
|
balancerTag = defaultBalancerTag,
|
||||||
type = "field"
|
type = "field"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace ServiceLib.Services.CoreConfig;
|
||||||
|
|
||||||
public partial class CoreConfigV2rayService
|
public partial class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
private async Task<int> GenObservatory(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
||||||
{
|
{
|
||||||
if (multipleLoad == EMultipleLoad.LeastPing)
|
if (multipleLoad == EMultipleLoad.LeastPing)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,11 @@ public partial class CoreConfigV2rayService
|
||||||
};
|
};
|
||||||
v2rayConfig.burstObservatory = burstObservatory;
|
v2rayConfig.burstObservatory = burstObservatory;
|
||||||
}
|
}
|
||||||
|
return await Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad, string selector = Global.ProxyTag)
|
||||||
|
{
|
||||||
var strategyType = multipleLoad switch
|
var strategyType = multipleLoad switch
|
||||||
{
|
{
|
||||||
EMultipleLoad.Random => "random",
|
EMultipleLoad.Random => "random",
|
||||||
|
@ -38,9 +43,10 @@ public partial class CoreConfigV2rayService
|
||||||
EMultipleLoad.LeastLoad => "leastLoad",
|
EMultipleLoad.LeastLoad => "leastLoad",
|
||||||
_ => "roundRobin",
|
_ => "roundRobin",
|
||||||
};
|
};
|
||||||
|
var balancerTag = $"{selector}{Global.BalancerTagSuffix}";
|
||||||
var balancer = new BalancersItem4Ray
|
var balancer = new BalancersItem4Ray
|
||||||
{
|
{
|
||||||
selector = [Global.ProxyTag],
|
selector = [selector],
|
||||||
strategy = new()
|
strategy = new()
|
||||||
{
|
{
|
||||||
type = strategyType,
|
type = strategyType,
|
||||||
|
@ -49,9 +55,10 @@ public partial class CoreConfigV2rayService
|
||||||
expected = 1,
|
expected = 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tag = $"{Global.ProxyTag}-round",
|
tag = balancerTag,
|
||||||
};
|
};
|
||||||
v2rayConfig.routing.balancers = [balancer];
|
v2rayConfig.routing.balancers ??= new();
|
||||||
return await Task.FromResult(0);
|
v2rayConfig.routing.balancers.Add(balancer);
|
||||||
|
return await Task.FromResult(balancerTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -746,14 +746,15 @@ public partial class CoreConfigV2rayService
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
outbound.tag = baseTagName + i.ToString();
|
// avoid v2ray observe
|
||||||
|
outbound.tag = "chain-" + baseTagName + i.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != nodes.Count - 1)
|
if (i != nodes.Count - 1)
|
||||||
{
|
{
|
||||||
outbound.streamSettings.sockopt = new()
|
outbound.streamSettings.sockopt = new()
|
||||||
{
|
{
|
||||||
dialerProxy = baseTagName + (i + 1).ToString()
|
dialerProxy = "chain-" + baseTagName + (i + 1).ToString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,43 @@ public partial class CoreConfigV2rayService
|
||||||
}
|
}
|
||||||
|
|
||||||
var node = await AppManager.Instance.GetProfileItemViaRemarks(outboundTag);
|
var node = await AppManager.Instance.GetProfileItemViaRemarks(outboundTag);
|
||||||
|
|
||||||
|
if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
|
||||||
|
{
|
||||||
|
ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem);
|
||||||
|
if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
var childProfiles = (await Task.WhenAll(
|
||||||
|
Utils.String2List(profileGroupItem.ChildItems)
|
||||||
|
.Where(p => !p.IsNullOrEmpty())
|
||||||
|
.Select(AppManager.Instance.GetProfileItem)
|
||||||
|
)).Where(p => p != null).ToList();
|
||||||
|
if (childProfiles.Count <= 0)
|
||||||
|
{
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
var childBaseTagName = $"{Global.ProxyTag}-{node.IndexId}";
|
||||||
|
var ret = node.ConfigType switch
|
||||||
|
{
|
||||||
|
EConfigType.PolicyGroup =>
|
||||||
|
await GenOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
||||||
|
EConfigType.ProxyChain =>
|
||||||
|
await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
};
|
||||||
|
if (node.ConfigType == EConfigType.PolicyGroup)
|
||||||
|
{
|
||||||
|
await GenBalancer(v2rayConfig, profileGroupItem.MultipleLoad, childBaseTagName);
|
||||||
|
}
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
return childBaseTagName;
|
||||||
|
}
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
|
||||||
if (node == null
|
if (node == null
|
||||||
|| !Global.XraySupportConfigType.Contains(node.ConfigType))
|
|| !Global.XraySupportConfigType.Contains(node.ConfigType))
|
||||||
{
|
{
|
||||||
|
|
|
@ -98,7 +98,7 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
|
||||||
private async void BtnSelectProfile_Click(object? sender, RoutedEventArgs e)
|
private async void BtnSelectProfile_Click(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var selectWindow = new ProfilesSelectWindow();
|
var selectWindow = new ProfilesSelectWindow();
|
||||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom }, exclude: true);
|
||||||
var result = await selectWindow.ShowDialog<bool?>(this);
|
var result = await selectWindow.ShowDialog<bool?>(this);
|
||||||
if (result == true)
|
if (result == true)
|
||||||
{
|
{
|
||||||
|
|
|
@ -91,7 +91,7 @@ public partial class RoutingRuleDetailsWindow
|
||||||
private async void BtnSelectProfile_Click(object sender, RoutedEventArgs e)
|
private async void BtnSelectProfile_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var selectWindow = new ProfilesSelectWindow();
|
var selectWindow = new ProfilesSelectWindow();
|
||||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom }, exclude: true);
|
||||||
if (selectWindow.ShowDialog() == true)
|
if (selectWindow.ShowDialog() == true)
|
||||||
{
|
{
|
||||||
var profile = await selectWindow.ProfileItem;
|
var profile = await selectWindow.ProfileItem;
|
||||||
|
|
Loading…
Reference in a new issue