mirror of
https://github.com/2dust/v2rayN.git
synced 2026-04-17 04:55:45 +00:00
Auto-fill empty node remarks during speed tests
This commit is contained in:
parent
8ebc168db8
commit
5d76a3e26e
3 changed files with 117 additions and 7 deletions
|
|
@ -3,6 +3,11 @@ namespace ServiceLib.Handler;
|
||||||
public static class ConnectionHandler
|
public static class ConnectionHandler
|
||||||
{
|
{
|
||||||
private static readonly string _tag = "ConnectionHandler";
|
private static readonly string _tag = "ConnectionHandler";
|
||||||
|
private static readonly string[] _speedtestIpApiUrls =
|
||||||
|
[
|
||||||
|
"https://api.ipapi.is",
|
||||||
|
"https://api.ip.sb/geoip"
|
||||||
|
];
|
||||||
|
|
||||||
public static async Task<string> RunAvailabilityCheck()
|
public static async Task<string> RunAvailabilityCheck()
|
||||||
{
|
{
|
||||||
|
|
@ -20,23 +25,83 @@ public static class ConnectionHandler
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadHandle = new DownloadService();
|
var port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
var result = await downloadHandle.TryDownloadString(url, true, "");
|
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{port}");
|
||||||
if (result == null)
|
var ipInfo = await GetIpApiInfo(url, webProxy, 10);
|
||||||
|
return FormatCountryAndIp(ipInfo, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<string?> GetCountryCodeAndIP(IWebProxy? webProxy, int downloadTimeout = 10)
|
||||||
|
{
|
||||||
|
foreach (var url in _speedtestIpApiUrls)
|
||||||
|
{
|
||||||
|
var ipInfo = await GetIpApiInfo(url, webProxy, downloadTimeout);
|
||||||
|
var compact = FormatCountryAndIp(ipInfo, true);
|
||||||
|
if (compact.IsNotEmpty())
|
||||||
|
{
|
||||||
|
return compact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<IPAPIInfo?> GetIpApiInfo(string url, IWebProxy? webProxy, int downloadTimeout)
|
||||||
|
{
|
||||||
|
if (url.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
|
try
|
||||||
|
{
|
||||||
|
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(downloadTimeout));
|
||||||
|
using var client = new HttpClient(new SocketsHttpHandler()
|
||||||
|
{
|
||||||
|
Proxy = webProxy,
|
||||||
|
UseProxy = webProxy != null
|
||||||
|
});
|
||||||
|
client.DefaultRequestHeaders.UserAgent.TryParseAdd(Utils.GetVersion(false));
|
||||||
|
|
||||||
|
using var response = await client.GetAsync(url, cts.Token).ConfigureAwait(false);
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await response.Content.ReadAsStringAsync(cts.Token).ConfigureAwait(false);
|
||||||
|
return JsonUtils.Deserialize<IPAPIInfo>(result);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? FormatCountryAndIp(IPAPIInfo? ipInfo, bool compact)
|
||||||
|
{
|
||||||
if (ipInfo == null)
|
if (ipInfo == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ip = ipInfo.ip ?? ipInfo.clientIp ?? ipInfo.ip_addr ?? ipInfo.query;
|
var ip = (ipInfo.ip ?? ipInfo.clientIp ?? ipInfo.ip_addr ?? ipInfo.query)?.Trim();
|
||||||
var country = ipInfo.country_code ?? ipInfo.country ?? ipInfo.countryCode ?? ipInfo.location?.country_code;
|
if (ip.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $"({country ?? "unknown"}) {ip}";
|
var country = (ipInfo.country_code ?? ipInfo.countryCode ?? ipInfo.location?.country_code ?? ipInfo.country)?.Trim();
|
||||||
|
if (country.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
country = "unknown";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
country = country.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
return compact ? $"{country}{ip}" : $"({country}) {ip}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<int> GetRealPingTimeInfo()
|
private static async Task<int> GetRealPingTimeInfo()
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,6 @@ public class ServerTestItem
|
||||||
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 bool NeedAutoFillRemarks { get; set; }
|
||||||
public int QueueNum { get; set; }
|
public int QueueNum { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,19 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
|
||||||
private readonly Config? _config = config;
|
private readonly Config? _config = config;
|
||||||
private readonly Func<SpeedTestResult, Task>? _updateFunc = updateFunc;
|
private readonly Func<SpeedTestResult, Task>? _updateFunc = updateFunc;
|
||||||
private static readonly ConcurrentBag<string> _lstExitLoop = new();
|
private static readonly ConcurrentBag<string> _lstExitLoop = new();
|
||||||
|
private int _remarksUpdated;
|
||||||
|
|
||||||
public void RunLoop(ESpeedActionType actionType, List<ProfileItem> selecteds)
|
public void RunLoop(ESpeedActionType actionType, List<ProfileItem> selecteds)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
Interlocked.Exchange(ref _remarksUpdated, 0);
|
||||||
await RunAsync(actionType, selecteds);
|
await RunAsync(actionType, selecteds);
|
||||||
await ProfileExManager.Instance.SaveTo();
|
await ProfileExManager.Instance.SaveTo();
|
||||||
|
if (Interlocked.CompareExchange(ref _remarksUpdated, 0, 0) > 0)
|
||||||
|
{
|
||||||
|
AppEvents.ProfilesRefreshRequested.Publish();
|
||||||
|
}
|
||||||
await UpdateFunc("", ResUI.SpeedtestingCompleted);
|
await UpdateFunc("", ResUI.SpeedtestingCompleted);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +86,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
|
||||||
Address = it.Address,
|
Address = it.Address,
|
||||||
Port = it.Port,
|
Port = it.Port,
|
||||||
ConfigType = it.ConfigType,
|
ConfigType = it.ConfigType,
|
||||||
|
NeedAutoFillRemarks = it.Remarks.IsNullOrEmpty(),
|
||||||
QueueNum = selecteds.IndexOf(it)
|
QueueNum = selecteds.IndexOf(it)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -297,11 +304,48 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
|
||||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
||||||
var responseTime = await ConnectionHandler.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
var responseTime = await ConnectionHandler.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||||
|
|
||||||
|
if (responseTime > 0 && it.NeedAutoFillRemarks)
|
||||||
|
{
|
||||||
|
await TryAutoFillRemarks(it, webProxy);
|
||||||
|
}
|
||||||
|
|
||||||
ProfileExManager.Instance.SetTestDelay(it.IndexId, responseTime);
|
ProfileExManager.Instance.SetTestDelay(it.IndexId, responseTime);
|
||||||
await UpdateFunc(it.IndexId, responseTime.ToString());
|
await UpdateFunc(it.IndexId, responseTime.ToString());
|
||||||
return responseTime;
|
return responseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task TryAutoFillRemarks(ServerTestItem it, IWebProxy webProxy)
|
||||||
|
{
|
||||||
|
if (!it.NeedAutoFillRemarks || it.IndexId.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var remarks = await ConnectionHandler.GetCountryCodeAndIP(webProxy, 8);
|
||||||
|
if (remarks.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var profileItem = await AppManager.Instance.GetProfileItem(it.IndexId);
|
||||||
|
if (profileItem == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (profileItem.Remarks.IsNotEmpty())
|
||||||
|
{
|
||||||
|
it.NeedAutoFillRemarks = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
profileItem.Remarks = remarks;
|
||||||
|
if (await SQLiteHelper.Instance.UpdateAsync(profileItem) > 0)
|
||||||
|
{
|
||||||
|
it.NeedAutoFillRemarks = false;
|
||||||
|
Interlocked.Increment(ref _remarksUpdated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task DoSpeedTest(DownloadService downloadHandle, ServerTestItem it)
|
private async Task DoSpeedTest(DownloadService downloadHandle, ServerTestItem it)
|
||||||
{
|
{
|
||||||
await UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
|
await UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue