diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 1951543f..2c6428d6 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1257,35 +1257,7 @@ public static class ConfigHandler var tun2SocksAddress = node.Address; if (node.ConfigType > EConfigType.Group) { - static async Task> GetChildNodeAddressesAsync(string parentIndexId) - { - var childAddresses = new List(); - if (!ProfileGroupItemManager.Instance.TryGet(parentIndexId, out var groupItem) || groupItem.ChildItems.IsNullOrEmpty()) - return childAddresses; - - var childIds = Utils.String2List(groupItem.ChildItems); - - foreach (var childId in childIds) - { - var childNode = await AppManager.Instance.GetProfileItem(childId); - if (childNode == null) - continue; - - if (!childNode.IsComplex()) - { - childAddresses.Add(childNode.Address); - } - else if (childNode.ConfigType > EConfigType.Group) - { - var subAddresses = await GetChildNodeAddressesAsync(childNode.IndexId); - childAddresses.AddRange(subAddresses); - } - } - - return childAddresses; - } - - var lstAddresses = await GetChildNodeAddressesAsync(node.IndexId); + var lstAddresses = (await ProfileGroupItemManager.GetAllChildDomainAddresses(node.IndexId)).ToList(); if (lstAddresses.Count > 0) { tun2SocksAddress = Utils.List2String(lstAddresses); diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index f131adf8..a41ceae6 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -100,7 +100,6 @@ public sealed class AppManager await ConfigHandler.SaveConfig(_config); await ProfileExManager.Instance.SaveTo(); - await ProfileGroupItemManager.Instance.SaveTo(); await StatisticsManager.Instance.SaveTo(); await CoreManager.Instance.CoreStop(); StatisticsManager.Instance.Close(); diff --git a/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs b/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs index 4812a0d2..447e7433 100644 --- a/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs +++ b/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs @@ -164,4 +164,113 @@ public class ProfileGroupItemManager Logging.SaveLog(_tag, ex); } } + + #region Helper + + public static bool HasCycle(string? indexId) + { + return HasCycle(indexId, new HashSet(), new HashSet()); + } + + public static bool HasCycle(string? indexId, HashSet visited, HashSet stack) + { + if (indexId.IsNullOrEmpty()) + return false; + + if (stack.Contains(indexId)) + return true; + + if (visited.Contains(indexId)) + return false; + + visited.Add(indexId); + stack.Add(indexId); + + Instance.TryGet(indexId, out var groupItem); + + if (groupItem == null || groupItem.ChildItems.IsNullOrEmpty()) + { + return false; + } + + var childIds = Utils.String2List(groupItem.ChildItems) + .Where(p => !string.IsNullOrEmpty(p)) + .ToList(); + + foreach (var child in childIds) + { + if (HasCycle(child, visited, stack)) + { + return true; + } + } + + stack.Remove(indexId); + return false; + } + + public static async Task<(List Items, ProfileGroupItem? Group)> GetChildProfileItems(string? indexId) + { + Instance.TryGet(indexId, out var profileGroupItem); + if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty()) + { + return (new List(), profileGroupItem); + } + var items = await GetChildProfileItems(profileGroupItem); + return (items, profileGroupItem); + } + + public static async Task> GetChildProfileItems(ProfileGroupItem? group) + { + if (group == null || group.ChildItems.IsNullOrEmpty()) + { + return new(); + } + var childProfiles = (await Task.WhenAll( + Utils.String2List(group.ChildItems) + .Where(p => !p.IsNullOrEmpty()) + .Select(AppManager.Instance.GetProfileItem) + )) + .Where(p => + p != null && + p.IsValid() && + p.ConfigType != EConfigType.Custom + ) + .ToList(); + return childProfiles; + } + + public static async Task> GetAllChildDomainAddresses(string parentIndexId) + { + // include grand children + var childAddresses = new HashSet(); + if (!Instance.TryGet(parentIndexId, out var groupItem) || groupItem.ChildItems.IsNullOrEmpty()) + return childAddresses; + + var childIds = Utils.String2List(groupItem.ChildItems); + + foreach (var childId in childIds) + { + var childNode = await AppManager.Instance.GetProfileItem(childId); + if (childNode == null) + continue; + + if (!childNode.IsComplex()) + { + childAddresses.Add(childNode.Address); + } + else if (childNode.ConfigType > EConfigType.Group) + { + var subAddresses = await GetAllChildDomainAddresses(childNode.IndexId); + foreach (var addr in subAddresses) + { + childAddresses.Add(addr); + } + } + } + + return childAddresses; + } + + #endregion Helper } diff --git a/v2rayN/ServiceLib/Manager/TaskManager.cs b/v2rayN/ServiceLib/Manager/TaskManager.cs index c626e1b7..dfbd242d 100644 --- a/v2rayN/ServiceLib/Manager/TaskManager.cs +++ b/v2rayN/ServiceLib/Manager/TaskManager.cs @@ -35,7 +35,6 @@ public class TaskManager await ConfigHandler.SaveConfig(_config); await ProfileExManager.Instance.SaveTo(); - await ProfileGroupItemManager.Instance.SaveTo(); } //Execute once 1 hour diff --git a/v2rayN/ServiceLib/Models/ProfileGroupItem.cs b/v2rayN/ServiceLib/Models/ProfileGroupItem.cs index bb1615ae..6fbe1d9c 100644 --- a/v2rayN/ServiceLib/Models/ProfileGroupItem.cs +++ b/v2rayN/ServiceLib/Models/ProfileGroupItem.cs @@ -11,48 +11,4 @@ public class ProfileGroupItem public string ChildItems { get; set; } public EMultipleLoad MultipleLoad { get; set; } = EMultipleLoad.LeastPing; - - public bool HasCycle() - { - return HasCycle(new HashSet(), new HashSet()); - } - - public bool HasCycle(HashSet visited, HashSet stack) - { - if (string.IsNullOrEmpty(ParentIndexId)) - return false; - - if (stack.Contains(ParentIndexId)) - return true; - - if (visited.Contains(ParentIndexId)) - return false; - - visited.Add(ParentIndexId); - stack.Add(ParentIndexId); - - if (string.IsNullOrEmpty(ChildItems)) - { - return false; - } - - var childIds = Utils.String2List(ChildItems) - .Where(p => !string.IsNullOrEmpty(p)) - .ToList(); - - var childProfiles = childIds.Select(ProfileGroupItemManager.Instance.GetOrDefault)//这里是内存访问 - .Where(p => p != null) - .ToList(); - - foreach (var child in childProfiles) - { - if (child.HasCycle(visited, stack)) - { - return true; - } - } - - stack.Remove(ParentIndexId); - return false; - } } diff --git a/v2rayN/ServiceLib/Models/ProfileItem.cs b/v2rayN/ServiceLib/Models/ProfileItem.cs index 8f883535..da34600b 100644 --- a/v2rayN/ServiceLib/Models/ProfileItem.cs +++ b/v2rayN/ServiceLib/Models/ProfileItem.cs @@ -109,42 +109,6 @@ public class ProfileItem : ReactiveObject return true; } - public async Task HasCycle(HashSet visited, HashSet stack) - { - if (ConfigType < EConfigType.Group) - return false; - - if (stack.Contains(IndexId)) - return true; - - if (visited.Contains(IndexId)) - return false; - - visited.Add(IndexId); - stack.Add(IndexId); - - if (ProfileGroupItemManager.Instance.TryGet(IndexId, out var group) - && !group.ChildItems.IsNullOrEmpty()) - { - var childProfiles = (await Task.WhenAll( - Utils.String2List(group.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )) - .Where(p => p != null) - .ToList(); - - foreach (var child in childProfiles) - { - if (await child.HasCycle(visited, stack)) - return true; - } - } - - stack.Remove(IndexId); - return false; - } - #endregion function [PrimaryKey] diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index e114b433..08005725 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -212,33 +212,13 @@ public partial class CoreConfigSingboxService { return -1; } - ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem); - if (profileGroupItem is null || profileGroupItem.ChildItems.IsNullOrEmpty()) - { - return -1; - } - - var hasCycle = await node.HasCycle(new HashSet(), new HashSet()); + var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); if (hasCycle) { return -1; } - // remove custom nodes - // remove group nodes for proxy chain - var childProfiles = (await Task.WhenAll( - Utils.String2List(profileGroupItem.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )) - .Where(p => - p != null - && p.IsValid() - && p.ConfigType != EConfigType.Custom - && (node.ConfigType == EConfigType.PolicyGroup || p.ConfigType < EConfigType.Group) - ) - .ToList(); - + var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); if (childProfiles.Count <= 0) { return -1; @@ -514,16 +494,13 @@ public partial class CoreConfigSingboxService if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain) { - ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem); - if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty()) + var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); + if (hasCycle) { - continue; + return -1; } - var childProfiles = (await Task.WhenAll( - Utils.String2List(profileGroupItem.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )).Where(p => p != null).ToList(); + + var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); if (childProfiles.Count <= 0) { continue; @@ -698,16 +675,13 @@ public partial class CoreConfigSingboxService continue; if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain) { - ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem); - if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty()) + var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); + if (hasCycle) { - continue; + return -1; } - var childProfiles = (await Task.WhenAll( - Utils.String2List(profileGroupItem.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )).Where(p => p != null).ToList(); + + var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); if (childProfiles.Count <= 0) { continue; diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 2fbf42b5..4c3a5148 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -1,5 +1,3 @@ -using ServiceLib.Models; - namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService @@ -490,34 +488,13 @@ public partial class CoreConfigV2rayService { return -1; } - ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem); - if (profileGroupItem is null || profileGroupItem.ChildItems.IsNullOrEmpty()) - { - return -1; - } - - var hasCycle = profileGroupItem.HasCycle(); - //var hasCycle = await node.HasCycle(new HashSet(), new HashSet()); + var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); if (hasCycle) { return -1; } - // remove custom nodes - // remove group nodes for proxy chain - var childProfiles = (await Task.WhenAll( - Utils.String2List(profileGroupItem.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )) - .Where(p => - p != null && - p.IsValid() && - p.ConfigType != EConfigType.Custom && - (node.ConfigType == EConfigType.PolicyGroup || p.ConfigType < EConfigType.Group) - ) - .ToList(); - + var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); if (childProfiles.Count <= 0) { return -1; @@ -654,16 +631,13 @@ public partial class CoreConfigV2rayService if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain) { - ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem); - if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty()) + var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); + if (hasCycle) { - continue; + return -1; } - var childProfiles = (await Task.WhenAll( - Utils.String2List(profileGroupItem.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )).Where(p => p != null).ToList(); + + var (childProfiles, _) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); if (childProfiles.Count <= 0) { continue; @@ -814,16 +788,13 @@ public partial class CoreConfigV2rayService continue; if (node.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain) { - ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem); - if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty()) + var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); + if (hasCycle) { - continue; + return -1; } - var childProfiles = (await Task.WhenAll( - Utils.String2List(profileGroupItem.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )).Where(p => p != null).ToList(); + + var (childProfiles, _) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); if (childProfiles.Count <= 0) { continue;