From dc3200f0a62afeeb835cc5d88ed1a5aa4ba66630 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 28 Mar 2025 21:08:51 +0800 Subject: [PATCH] add xray core leastPing support --- v2rayN/ServiceLib/Enums/EMultipleLoad.cs | 10 ++++ v2rayN/ServiceLib/Handler/ConfigHandler.cs | 25 +++++++- .../ServiceLib/Handler/CoreConfigHandler.cs | 21 +++++-- v2rayN/ServiceLib/Models/V2rayConfig.cs | 42 ++++++++++++++ .../CoreConfig/CoreConfigV2rayService.cs | 58 ++++++++++++++++--- .../ViewModels/ProfilesViewModel.cs | 8 +-- 6 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 v2rayN/ServiceLib/Enums/EMultipleLoad.cs diff --git a/v2rayN/ServiceLib/Enums/EMultipleLoad.cs b/v2rayN/ServiceLib/Enums/EMultipleLoad.cs new file mode 100644 index 00000000..a5541f91 --- /dev/null +++ b/v2rayN/ServiceLib/Enums/EMultipleLoad.cs @@ -0,0 +1,10 @@ +namespace ServiceLib.Enums +{ + public enum EMultipleLoad + { + Random, + RoundRobin, + LeastPing, + LeastLoad + } +} diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index f3596c9f..58942f4b 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1005,12 +1005,33 @@ namespace ServiceLib.Handler return 0; } - public static async Task AddCustomServer4Multiple(Config config, List selecteds, ECoreType coreType) + public static async Task AddCustomServer4Multiple(Config config, List selecteds, EMultipleLoad multipleLoad) { var indexId = Utils.GetMd5(Global.CoreMultipleLoadConfigFileName); var configPath = Utils.GetConfigPath(Global.CoreMultipleLoadConfigFileName); - var result = await CoreConfigHandler.GenerateClientMultipleLoadConfig(config, configPath, selecteds, coreType); + var coreType = AppHandler.Instance.Config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == EConfigType.Custom)?.CoreType ?? ECoreType.Xray; + if (multipleLoad == EMultipleLoad.LeastPing && coreType == ECoreType.Xray) + { + var support = selecteds.All(it => it.ConfigType is + EConfigType.VMess or + EConfigType.VLESS or + EConfigType.Trojan or + EConfigType.Shadowsocks or + EConfigType.SOCKS or + EConfigType.HTTP or + EConfigType.WireGuard); + if (!support) + { + coreType = ECoreType.sing_box; + } + } + else if (multipleLoad == EMultipleLoad.RoundRobin) + { + coreType = ECoreType.Xray; + } + + var result = await CoreConfigHandler.GenerateClientMultipleLoadConfig(config, configPath, selecteds, coreType, multipleLoad); if (result.Success != true) { return result; diff --git a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs index 0d9b2a0e..d9fddb58 100644 --- a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs @@ -1,3 +1,7 @@ +using DynamicData; +using ServiceLib.Enums; +using ServiceLib.Models; + namespace ServiceLib.Handler { /// @@ -133,16 +137,23 @@ namespace ServiceLib.Handler return result; } - public static async Task GenerateClientMultipleLoadConfig(Config config, string fileName, List selecteds, ECoreType coreType) + public static async Task GenerateClientMultipleLoadConfig(Config config, string fileName, List selecteds, ECoreType coreType, EMultipleLoad multipleLoad) { var result = new RetResult(); - if (coreType == ECoreType.sing_box) + if (multipleLoad == EMultipleLoad.RoundRobin) { - result = await new CoreConfigSingboxService(config).GenerateClientMultipleLoadConfig(selecteds); + result = await new CoreConfigV2rayService(config).GenerateClientMultipleRoundRobinConfig(selecteds); } - else if (coreType == ECoreType.Xray) + else { - result = await new CoreConfigV2rayService(config).GenerateClientMultipleLoadConfig(selecteds); + if (coreType == ECoreType.sing_box) + { + result = await new CoreConfigSingboxService(config).GenerateClientMultipleLoadConfig(selecteds); + } + else if (coreType == ECoreType.Xray) + { + result = await new CoreConfigV2rayService(config).GenerateClientMultipleLeastPingConfig(selecteds); + } } if (result.Success != true) diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs index e3fa0fd3..1f441bb8 100644 --- a/v2rayN/ServiceLib/Models/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/V2rayConfig.cs @@ -12,6 +12,8 @@ namespace ServiceLib.Models public Metrics4Ray? metrics { get; set; } public Policy4Ray? policy { get; set; } public Stats4Ray? stats { get; set; } + public Observatory4Ray? observatory { get; set; } + public BurstObservatory4Ray? burstObservatory { get; set; } public string? remarks { get; set; } } @@ -232,6 +234,46 @@ namespace ServiceLib.Models public class BalancersStrategy4Ray { public string? type { get; set; } + public BalancersStrategySettings4Ray? settings { get; set; } + } + + public class BalancersStrategySettings4Ray + { + public int? expected { get; set; } + public string? maxRTT { get; set; } + public float? tolerance { get; set; } + public List? baselines { get; set; } + public List? costs { get; set; } + } + + public class BalancersStrategySettingsCosts4Ray + { + public bool? regexp { get; set; } + public string? match { get; set; } + public float? value { get; set; } + } + + public class Observatory4Ray + { + public List? subjectSelector { get; set; } + public string? probeUrl { get; set; } + public string? probeInterval { get; set; } + public bool? enableConcurrency { get; set; } + } + + public class BurstObservatory4Ray + { + public List? subjectSelector { get; set; } + public BurstObservatoryPingConfig4Ray? pingConfig { get; set; } + } + + public class BurstObservatoryPingConfig4Ray + { + public string? destination { get; set; } + public string? connectivity { get; set; } + public string? interval { get; set; } + public int? sampling { get; set; } + public string? timeout { get; set; } } public class StreamSettings4Ray diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs index 4077ea8c..f41da883 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs @@ -77,7 +77,17 @@ namespace ServiceLib.Services.CoreConfig } } - public async Task GenerateClientMultipleLoadConfig(List selecteds) + public async Task GenerateClientMultipleRoundRobinConfig(List selecteds) + { + return await GenerateClientMultipleLoadConfig(selecteds, EMultipleLoad.RoundRobin); + } + + public async Task GenerateClientMultipleLeastPingConfig(List selecteds) + { + return await GenerateClientMultipleLoadConfig(selecteds, EMultipleLoad.LeastPing); + } + + public async Task GenerateClientMultipleLoadConfig(List selecteds, EMultipleLoad multipleLoad) { var ret = new RetResult(); @@ -164,13 +174,16 @@ namespace ServiceLib.Services.CoreConfig } //add balancers - var balancer = new BalancersItem4Ray + if (multipleLoad == EMultipleLoad.RoundRobin) { - selector = [Global.ProxyTag], - strategy = new() { type = "roundRobin" }, - tag = $"{Global.ProxyTag}-round", - }; - v2rayConfig.routing.balancers = [balancer]; + await GenRoundRobinBalancer(v2rayConfig); + } + else + { + await GenLeastPingBalancer(v2rayConfig); + } + + var balancer = v2rayConfig.routing.balancers.First(); //add rule var rules = v2rayConfig.routing.rules.Where(t => t.outboundTag == Global.ProxyTag).ToList(); @@ -1316,6 +1329,37 @@ namespace ServiceLib.Services.CoreConfig return 0; } + private async Task GenRoundRobinBalancer(V2rayConfig v2rayConfig) + { + var balancer = new BalancersItem4Ray + { + selector = [Global.ProxyTag], + strategy = new() { type = "roundRobin" }, + tag = $"{Global.ProxyTag}-round", + }; + v2rayConfig.routing.balancers = [balancer]; + return await Task.FromResult(0); + } + + private async Task GenLeastPingBalancer(V2rayConfig v2rayConfig) + { + var observatory = new Observatory4Ray + { + subjectSelector = [Global.ProxyTag], + probeUrl = AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl, + probeInterval = "3m" + }; + var balancer = new BalancersItem4Ray + { + selector = [Global.ProxyTag], + strategy = new() { type = "leastPing" }, + tag = $"{Global.ProxyTag}-round", + }; + v2rayConfig.routing.balancers = [balancer]; + v2rayConfig.observatory = observatory; + return await Task.FromResult(0); + } + #endregion private gen function } } diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index d4032e98..6688cd9b 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -152,11 +152,11 @@ namespace ServiceLib.ViewModels }, canEditRemove); SetDefaultMultipleServerCmd = ReactiveCommand.CreateFromTask(async () => { - await SetDefaultMultipleServer(ECoreType.sing_box); + await SetDefaultMultipleServer(EMultipleLoad.LeastPing); }, canEditRemove); SetDefaultLoadBalanceServerCmd = ReactiveCommand.CreateFromTask(async () => { - await SetDefaultMultipleServer(ECoreType.Xray); + await SetDefaultMultipleServer(EMultipleLoad.RoundRobin); }, canEditRemove); //servers move @@ -621,7 +621,7 @@ namespace ServiceLib.ViewModels await _updateView?.Invoke(EViewAction.ShareServer, url); } - private async Task SetDefaultMultipleServer(ECoreType coreType) + private async Task SetDefaultMultipleServer(EMultipleLoad multipleLoad) { var lstSelected = await GetProfileItems(true); if (lstSelected == null) @@ -629,7 +629,7 @@ namespace ServiceLib.ViewModels return; } - var ret = await ConfigHandler.AddCustomServer4Multiple(_config, lstSelected, coreType); + var ret = await ConfigHandler.AddCustomServer4Multiple(_config, lstSelected, multipleLoad); if (ret.Success != true) { NoticeHandler.Instance.Enqueue(ResUI.OperationFailed);