From 1198ec0f74e7815fefbe78b66efa1515adc94f5a Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:46:51 +0800 Subject: [PATCH] Improved and optimized speedtest When testing server speed, start the Core for each server and generate the same configuration files as when using the server. Add a folder binConfigs to store temporary configuration files for Core. --- v2rayN/ServiceLib/Common/ProcUtils.cs | 42 +- v2rayN/ServiceLib/Common/Utils.cs | 38 +- v2rayN/ServiceLib/Global.cs | 2 +- v2rayN/ServiceLib/Handler/AppHandler.cs | 5 +- .../ServiceLib/Handler/CoreConfigHandler.cs | 28 +- v2rayN/ServiceLib/Handler/CoreHandler.cs | 42 +- v2rayN/ServiceLib/Models/ServerTestItem.cs | 6 +- .../CoreConfig/CoreConfigSingboxService.cs | 62 ++- .../CoreConfig/CoreConfigV2rayService.cs | 58 +++ .../ServiceLib/Services/SpeedtestService.cs | 379 +++++++----------- .../ViewModels/BackupAndRestoreViewModel.cs | 2 +- 11 files changed, 405 insertions(+), 259 deletions(-) diff --git a/v2rayN/ServiceLib/Common/ProcUtils.cs b/v2rayN/ServiceLib/Common/ProcUtils.cs index f9cc8ccd..ded6f4d8 100644 --- a/v2rayN/ServiceLib/Common/ProcUtils.cs +++ b/v2rayN/ServiceLib/Common/ProcUtils.cs @@ -86,17 +86,43 @@ public static class ProcUtils GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName); try - { proc?.Kill(true); } - catch (Exception ex) { Logging.SaveLog(_tag, ex); } + { + if (Utils.IsNonWindows()) + { + proc?.Kill(true); + } + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } + try - { proc?.Kill(); } - catch (Exception ex) { Logging.SaveLog(_tag, ex); } + { + proc?.Kill(); + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } + try - { proc?.Close(); } - catch (Exception ex) { Logging.SaveLog(_tag, ex); } + { + proc?.Close(); + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } + try - { proc?.Dispose(); } - catch (Exception ex) { Logging.SaveLog(_tag, ex); } + { + proc?.Dispose(); + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } await Task.Delay(300); await ProcessKillByKeyInfo(review, procId, fileName, processName); diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index f4b60f3c..15f111d4 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -433,10 +433,22 @@ namespace ServiceLib.Common { try { - var ipProperties = IPGlobalProperties.GetIPGlobalProperties(); - var ipEndPoints = ipProperties.GetActiveTcpListeners(); - //var lstIpEndPoints = new List(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); - return ipEndPoints.Any(endPoint => endPoint.Port == port); + List lstIpEndPoints = new(); + List lstTcpConns = new(); + + lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); + lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners()); + lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()); + + if (lstIpEndPoints?.FindIndex(it => it.Port == port) >= 0) + { + return true; + } + + if (lstTcpConns?.FindIndex(it => it.LocalEndPoint.Port == port) >= 0) + { + return true; + } } catch (Exception ex) { @@ -786,6 +798,24 @@ namespace ServiceLib.Common } } + public static string GetBinConfigPath(string filename = "") + { + var tempPath = Path.Combine(StartupPath(), "binConfigs"); + if (!Directory.Exists(tempPath)) + { + Directory.CreateDirectory(tempPath); + } + + if (Utils.IsNullOrEmpty(filename)) + { + return tempPath; + } + else + { + return Path.Combine(tempPath, filename); + } + } + #endregion TempPath #region Platform diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index eb4da4ab..0e874ae0 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -16,7 +16,7 @@ namespace ServiceLib public const string ConfigFileName = "guiNConfig.json"; public const string CoreConfigFileName = "config.json"; public const string CorePreConfigFileName = "configPre.json"; - public const string CoreSpeedtestConfigFileName = "configSpeedtest.json"; + public const string CoreSpeedtestConfigFileName = "configTest{0}.json"; public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json"; public const string ClashMixinConfigFileName = "Mixin.yaml"; diff --git a/v2rayN/ServiceLib/Handler/AppHandler.cs b/v2rayN/ServiceLib/Handler/AppHandler.cs index 72a080e8..cf0f73af 100644 --- a/v2rayN/ServiceLib/Handler/AppHandler.cs +++ b/v2rayN/ServiceLib/Handler/AppHandler.cs @@ -1,4 +1,4 @@ -namespace ServiceLib.Handler +namespace ServiceLib.Handler { public sealed class AppHandler { @@ -98,6 +98,7 @@ { FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1)); FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1)); + FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1)); }); } @@ -252,4 +253,4 @@ #endregion Core Type } -} \ No newline at end of file +} diff --git a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs index 8713b8dd..11982882 100644 --- a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs @@ -1,4 +1,4 @@ -namespace ServiceLib.Handler +namespace ServiceLib.Handler { /// /// Core configuration file processing class @@ -109,6 +109,30 @@ return result; } + public static async Task GenerateClientSpeedtestConfig(Config config, ProfileItem node, ServerTestItem testItem, string fileName) + { + var result = new RetResult(); + var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest); + var port = Utils.GetFreePort(initPort + testItem.QueueNum); + testItem.Port = port; + + if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box) + { + result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(node, port); + } + else + { + result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(node, port); + } + if (result.Success != true) + { + return result; + } + + await File.WriteAllTextAsync(fileName, result.Data.ToString()); + return result; + } + public static async Task GenerateClientMultipleLoadConfig(Config config, string fileName, List selecteds, ECoreType coreType) { var result = new RetResult(); @@ -129,4 +153,4 @@ return result; } } -} \ No newline at end of file +} diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs index dbd93081..08615879 100644 --- a/v2rayN/ServiceLib/Handler/CoreHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs @@ -70,7 +70,7 @@ namespace ServiceLib.Handler return; } - var fileName = Utils.GetConfigPath(Global.CoreConfigFileName); + var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName); var result = await CoreConfigHandler.GenerateClientConfig(node, fileName); if (result.Success != true) { @@ -101,7 +101,8 @@ namespace ServiceLib.Handler public async Task LoadCoreConfigSpeedtest(List selecteds) { var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray; - var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName); + var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false)); + var configPath = Utils.GetBinConfigPath(fileName); var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType); UpdateFunc(false, result.Msg); if (result.Success != true) @@ -113,7 +114,34 @@ namespace ServiceLib.Handler UpdateFunc(false, configPath); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); - var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false); + var proc = await RunProcess(coreInfo, fileName, true, false); + if (proc is null) + { + return -1; + } + + return proc.Id; + } + + public async Task LoadCoreConfigSpeedtest(ServerTestItem testItem) + { + var node = await AppHandler.Instance.GetProfileItem(testItem.IndexId); + if (node is null) + { + return -1; + } + + var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false)); + var configPath = Utils.GetBinConfigPath(fileName); + var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, node, testItem, configPath); + if (result.Success != true) + { + return -1; + } + + var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType); + var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); + var proc = await CoreHandler.Instance.RunProcess(coreInfo, fileName, true, false); if (proc is null) { return -1; @@ -175,7 +203,7 @@ namespace ServiceLib.Handler if (itemSocks != null) { var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box; - var fileName = Utils.GetConfigPath(Global.CorePreConfigFileName); + var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName); var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName); if (result.Success) { @@ -225,8 +253,8 @@ namespace ServiceLib.Handler StartInfo = new() { FileName = fileName, - Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetConfigPath(configPath) : configPath), - WorkingDirectory = Utils.GetConfigPath(), + Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath) : configPath), + WorkingDirectory = Utils.GetBinConfigPath(), UseShellExecute = false, RedirectStandardOutput = displayLog, RedirectStandardError = displayLog, @@ -298,7 +326,7 @@ namespace ServiceLib.Handler private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath) { - var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}"; + var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}"; var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh"); proc.StartInfo.FileName = shFilePath; diff --git a/v2rayN/ServiceLib/Models/ServerTestItem.cs b/v2rayN/ServiceLib/Models/ServerTestItem.cs index 1a6352f6..99e45d2b 100644 --- a/v2rayN/ServiceLib/Models/ServerTestItem.cs +++ b/v2rayN/ServiceLib/Models/ServerTestItem.cs @@ -1,4 +1,4 @@ -namespace ServiceLib.Models +namespace ServiceLib.Models { [Serializable] public class ServerTestItem @@ -8,6 +8,6 @@ public int Port { get; set; } public EConfigType ConfigType { get; set; } public bool AllowTest { get; set; } - public int Delay { get; set; } + public int QueueNum { get; set; } } -} \ No newline at end of file +} diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 3b044f57..cd11ecd1 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -242,6 +242,66 @@ namespace ServiceLib.Services.CoreConfig } } + public async Task GenerateClientSpeedtestConfig(ProfileItem node, int port) + { + var ret = new RetResult(); + try + { + if (node is not { Port: > 0 }) + { + ret.Msg = ResUI.CheckServerSettings; + return ret; + } + if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp)) + { + ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; + return ret; + } + + ret.Msg = ResUI.InitialConfiguration; + + var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient); + if (Utils.IsNullOrEmpty(result)) + { + ret.Msg = ResUI.FailedGetDefaultConfiguration; + return ret; + } + + var singboxConfig = JsonUtils.Deserialize(result); + if (singboxConfig == null) + { + ret.Msg = ResUI.FailedGenDefaultConfiguration; + return ret; + } + + await GenLog(singboxConfig); + await GenOutbound(node, singboxConfig.outbounds.First()); + await GenMoreOutbounds(node, singboxConfig); + await GenDnsDomains(null, singboxConfig, null); + + singboxConfig.route.rules.Clear(); + singboxConfig.inbounds.Clear(); + singboxConfig.inbounds.Add(new() + { + tag = $"{EInboundProtocol.mixed}{port}", + listen = Global.Loopback, + listen_port = port, + type = EInboundProtocol.mixed.ToString(), + }); + + ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); + ret.Success = true; + ret.Data = JsonUtils.Serialize(singboxConfig); + return ret; + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + ret.Msg = ResUI.FailedGenDefaultConfiguration; + return ret; + } + } + public async Task GenerateClientMultipleLoadConfig(List selecteds) { var ret = new RetResult(); @@ -1264,7 +1324,7 @@ namespace ServiceLib.Services.CoreConfig singboxConfig.experimental.cache_file = new CacheFile4Sbox() { enabled = true, - path = Utils.GetConfigPath("cache.db") + path = Utils.GetBinConfigPath("cache.db") }; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs index c79cc56c..46c99e97 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs @@ -353,6 +353,64 @@ namespace ServiceLib.Services.CoreConfig } } + public async Task GenerateClientSpeedtestConfig(ProfileItem node, int port) + { + var ret = new RetResult(); + try + { + if (node is not { Port: > 0 }) + { + ret.Msg = ResUI.CheckServerSettings; + return ret; + } + + if (node.GetNetwork() is nameof(ETransport.quic)) + { + ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; + return ret; + } + + var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient); + if (Utils.IsNullOrEmpty(result)) + { + ret.Msg = ResUI.FailedGetDefaultConfiguration; + return ret; + } + + var v2rayConfig = JsonUtils.Deserialize(result); + if (v2rayConfig == null) + { + ret.Msg = ResUI.FailedGenDefaultConfiguration; + return ret; + } + + await GenLog(v2rayConfig); + await GenOutbound(node, v2rayConfig.outbounds.First()); + await GenMoreOutbounds(node, v2rayConfig); + + v2rayConfig.routing.rules.Clear(); + v2rayConfig.inbounds.Clear(); + v2rayConfig.inbounds.Add(new() + { + tag = $"{EInboundProtocol.socks}{port}", + listen = Global.Loopback, + port = port, + protocol = EInboundProtocol.socks.ToString(), + }); + + ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); + ret.Success = true; + ret.Data = JsonUtils.Serialize(v2rayConfig); + return ret; + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + ret.Msg = ResUI.FailedGenDefaultConfiguration; + return ret; + } + } + #endregion public gen function #region private gen function diff --git a/v2rayN/ServiceLib/Services/SpeedtestService.cs b/v2rayN/ServiceLib/Services/SpeedtestService.cs index a978f2f5..6fe94284 100644 --- a/v2rayN/ServiceLib/Services/SpeedtestService.cs +++ b/v2rayN/ServiceLib/Services/SpeedtestService.cs @@ -22,12 +22,11 @@ namespace ServiceLib.Services { Task.Run(async () => { - var exitLoopKey = Utils.GetGuid(false); - _lstExitLoop.Add(exitLoopKey); - - var lstSelected = GetClearItem(actionType, selecteds); - await RunAsync(actionType, lstSelected, exitLoopKey); + await RunAsync(actionType, selecteds); + await ProfileExHandler.Instance.SaveTo(); UpdateFunc("", ResUI.SpeedtestingCompleted); + + FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1)); }); } @@ -41,49 +40,30 @@ namespace ServiceLib.Services } } - private async Task RunAsync(ESpeedActionType actionType, List lstSelected, string exitLoopKey, int pageSize = 0) + private async Task RunAsync(ESpeedActionType actionType, List selecteds) { - if (actionType == ESpeedActionType.Tcping) - { - await RunTcpingAsync(lstSelected); - return; - } + var exitLoopKey = Utils.GetGuid(false); + _lstExitLoop.Add(exitLoopKey); - if (pageSize <= 0) - { - pageSize = lstSelected.Count < Global.SpeedTestPageSize ? lstSelected.Count : Global.SpeedTestPageSize; - } - var lstTest = GetTestBatchItem(lstSelected, pageSize); + var lstSelected = GetClearItem(actionType, selecteds); - List lstFailed = new(); - foreach (var lst in lstTest) + switch (actionType) { - var ret = actionType switch - { - ESpeedActionType.Realping => await RunRealPingAsync(lst, exitLoopKey), - ESpeedActionType.Speedtest => await RunSpeedTestAsync(lst, exitLoopKey), - ESpeedActionType.Mixedtest => await RunMixedTestAsync(lst, exitLoopKey), - _ => true - }; - if (ret == false) - { - lstFailed.AddRange(lst); - } - await Task.Delay(100); - } + case ESpeedActionType.Tcping: + await RunTcpingAsync(lstSelected); + break; - //Retest the failed part - var pageSizeNext = pageSize / 2; - if (lstFailed.Count > 0 && pageSizeNext > 0) - { - if (_lstExitLoop.Any(p => p == exitLoopKey) == false) - { - UpdateFunc("", ResUI.SpeedtestingSkip); - return; - } + case ESpeedActionType.Realping: + await RunRealPingBatchAsync(lstSelected, exitLoopKey); + break; - UpdateFunc("", string.Format(ResUI.SpeedtestingTestFailedPart, lstFailed.Count)); - await RunAsync(actionType, lstFailed, exitLoopKey, pageSizeNext); + case ESpeedActionType.Speedtest: + await RunMixedTestAsync(lstSelected, 1, exitLoopKey); + break; + + case ESpeedActionType.Mixedtest: + await RunMixedTestAsync(lstSelected, 5, exitLoopKey); + break; } } @@ -107,7 +87,8 @@ namespace ServiceLib.Services IndexId = it.IndexId, Address = it.Address, Port = it.Port, - ConfigType = it.ConfigType + ConfigType = it.ConfigType, + QueueNum = selecteds.IndexOf(it) }); } @@ -138,60 +119,65 @@ namespace ServiceLib.Services return lstSelected; } - private List> GetTestBatchItem(List lstSelected, int pageSize) - { - List> lstTest = new(); - var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList(); - var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList(); - - for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++) - { - lstTest.Add(lst1.Skip(num * pageSize).Take(pageSize).ToList()); - } - for (var num = 0; num < (int)Math.Ceiling(lst2.Count * 1.0 / pageSize); num++) - { - lstTest.Add(lst2.Skip(num * pageSize).Take(pageSize).ToList()); - } - - return lstTest; - } - private async Task RunTcpingAsync(List selecteds) { - try + List tasks = []; + foreach (var it in selecteds) { - List tasks = []; - foreach (var it in selecteds) + if (it.ConfigType == EConfigType.Custom) { - if (it.ConfigType == EConfigType.Custom) - { - continue; - } - tasks.Add(Task.Run(async () => - { - try - { - var time = await GetTcpingTime(it.Address, it.Port); - var output = FormatOut(time, Global.DelayUnit); - - ProfileExHandler.Instance.SetTestDelay(it.IndexId, output); - UpdateFunc(it.IndexId, output); - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - })); + continue; } - Task.WaitAll([.. tasks]); + tasks.Add(Task.Run(async () => + { + try + { + var time = await GetTcpingTime(it.Address, it.Port); + var output = FormatOut(time, Global.DelayUnit); + + ProfileExHandler.Instance.SetTestDelay(it.IndexId, output); + UpdateFunc(it.IndexId, output); + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } + })); } - catch (Exception ex) + Task.WaitAll([.. tasks]); + } + + private async Task RunRealPingBatchAsync(List lstSelected, string exitLoopKey, int pageSize = 0) + { + if (pageSize <= 0) { - Logging.SaveLog(_tag, ex); + pageSize = lstSelected.Count < Global.SpeedTestPageSize ? lstSelected.Count : Global.SpeedTestPageSize; } - finally + var lstTest = GetTestBatchItem(lstSelected, pageSize); + + List lstFailed = new(); + foreach (var lst in lstTest) { - await ProfileExHandler.Instance.SaveTo(); + var ret = await RunRealPingAsync(lst, exitLoopKey); + if (ret == false) + { + lstFailed.AddRange(lst); + } + await Task.Delay(100); + } + + //Retest the failed part + var pageSizeNext = pageSize / 2; + if (lstFailed.Count > 0 && pageSizeNext > 0) + { + if (_lstExitLoop.Any(p => p == exitLoopKey) == false) + { + UpdateFunc("", ResUI.SpeedtestingSkip); + return; + } + + UpdateFunc("", string.Format(ResUI.SpeedtestingTestFailedPart, lstFailed.Count)); + await RunRealPingBatchAsync(lstFailed, exitLoopKey, pageSizeNext); } } @@ -221,20 +207,7 @@ namespace ServiceLib.Services } tasks.Add(Task.Run(async () => { - try - { - var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}"); - var output = await GetRealPingTime(downloadHandle, webProxy); - - ProfileExHandler.Instance.SetTestDelay(it.IndexId, output); - UpdateFunc(it.IndexId, output); - int.TryParse(output, out var delay); - it.Delay = delay; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } + await DoRealPing(downloadHandle, it); })); } Task.WaitAll(tasks.ToArray()); @@ -249,25 +222,15 @@ namespace ServiceLib.Services { await ProcUtils.ProcessKill(pid); } - await ProfileExHandler.Instance.SaveTo(); } return true; } - private async Task RunSpeedTestAsync(List selecteds, string exitLoopKey) + private async Task RunMixedTestAsync(List selecteds, int concurrencyCount, string exitLoopKey) { - var pid = -1; - pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds); - if (pid < 0) - { - return false; - } - - var url = _config.SpeedTestItem.SpeedTestUrl; - var timeout = _config.SpeedTestItem.SpeedTestTimeout; - - DownloadService downloadHandle = new(); - + using var concurrencySemaphore = new SemaphoreSlim(concurrencyCount); + var downloadHandle = new DownloadService(); + List tasks = new(); foreach (var it in selecteds) { if (_lstExitLoop.Any(p => p == exitLoopKey) == false) @@ -275,135 +238,73 @@ namespace ServiceLib.Services UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip); continue; } - - if (!it.AllowTest) - { - continue; - } if (it.ConfigType == EConfigType.Custom) { continue; } - //if (it.delay < 0) - //{ - // UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); - // continue; - //} - ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1"); - UpdateFunc(it.IndexId, "", ResUI.Speedtesting); + await concurrencySemaphore.WaitAsync(); - var item = await AppHandler.Instance.GetProfileItem(it.IndexId); - if (item is null) - continue; - - var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}"); - - await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) => + tasks.Add(Task.Run(async () => { - decimal.TryParse(msg, out var dec); - if (dec > 0) + var pid = -1; + try { - ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg); + pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it); + if (pid > 0) + { + await Task.Delay(1000); + await DoRealPing(downloadHandle, it); + await DoSpeedTest(downloadHandle, it); + } + else + { + UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore); + } } - UpdateFunc(it.IndexId, "", msg); - }); - } - - if (pid > 0) - { - await ProcUtils.ProcessKill(pid); - } - await ProfileExHandler.Instance.SaveTo(); - return true; - } - - private async Task RunSpeedTestMultiAsync(List selecteds, string exitLoopKey) - { - var pid = -1; - pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds); - if (pid < 0) - { - return false; - } - - var url = _config.SpeedTestItem.SpeedTestUrl; - var timeout = _config.SpeedTestItem.SpeedTestTimeout; - - DownloadService downloadHandle = new(); - - foreach (var it in selecteds) - { - if (_lstExitLoop.Any(p => p == exitLoopKey) == false) - { - UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip); - continue; - } - - if (!it.AllowTest) - { - continue; - } - if (it.ConfigType == EConfigType.Custom) - { - continue; - } - if (it.Delay < 0) - { - UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip); - continue; - } - ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1"); - UpdateFunc(it.IndexId, "", ResUI.Speedtesting); - - var item = await AppHandler.Instance.GetProfileItem(it.IndexId); - if (item is null) - continue; - - var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}"); - _ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) => - { - decimal.TryParse(msg, out var dec); - if (dec > 0) + catch (Exception ex) { - ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg); + Logging.SaveLog(_tag, ex); } - UpdateFunc(it.IndexId, "", msg); - }); - await Task.Delay(2000); + finally + { + if (pid > 0) + { + await ProcUtils.ProcessKill(pid); + } + concurrencySemaphore.Release(); + } + })); } - - await Task.Delay((timeout + 2) * 1000); - - if (pid > 0) - { - await ProcUtils.ProcessKill(pid); - } - await ProfileExHandler.Instance.SaveTo(); - return true; + Task.WaitAll(tasks.ToArray()); } - private async Task RunMixedTestAsync(List selecteds, string exitLoopKey) - { - var ret = await RunRealPingAsync(selecteds, exitLoopKey); - if (ret == false) - { - return false; - } - - await Task.Delay(1000); - - var ret2 = await RunSpeedTestMultiAsync(selecteds, exitLoopKey); - if (ret2 == false) - { - return false; - } - return true; - } - - private async Task GetRealPingTime(DownloadService downloadHandle, IWebProxy webProxy) + private async Task DoRealPing(DownloadService downloadHandle, ServerTestItem it) { + var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}"); var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10); - return FormatOut(responseTime, Global.DelayUnit); + var output = FormatOut(responseTime, Global.DelayUnit); + + ProfileExHandler.Instance.SetTestDelay(it.IndexId, output); + UpdateFunc(it.IndexId, output); + } + + private async Task DoSpeedTest(DownloadService downloadHandle, ServerTestItem it) + { + ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1"); + UpdateFunc(it.IndexId, "", ResUI.Speedtesting); + + var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}"); + var url = _config.SpeedTestItem.SpeedTestUrl; + var timeout = _config.SpeedTestItem.SpeedTestTimeout; + await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) => + { + decimal.TryParse(msg, out var dec); + if (dec > 0) + { + ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg); + } + UpdateFunc(it.IndexId, "", msg); + }); } private async Task GetTcpingTime(string url, int port) @@ -438,6 +339,24 @@ namespace ServiceLib.Services return responseTime; } + private List> GetTestBatchItem(List lstSelected, int pageSize) + { + List> lstTest = new(); + var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList(); + var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList(); + + for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++) + { + lstTest.Add(lst1.Skip(num * pageSize).Take(pageSize).ToList()); + } + for (var num = 0; num < (int)Math.Ceiling(lst2.Count * 1.0 / pageSize); num++) + { + lstTest.Add(lst2.Skip(num * pageSize).Take(pageSize).ToList()); + } + + return lstTest; + } + private string FormatOut(object time, string unit) { return $"{time}"; diff --git a/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs b/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs index ff74b377..fddb48d7 100644 --- a/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs @@ -173,7 +173,7 @@ namespace ServiceLib.ViewModels var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}"); var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs); - FileManager.CopyDirectory(configDir, configDirTemp, false, true, "cache.db"); + FileManager.CopyDirectory(configDir, configDirTemp, false, true, ""); var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName); Directory.Delete(configDirZipTemp, true); return await Task.FromResult(ret);