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.
pull/6714/head
2dust 2025-02-13 19:46:51 +08:00
parent 4104964e38
commit 1198ec0f74
11 changed files with 405 additions and 259 deletions

View File

@ -86,17 +86,43 @@ public static class ProcUtils
GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName); GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName);
try 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 try
{ proc?.Kill(); } {
catch (Exception ex) { Logging.SaveLog(_tag, ex); } proc?.Kill();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
try try
{ proc?.Close(); } {
catch (Exception ex) { Logging.SaveLog(_tag, ex); } proc?.Close();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
try try
{ proc?.Dispose(); } {
catch (Exception ex) { Logging.SaveLog(_tag, ex); } proc?.Dispose();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
await Task.Delay(300); await Task.Delay(300);
await ProcessKillByKeyInfo(review, procId, fileName, processName); await ProcessKillByKeyInfo(review, procId, fileName, processName);

View File

@ -433,10 +433,22 @@ namespace ServiceLib.Common
{ {
try try
{ {
var ipProperties = IPGlobalProperties.GetIPGlobalProperties(); List<IPEndPoint> lstIpEndPoints = new();
var ipEndPoints = ipProperties.GetActiveTcpListeners(); List<TcpConnectionInformation> lstTcpConns = new();
//var lstIpEndPoints = new List<IPEndPoint>(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
return ipEndPoints.Any(endPoint => endPoint.Port == port); 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) 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 #endregion TempPath
#region Platform #region Platform

View File

@ -16,7 +16,7 @@ namespace ServiceLib
public const string ConfigFileName = "guiNConfig.json"; public const string ConfigFileName = "guiNConfig.json";
public const string CoreConfigFileName = "config.json"; public const string CoreConfigFileName = "config.json";
public const string CorePreConfigFileName = "configPre.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 CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
public const string ClashMixinConfigFileName = "Mixin.yaml"; public const string ClashMixinConfigFileName = "Mixin.yaml";

View File

@ -1,4 +1,4 @@
namespace ServiceLib.Handler namespace ServiceLib.Handler
{ {
public sealed class AppHandler public sealed class AppHandler
{ {
@ -98,6 +98,7 @@
{ {
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1)); FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1)); FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
}); });
} }

View File

@ -1,4 +1,4 @@
namespace ServiceLib.Handler namespace ServiceLib.Handler
{ {
/// <summary> /// <summary>
/// Core configuration file processing class /// Core configuration file processing class
@ -109,6 +109,30 @@
return result; return result;
} }
public static async Task<RetResult> 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<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType) public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType)
{ {
var result = new RetResult(); var result = new RetResult();

View File

@ -70,7 +70,7 @@ namespace ServiceLib.Handler
return; return;
} }
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName); var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName); var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
if (result.Success != true) if (result.Success != true)
{ {
@ -101,7 +101,8 @@ namespace ServiceLib.Handler
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds) public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
{ {
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray; 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); var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
UpdateFunc(false, result.Msg); UpdateFunc(false, result.Msg);
if (result.Success != true) if (result.Success != true)
@ -113,7 +114,34 @@ namespace ServiceLib.Handler
UpdateFunc(false, configPath); UpdateFunc(false, configPath);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); 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<int> 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) if (proc is null)
{ {
return -1; return -1;
@ -175,7 +203,7 @@ namespace ServiceLib.Handler
if (itemSocks != null) if (itemSocks != null)
{ {
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box; 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); var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
if (result.Success) if (result.Success)
{ {
@ -225,8 +253,8 @@ namespace ServiceLib.Handler
StartInfo = new() StartInfo = new()
{ {
FileName = fileName, FileName = fileName,
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetConfigPath(configPath) : configPath), Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath) : configPath),
WorkingDirectory = Utils.GetConfigPath(), WorkingDirectory = Utils.GetBinConfigPath(),
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = displayLog, RedirectStandardOutput = displayLog,
RedirectStandardError = displayLog, RedirectStandardError = displayLog,
@ -298,7 +326,7 @@ namespace ServiceLib.Handler
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath) 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"); var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
proc.StartInfo.FileName = shFilePath; proc.StartInfo.FileName = shFilePath;

View File

@ -1,4 +1,4 @@
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class ServerTestItem public class ServerTestItem
@ -8,6 +8,6 @@
public int Port { get; set; } public int Port { get; set; }
public EConfigType ConfigType { get; set; } public EConfigType ConfigType { get; set; }
public bool AllowTest { get; set; } public bool AllowTest { get; set; }
public int Delay { get; set; } public int QueueNum { get; set; }
} }
} }

