This commit is contained in:
DHR60 2025-09-30 19:40:34 +08:00
parent 4bf86665b7
commit 7c68e8aece
7 changed files with 157 additions and 42 deletions

View file

@ -1087,6 +1087,8 @@ public static class ConfigHandler
profileItem.IndexId = Utils.GetGuid(false); profileItem.IndexId = Utils.GetGuid(false);
maxSort = ProfileExManager.Instance.GetMaxSort(); maxSort = ProfileExManager.Instance.GetMaxSort();
} }
var groupType = profileItem.ConfigType == EConfigType.ProxyChain ? EConfigType.ProxyChain.ToString() : profileGroupItem.MultipleLoad.ToString();
profileItem.Address = $"{profileItem.CoreType}-{groupType}";
if (maxSort > 0) if (maxSort > 0)
{ {
ProfileExManager.Instance.SetSort(profileItem.IndexId, maxSort + 1); ProfileExManager.Instance.SetSort(profileItem.IndexId, maxSort + 1);
@ -1194,10 +1196,10 @@ public static class ConfigHandler
var indexId = Utils.GetGuid(false); var indexId = Utils.GetGuid(false);
var childProfileIndexId = Utils.List2String(selecteds.Select(p => p.IndexId).ToList()); var childProfileIndexId = Utils.List2String(selecteds.Select(p => p.IndexId).ToList());
var remark = string.Empty; var remark = subId.IsNullOrEmpty() ? string.Empty : $"{(await AppManager.Instance.GetSubItem(subId)).Remarks} ";
if (coreType == ECoreType.Xray) if (coreType == ECoreType.Xray)
{ {
remark = multipleLoad switch remark += multipleLoad switch
{ {
EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerXrayLeastPing, EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerXrayLeastPing,
EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerXrayFallback, EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerXrayFallback,
@ -1209,7 +1211,7 @@ public static class ConfigHandler
} }
else if (coreType == ECoreType.sing_box) else if (coreType == ECoreType.sing_box)
{ {
remark = multipleLoad switch remark += multipleLoad switch
{ {
EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerSingBoxLeastPing, EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerSingBoxLeastPing,
EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerSingBoxFallback, EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerSingBoxFallback,
@ -1222,7 +1224,6 @@ public static class ConfigHandler
CoreType = coreType, CoreType = coreType,
ConfigType = EConfigType.PolicyGroup, ConfigType = EConfigType.PolicyGroup,
Remarks = remark, Remarks = remark,
Address = childProfileIndexId,
}; };
if (!subId.IsNullOrEmpty()) if (!subId.IsNullOrEmpty())
{ {

View file

@ -363,8 +363,6 @@ public partial class CoreConfigSingboxService(Config config)
await GenLog(singboxConfig); await GenLog(singboxConfig);
await GenInbounds(singboxConfig); await GenInbounds(singboxConfig);
await GenRouting(singboxConfig);
await GenExperimental(singboxConfig);
var groupRet = await GenGroupOutbound(parentNode, singboxConfig); var groupRet = await GenGroupOutbound(parentNode, singboxConfig);
if (groupRet != 0) if (groupRet != 0)
@ -373,6 +371,8 @@ public partial class CoreConfigSingboxService(Config config)
return ret; return ret;
} }
await GenRouting(singboxConfig);
await GenExperimental(singboxConfig);
await GenDns(null, singboxConfig); await GenDns(null, singboxConfig);
await ConvertGeo2Ruleset(singboxConfig); await ConvertGeo2Ruleset(singboxConfig);
@ -416,12 +416,10 @@ 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 GenExperimental(singboxConfig);
singboxConfig.outbounds.RemoveAt(0);
var groupRet = await GenGroupOutbound(parentNode, singboxConfig); var groupRet = await GenGroupOutbound(parentNode, singboxConfig);
if (groupRet != 0) if (groupRet != 0)
@ -430,6 +428,8 @@ public partial class CoreConfigSingboxService(Config config)
return ret; return ret;
} }
await GenRouting(singboxConfig);
await GenExperimental(singboxConfig);
await GenDns(null, singboxConfig); await GenDns(null, singboxConfig);
await ConvertGeo2Ruleset(singboxConfig); await ConvertGeo2Ruleset(singboxConfig);

View file

@ -694,6 +694,39 @@ public partial class CoreConfigSingboxService
for (var i = 0; i < nodes.Count; i++) for (var i = 0; i < nodes.Count; i++)
{ {
var node = nodes[i]; var node = nodes[i];
if (node == null)
continue;
if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
{
ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem);
if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty())
{
continue;
}
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)
{
continue;
}
var childBaseTagName = $"{baseTagName}-{i + 1}";
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)
{
proxyTags.Add(childBaseTagName);
}
continue;
}
var server = await GenServer(node); var server = await GenServer(node);
if (server is null) if (server is null)
{ {

View file

@ -114,9 +114,6 @@ public partial class CoreConfigV2rayService(Config config)
await GenLog(v2rayConfig); await GenLog(v2rayConfig);
await GenInbounds(v2rayConfig); await GenInbounds(v2rayConfig);
await GenRouting(v2rayConfig);
await GenDns(null, v2rayConfig);
await GenStatistic(v2rayConfig);
var groupRet = await GenGroupOutbound(parentNode, v2rayConfig); var groupRet = await GenGroupOutbound(parentNode, v2rayConfig);
if (groupRet != 0) if (groupRet != 0)
@ -125,11 +122,15 @@ public partial class CoreConfigV2rayService(Config config)
return ret; return ret;
} }
await GenRouting(v2rayConfig);
await GenDns(null, v2rayConfig);
await GenStatistic(v2rayConfig);
var defaultBalancerTag = $"{Global.ProxyTag}{Global.BalancerTagSuffix}"; var defaultBalancerTag = $"{Global.ProxyTag}{Global.BalancerTagSuffix}";
//add rule //add rule
var rules = v2rayConfig.routing.rules; var rules = v2rayConfig.routing.rules;
if (rules?.Count > 0) if (rules?.Count > 0 && ((v2rayConfig.routing.balancers?.Count ?? 0) > 0))
{ {
var balancerTagSet = v2rayConfig.routing.balancers var balancerTagSet = v2rayConfig.routing.balancers
.Select(b => b.tag) .Select(b => b.tag)
@ -215,13 +216,10 @@ 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 GenDns(null, v2rayConfig);
await GenStatistic(v2rayConfig);
v2rayConfig.outbounds.RemoveAt(0);
var groupRet = await GenGroupOutbound(parentNode, v2rayConfig); var groupRet = await GenGroupOutbound(parentNode, v2rayConfig);
if (groupRet != 0) if (groupRet != 0)
@ -230,6 +228,10 @@ public partial class CoreConfigV2rayService(Config config)
return ret; return ret;
} }
await GenRouting(v2rayConfig);
await GenDns(null, v2rayConfig);
await GenStatistic(v2rayConfig);
ret.Success = true; ret.Success = true;
ret.Data = await ApplyFullConfigTemplate(v2rayConfig, true); ret.Data = await ApplyFullConfigTemplate(v2rayConfig, true);

View file

@ -4,32 +4,80 @@ public partial class CoreConfigV2rayService
{ {
private async Task<int> GenObservatory(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag) private async Task<int> GenObservatory(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag)
{ {
if (multipleLoad == EMultipleLoad.LeastPing) // Collect all existing subject selectors from both observatories
var subjectSelectors = new List<string>();
subjectSelectors.AddRange(v2rayConfig.burstObservatory?.subjectSelector ?? []);
subjectSelectors.AddRange(v2rayConfig.observatory?.subjectSelector ?? []);
// Case 1: exact match already exists -> nothing to do
if (subjectSelectors.Any(baseTagName.StartsWith))
return await Task.FromResult(0);
// Case 2: prefix match exists -> reuse it and move to the first position
var matched = subjectSelectors.FirstOrDefault(s => s.StartsWith(baseTagName));
if (matched is not null)
{ {
var observatory = new Observatory4Ray baseTagName = matched;
if (v2rayConfig.burstObservatory?.subjectSelector?.Contains(baseTagName) == true)
{ {
subjectSelector = [baseTagName], v2rayConfig.burstObservatory.subjectSelector.Remove(baseTagName);
probeUrl = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl, v2rayConfig.burstObservatory.subjectSelector.Insert(0, baseTagName);
probeInterval = "3m", }
enableConcurrency = true,
}; if (v2rayConfig.observatory?.subjectSelector?.Contains(baseTagName) == true)
v2rayConfig.observatory = observatory; {
v2rayConfig.observatory.subjectSelector.Remove(baseTagName);
v2rayConfig.observatory.subjectSelector.Insert(0, baseTagName);
}
return await Task.FromResult(0);
} }
else if (multipleLoad is EMultipleLoad.LeastLoad or EMultipleLoad.Fallback)
// Case 3: need to create or insert based on multipleLoad type
if (multipleLoad is EMultipleLoad.LeastLoad or EMultipleLoad.Fallback)
{ {
var burstObservatory = new BurstObservatory4Ray if (v2rayConfig.burstObservatory is null)
{ {
subjectSelector = [baseTagName], // Create new burst observatory with default ping config
pingConfig = new() v2rayConfig.burstObservatory = new BurstObservatory4Ray
{ {
destination = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl, subjectSelector = [baseTagName],
interval = "5m", pingConfig = new()
timeout = "30s", {
sampling = 2, destination = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
} interval = "5m",
}; timeout = "30s",
v2rayConfig.burstObservatory = burstObservatory; sampling = 2,
}
};
}
else
{
v2rayConfig.burstObservatory.subjectSelector ??= new();
v2rayConfig.burstObservatory.subjectSelector.Add(baseTagName);
}
} }
else if (multipleLoad is EMultipleLoad.LeastPing)
{
if (v2rayConfig.observatory is null)
{
// Create new observatory with default probe config
v2rayConfig.observatory = new Observatory4Ray
{
subjectSelector = [baseTagName],
probeUrl = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
probeInterval = "3m",
enableConcurrency = true,
};
}
else
{
v2rayConfig.observatory.subjectSelector ??= new();
v2rayConfig.observatory.subjectSelector.Add(baseTagName);
}
}
return await Task.FromResult(0); return await Task.FromResult(0);
} }

View file

@ -539,9 +539,11 @@ public partial class CoreConfigV2rayService
} }
//add balancers //add balancers
await GenObservatory(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); if (node.ConfigType == EConfigType.PolicyGroup)
await GenBalancer(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); {
await GenObservatory(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName);
await GenBalancer(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -797,6 +799,35 @@ public partial class CoreConfigV2rayService
for (var i = 0; i < nodes.Count; i++) for (var i = 0; i < nodes.Count; i++)
{ {
var node = nodes[i]; var node = nodes[i];
if (node == null)
continue;
if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
{
ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem);
if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty())
{
continue;
}
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)
{
continue;
}
var childBaseTagName = $"{baseTagName}-{i + 1}";
var ret = node.ConfigType switch
{
EConfigType.PolicyGroup =>
await GenOutboundsListWithChain(childProfiles, v2rayConfig, childBaseTagName),
EConfigType.ProxyChain =>
await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
_ => throw new NotImplementedException()
};
continue;
}
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
if (txtOutbound.IsNullOrEmpty()) if (txtOutbound.IsNullOrEmpty())
{ {

View file

@ -195,12 +195,12 @@ public class AddGroupServerViewModel : MyReactiveObject
var childIndexIds = new List<string>(); var childIndexIds = new List<string>();
foreach (var item in ChildItemsObs) foreach (var item in ChildItemsObs)
{ {
if (!item.IndexId.IsNullOrEmpty()) if (item.IndexId.IsNullOrEmpty())
{ {
childIndexIds.Add(item.IndexId); continue;
} }
childIndexIds.Add(item.IndexId);
} }
SelectedSource.Address = Utils.List2String(childIndexIds);
var profileGroup = ProfileGroupItemManager.Instance.GetOrCreateAndMarkDirty(SelectedSource.IndexId); var profileGroup = ProfileGroupItemManager.Instance.GetOrCreateAndMarkDirty(SelectedSource.IndexId);
profileGroup.ChildItems = Utils.List2String(childIndexIds); profileGroup.ChildItems = Utils.List2String(childIndexIds);
profileGroup.MultipleLoad = PolicyGroupType switch profileGroup.MultipleLoad = PolicyGroupType switch