From aab6d3d1368287d1cc4081dd5fcbdb2ec864d365 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Mon, 22 Sep 2025 17:15:00 +0800 Subject: [PATCH] Add helper function --- v2rayN/ServiceLib/Models/ProfileItem.cs | 45 +++++++++++++++++++ .../Singbox/SingboxOutboundService.cs | 41 +++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/v2rayN/ServiceLib/Models/ProfileItem.cs b/v2rayN/ServiceLib/Models/ProfileItem.cs index 45c8df8d..848c7a65 100644 --- a/v2rayN/ServiceLib/Models/ProfileItem.cs +++ b/v2rayN/ServiceLib/Models/ProfileItem.cs @@ -64,6 +64,51 @@ public class ProfileItem : ReactiveObject return Network.TrimEx(); } + public bool IsComplex() + { + return ConfigType is EConfigType.Custom or > EConfigType.Group; + } + + public bool IsValid() + { + if (IsComplex()) + return true; + + if (Address.IsNullOrEmpty() || Port is <= 0 or >= 65536) + return false; + + switch (ConfigType) + { + case EConfigType.VMess: + if (Id.IsNullOrEmpty() || !Utils.IsGuidByParse(Id)) + return false; + break; + + case EConfigType.VLESS: + if (Id.IsNullOrEmpty() || (!Utils.IsGuidByParse(Id) && Id.Length > 30)) + return false; + if (!Global.Flows.Contains(Flow)) + return false; + break; + + case EConfigType.Shadowsocks: + if (Id.IsNullOrEmpty()) + return false; + if (string.IsNullOrEmpty(Security) || !Global.SsSecuritiesInSingbox.Contains(Security)) + return false; + break; + } + + if ((ConfigType is EConfigType.VLESS or EConfigType.Trojan) + && StreamSecurity == Global.StreamSecurityReality + && PublicKey.IsNullOrEmpty()) + { + return false; + } + + return true; + } + #endregion function [PrimaryKey] diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 7bfdde9e..b8c58e75 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -204,6 +204,47 @@ public partial class CoreConfigSingboxService return await Task.FromResult(null); } + private async Task GenGroupOutbound(ProfileItem node, SingboxConfig singboxConfig, string baseTagName = Global.ProxyTag) + { + try + { + if (node.ConfigType is not (EConfigType.PolicyGroup or EConfigType.ProxyChain)) + { + return -1; + } + ProfileGroupItemManager.Instance.TryGet(node.IndexId, out var profileGroupItem); + if (profileGroupItem is null || profileGroupItem.ChildItems.IsNullOrEmpty()) + { + return -1; + } + var childProfiles = (await Task.WhenAll( + Utils.String2List(profileGroupItem.ChildItems) + .Where(p => !p.IsNullOrEmpty()) + .Select(AppManager.Instance.GetProfileItem) + )).Where(p => p != null && p.IsValid()).ToList(); + if (childProfiles.Count <= 0) + { + return -1; + } + switch (node.ConfigType) + { + case EConfigType.PolicyGroup: + await GenOutboundsListWithChain(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, baseTagName); + break; + case EConfigType.ProxyChain: + await GenChainOutboundsList(childProfiles, singboxConfig, baseTagName); + break; + default: + break; + } + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } + return await Task.FromResult(0); + } + private async Task GenOutboundMux(ProfileItem node, Outbound4Sbox outbound) { try