From ef09be7a26bc5431238a56e903f7c4dc83c4877d Mon Sep 17 00:00:00 2001 From: DHR60 Date: Tue, 30 Sep 2025 19:40:34 +0800 Subject: [PATCH] Fix --- v2rayN/ServiceLib/Handler/ConfigHandler.cs | 9 +- .../Singbox/CoreConfigSingboxService.cs | 10 +-- .../Singbox/SingboxOutboundService.cs | 33 +++++++ .../V2ray/CoreConfigV2rayService.cs | 18 ++-- .../CoreConfig/V2ray/V2rayBalancerService.cs | 86 +++++++++++++++---- .../CoreConfig/V2ray/V2rayOutboundService.cs | 37 +++++++- .../ViewModels/AddGroupServerViewModel.cs | 6 +- 7 files changed, 157 insertions(+), 42 deletions(-) diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 81b0a9ff..1951543f 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1087,6 +1087,8 @@ public static class ConfigHandler profileItem.IndexId = Utils.GetGuid(false); maxSort = ProfileExManager.Instance.GetMaxSort(); } + var groupType = profileItem.ConfigType == EConfigType.ProxyChain ? EConfigType.ProxyChain.ToString() : profileGroupItem.MultipleLoad.ToString(); + profileItem.Address = $"{profileItem.CoreType}-{groupType}"; if (maxSort > 0) { ProfileExManager.Instance.SetSort(profileItem.IndexId, maxSort + 1); @@ -1194,10 +1196,10 @@ public static class ConfigHandler var indexId = Utils.GetGuid(false); 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) { - remark = multipleLoad switch + remark += multipleLoad switch { EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerXrayLeastPing, EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerXrayFallback, @@ -1209,7 +1211,7 @@ public static class ConfigHandler } else if (coreType == ECoreType.sing_box) { - remark = multipleLoad switch + remark += multipleLoad switch { EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerSingBoxLeastPing, EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerSingBoxFallback, @@ -1222,7 +1224,6 @@ public static class ConfigHandler CoreType = coreType, ConfigType = EConfigType.PolicyGroup, Remarks = remark, - Address = childProfileIndexId, }; if (!subId.IsNullOrEmpty()) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs index 757ad3a3..fd77480a 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs @@ -363,8 +363,6 @@ public partial class CoreConfigSingboxService(Config config) await GenLog(singboxConfig); await GenInbounds(singboxConfig); - await GenRouting(singboxConfig); - await GenExperimental(singboxConfig); var groupRet = await GenGroupOutbound(parentNode, singboxConfig); if (groupRet != 0) @@ -373,6 +371,8 @@ public partial class CoreConfigSingboxService(Config config) return ret; } + await GenRouting(singboxConfig); + await GenExperimental(singboxConfig); await GenDns(null, singboxConfig); await ConvertGeo2Ruleset(singboxConfig); @@ -416,12 +416,10 @@ public partial class CoreConfigSingboxService(Config config) ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; } + singboxConfig.outbounds.RemoveAt(0); await GenLog(singboxConfig); await GenInbounds(singboxConfig); - await GenRouting(singboxConfig); - await GenExperimental(singboxConfig); - singboxConfig.outbounds.RemoveAt(0); var groupRet = await GenGroupOutbound(parentNode, singboxConfig); if (groupRet != 0) @@ -430,6 +428,8 @@ public partial class CoreConfigSingboxService(Config config) return ret; } + await GenRouting(singboxConfig); + await GenExperimental(singboxConfig); await GenDns(null, singboxConfig); await ConvertGeo2Ruleset(singboxConfig); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 8bc93e71..77191b86 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -694,6 +694,39 @@ public partial class CoreConfigSingboxService for (var i = 0; i < nodes.Count; 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); if (server is null) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs index 1dd1c0ef..37c55bca 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs @@ -114,9 +114,6 @@ public partial class CoreConfigV2rayService(Config config) await GenLog(v2rayConfig); await GenInbounds(v2rayConfig); - await GenRouting(v2rayConfig); - await GenDns(null, v2rayConfig); - await GenStatistic(v2rayConfig); var groupRet = await GenGroupOutbound(parentNode, v2rayConfig); if (groupRet != 0) @@ -125,11 +122,15 @@ public partial class CoreConfigV2rayService(Config config) return ret; } + await GenRouting(v2rayConfig); + await GenDns(null, v2rayConfig); + await GenStatistic(v2rayConfig); + var defaultBalancerTag = $"{Global.ProxyTag}{Global.BalancerTagSuffix}"; //add rule var rules = v2rayConfig.routing.rules; - if (rules?.Count > 0) + if (rules?.Count > 0 && ((v2rayConfig.routing.balancers?.Count ?? 0) > 0)) { var balancerTagSet = v2rayConfig.routing.balancers .Select(b => b.tag) @@ -215,13 +216,10 @@ public partial class CoreConfigV2rayService(Config config) ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; } + v2rayConfig.outbounds.RemoveAt(0); await GenLog(v2rayConfig); await GenInbounds(v2rayConfig); - await GenRouting(v2rayConfig); - await GenDns(null, v2rayConfig); - await GenStatistic(v2rayConfig); - v2rayConfig.outbounds.RemoveAt(0); var groupRet = await GenGroupOutbound(parentNode, v2rayConfig); if (groupRet != 0) @@ -230,6 +228,10 @@ public partial class CoreConfigV2rayService(Config config) return ret; } + await GenRouting(v2rayConfig); + await GenDns(null, v2rayConfig); + await GenStatistic(v2rayConfig); + ret.Success = true; ret.Data = await ApplyFullConfigTemplate(v2rayConfig); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs index 028782e9..660cc700 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs @@ -4,32 +4,80 @@ public partial class CoreConfigV2rayService { private async Task 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(); + 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], - probeUrl = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl, - probeInterval = "3m", - enableConcurrency = true, - }; - v2rayConfig.observatory = observatory; + v2rayConfig.burstObservatory.subjectSelector.Remove(baseTagName); + v2rayConfig.burstObservatory.subjectSelector.Insert(0, baseTagName); + } + + if (v2rayConfig.observatory?.subjectSelector?.Contains(baseTagName) == true) + { + 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], - pingConfig = new() + // Create new burst observatory with default ping config + v2rayConfig.burstObservatory = new BurstObservatory4Ray { - destination = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl, - interval = "5m", - timeout = "30s", - sampling = 2, - } - }; - v2rayConfig.burstObservatory = burstObservatory; + subjectSelector = [baseTagName], + pingConfig = new() + { + destination = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl, + interval = "5m", + timeout = "30s", + 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); } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 3d6597ae..195c0669 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -539,9 +539,11 @@ public partial class CoreConfigV2rayService } //add balancers - await GenObservatory(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); - await GenBalancer(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); - + if (node.ConfigType == EConfigType.PolicyGroup) + { + await GenObservatory(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); + await GenBalancer(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); + } } catch (Exception ex) { @@ -797,6 +799,35 @@ public partial class CoreConfigV2rayService for (var i = 0; i < nodes.Count; 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); if (txtOutbound.IsNullOrEmpty()) { diff --git a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs index 4a6af40e..beda67d0 100644 --- a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs @@ -195,12 +195,12 @@ public class AddGroupServerViewModel : MyReactiveObject var childIndexIds = new List(); 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); profileGroup.ChildItems = Utils.List2String(childIndexIds); profileGroup.MultipleLoad = PolicyGroupType switch