View File

@ -242,6 +242,66 @@ namespace ServiceLib.Services.CoreConfig
} }
} }
public async Task<RetResult> 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<SingboxConfig>(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<RetResult> GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds) public async Task<RetResult> GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds)
{ {
var ret = new RetResult(); var ret = new RetResult();
@ -1264,7 +1324,7 @@ namespace ServiceLib.Services.CoreConfig
singboxConfig.experimental.cache_file = new CacheFile4Sbox() singboxConfig.experimental.cache_file = new CacheFile4Sbox()
{ {
enabled = true, enabled = true,
path = Utils.GetConfigPath("cache.db") path = Utils.GetBinConfigPath("cache.db")
}; };
} }

View File

@ -353,6 +353,64 @@ namespace ServiceLib.Services.CoreConfig
} }
} }
public async Task<RetResult> 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<V2rayConfig>(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 #endregion public gen function
#region private gen function #region private gen function

View File

@ -22,12 +22,11 @@ namespace ServiceLib.Services
{ {
Task.Run(async () => Task.Run(async () =>
{ {
var exitLoopKey = Utils.GetGuid(false); await RunAsync(actionType, selecteds);
_lstExitLoop.Add(exitLoopKey); await ProfileExHandler.Instance.SaveTo();
var lstSelected = GetClearItem(actionType, selecteds);
await RunAsync(actionType, lstSelected, exitLoopKey);
UpdateFunc("", ResUI.SpeedtestingCompleted); 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<ServerTestItem> lstSelected, string exitLoopKey, int pageSize = 0) private async Task RunAsync(ESpeedActionType actionType, List<ProfileItem> selecteds)
{ {
if (actionType == ESpeedActionType.Tcping) var exitLoopKey = Utils.GetGuid(false);
_lstExitLoop.Add(exitLoopKey);
var lstSelected = GetClearItem(actionType, selecteds);
switch (actionType)
{ {
case ESpeedActionType.Tcping:
await RunTcpingAsync(lstSelected); await RunTcpingAsync(lstSelected);
return; break;
}
if (pageSize <= 0) case ESpeedActionType.Realping:
{ await RunRealPingBatchAsync(lstSelected, exitLoopKey);
pageSize = lstSelected.Count < Global.SpeedTestPageSize ? lstSelected.Count : Global.SpeedTestPageSize; break;
}
var lstTest = GetTestBatchItem(lstSelected, pageSize);
List<ServerTestItem> lstFailed = new(); case ESpeedActionType.Speedtest:
foreach (var lst in lstTest) await RunMixedTestAsync(lstSelected, 1, exitLoopKey);
{ break;
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);
}
//Retest the failed part case ESpeedActionType.Mixedtest:
var pageSizeNext = pageSize / 2; await RunMixedTestAsync(lstSelected, 5, exitLoopKey);
if (lstFailed.Count > 0 && pageSizeNext > 0) break;
{
if (_lstExitLoop.Any(p => p == exitLoopKey) == false)
{
UpdateFunc("", ResUI.SpeedtestingSkip);
return;
}
UpdateFunc("", string.Format(ResUI.SpeedtestingTestFailedPart, lstFailed.Count));
await RunAsync(actionType, lstFailed, exitLoopKey, pageSizeNext);
} }
} }
@ -107,7 +87,8 @@ namespace ServiceLib.Services
IndexId = it.IndexId, IndexId = it.IndexId,
Address = it.Address, Address = it.Address,
Port = it.Port, Port = it.Port,
ConfigType = it.ConfigType ConfigType = it.ConfigType,
QueueNum = selecteds.IndexOf(it)
}); });
} }
@ -138,27 +119,7 @@ namespace ServiceLib.Services
return lstSelected; return lstSelected;
} }
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
{
List<List<ServerTestItem>> 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<ServerTestItem> selecteds) private async Task RunTcpingAsync(List<ServerTestItem> selecteds)
{
try
{ {
List<Task> tasks = []; List<Task> tasks = [];
foreach (var it in selecteds) foreach (var it in selecteds)
@ -185,13 +146,38 @@ namespace ServiceLib.Services
} }
Task.WaitAll([.. tasks]); Task.WaitAll([.. tasks]);
} }
catch (Exception ex)
private async Task RunRealPingBatchAsync(List<ServerTestItem> lstSelected, string exitLoopKey, int pageSize = 0)
{ {
Logging.SaveLog(_tag, ex); if (pageSize <= 0)
{
pageSize = lstSelected.Count < Global.SpeedTestPageSize ? lstSelected.Count : Global.SpeedTestPageSize;
} }
finally var lstTest = GetTestBatchItem(lstSelected, pageSize);
List<ServerTestItem> 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 () => tasks.Add(Task.Run(async () =>
{ {
try await DoRealPing(downloadHandle, it);
{
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);
}
})); }));
} }
Task.WaitAll(tasks.ToArray()); Task.WaitAll(tasks.ToArray());
@ -249,25 +222,15 @@ namespace ServiceLib.Services
{ {
await ProcUtils.ProcessKill(pid); await ProcUtils.ProcessKill(pid);
} }
await ProfileExHandler.Instance.SaveTo();
} }
return true; return true;
} }
private async Task<bool> RunSpeedTestAsync(List<ServerTestItem> selecteds, string exitLoopKey) private async Task RunMixedTestAsync(List<ServerTestItem> selecteds, int concurrencyCount, string exitLoopKey)
{ {
var pid = -1; using var concurrencySemaphore = new SemaphoreSlim(concurrencyCount);
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds); var downloadHandle = new DownloadService();
if (pid < 0) List<Task> tasks = new();
{
return false;
}
var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
DownloadService downloadHandle = new();
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
if (_lstExitLoop.Any(p => p == exitLoopKey) == false) if (_lstExitLoop.Any(p => p == exitLoopKey) == false)
@ -275,29 +238,64 @@ namespace ServiceLib.Services
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip); UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
continue; continue;
} }
if (!it.AllowTest)
{
continue;
}
if (it.ConfigType == EConfigType.Custom) if (it.ConfigType == EConfigType.Custom)
{ {
continue; continue;
} }
//if (it.delay < 0) await concurrencySemaphore.WaitAsync();
//{
// UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); tasks.Add(Task.Run(async () =>
// continue; {
//} var pid = -1;
try
{
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);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
finally
{
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
concurrencySemaphore.Release();
}
}));
}
Task.WaitAll(tasks.ToArray());
}
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);
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"); ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1");
UpdateFunc(it.IndexId, "", ResUI.Speedtesting); 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}"); 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) => await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
{ {
decimal.TryParse(msg, out var dec); decimal.TryParse(msg, out var dec);
@ -309,103 +307,6 @@ namespace ServiceLib.Services
}); });
} }
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
await ProfileExHandler.Instance.SaveTo();
return true;
}
private async Task<bool> RunSpeedTestMultiAsync(List<ServerTestItem> 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)
{
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
}
UpdateFunc(it.IndexId, "", msg);
});
await Task.Delay(2000);
}
await Task.Delay((timeout + 2) * 1000);
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
await ProfileExHandler.Instance.SaveTo();
return true;
}
private async Task<bool> RunMixedTestAsync(List<ServerTestItem> 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<string> GetRealPingTime(DownloadService downloadHandle, IWebProxy webProxy)
{
var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
return FormatOut(responseTime, Global.DelayUnit);
}
private async Task<int> GetTcpingTime(string url, int port) private async Task<int> GetTcpingTime(string url, int port)
{ {
var responseTime = -1; var responseTime = -1;
@ -438,6 +339,24 @@ namespace ServiceLib.Services
return responseTime; return responseTime;
} }
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
{
List<List<ServerTestItem>> 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) private string FormatOut(object time, string unit)
{ {
return $"{time}"; return $"{time}";

View File

@ -173,7 +173,7 @@ namespace ServiceLib.ViewModels
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}"); var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs); 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); var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName);
Directory.Delete(configDirZipTemp, true); Directory.Delete(configDirZipTemp, true);
return await Task.FromResult(ret); return await Task.FromResult(ret);