Added the current connection information test url option
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run

https://github.com/2dust/v2rayN/discussions/7268
This commit is contained in:
2dust 2025-05-11 16:59:00 +08:00
parent 8381fefb78
commit a2cfe6fa51
19 changed files with 139 additions and 25 deletions

View file

@ -8,9 +8,7 @@ public class Global
public const string GithubUrl = "https://github.com";
public const string GithubApiUrl = "https://api.github.com/repos";
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
public const string IPAPIUrl = "https://api.ip.sb/geoip";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json";
@ -519,5 +517,15 @@ public class Global
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
];
public static readonly List<string> IPAPIUrls =
[
@"https://speed.cloudflare.com/meta",
@"https://api.ip.sb/geoip",
@"https://api-ipv4.ip.sb/geoip",
@"https://api-ipv6.ip.sb/geoip",
@"https://api.ipapi.is",
@""
];
#endregion const
}

View file

@ -122,7 +122,7 @@ public class ConfigHandler
}
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
{
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrls.First();
}
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
{

View file

@ -0,0 +1,42 @@
namespace ServiceLib.Handler;
public class ConnectionHandler
{
private static readonly Lazy<ConnectionHandler> _instance = new(() => new());
public static ConnectionHandler Instance => _instance.Value;
public async Task<string> RunAvailabilityCheck()
{
var downloadHandle = new DownloadService();
var time = await downloadHandle.RunAvailabilityCheck(null);
var ip = time > 0 ? await GetIPInfo(downloadHandle) ?? Global.None : Global.None;
return string.Format(ResUI.TestMeOutput, time, ip);
}
private async Task<string?> GetIPInfo(DownloadService downloadHandle)
{
var url = AppHandler.Instance.Config.SpeedTestItem.IPAPIUrl;
if (url.IsNullOrEmpty())
{
return null;
}
var result = await downloadHandle.TryDownloadString(url, true, "");
if (result == null)
{
return null;
}
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
if (ipInfo == null)
{
return null;
}
var ip = ipInfo.ip ?? ipInfo.clientIp ?? ipInfo.ip_addr ?? ipInfo.query;
var country = ipInfo.country_code ?? ipInfo.country ?? ipInfo.countryCode ?? ipInfo.location?.country_code;
return $"({country ?? "unknown"}) {ip}";
}
}

View file

@ -156,6 +156,7 @@ public class SpeedTestItem
public string SpeedTestUrl { get; set; }
public string SpeedPingTestUrl { get; set; }
public int MixedConcurrencyCount { get; set; }
public string IPAPIUrl { get; set; }
}
[Serializable]

View file

@ -3,10 +3,17 @@ namespace ServiceLib.Models;
internal class IPAPIInfo
{
public string? ip { get; set; }
public string? city { get; set; }
public string? region { get; set; }
public string? region_code { get; set; }
public string? clientIp { get; set; }
public string? ip_addr { get; set; }
public string? query { get; set; }
public string? country { get; set; }
public string? country_name { get; set; }
public string? country_code { get; set; }
public string? countryCode { get; set; }
public LocationInfo? location { get; set; }
}
public class LocationInfo
{
public string? country_code { get; set; }
}

View file

@ -3201,6 +3201,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Current connection info test URL 的本地化字符串。
/// </summary>
public static string TbSettingsIPAPIUrl {
get {
return ResourceManager.GetString("TbSettingsIPAPIUrl", resourceCulture);
}
}
/// <summary>
/// 查找类似 Keep older entries when de-duplicating 的本地化字符串。
/// </summary>

View file

@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve">
<value>صادر کردن سرور</value>
</data>
</root>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root>

View file

@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve">
<value>Export server</value>
</data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root>

View file

@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve">
<value>Export Configuration</value>
</data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root>

View file

@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve">
<value>Export server</value>
</data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root>

View file

@ -1413,4 +1413,7 @@
<data name="menuExportConfig" xml:space="preserve">
<value>导出配置文件</value>
</data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>当前连接信息测试地址</value>
</data>
</root>

View file

@ -1413,4 +1413,7 @@
<data name="menuExportConfig" xml:space="preserve">
<value>匯出設定檔</value>
</data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>目前連接資訊測試地址</value>
</data>
</root>

View file

@ -243,21 +243,6 @@ public class UpdateService
_updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
}
public async Task<string> RunAvailabilityCheck()
{
var downloadHandle = new DownloadService();
var time = await downloadHandle.RunAvailabilityCheck(null);
var ip = Global.None;
//if (time > 0)
//{
// var result = await downloadHandle.TryDownloadString(Global.IPAPIUrl, true, Global.IPAPIUrl);
// var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
// ip = $"({ipInfo?.country_code}) {ipInfo?.ip}";
//}
return string.Format(ResUI.TestMeOutput, time, ip);
}
#region CheckUpdate private
private async Task<RetResult> CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease)

View file

@ -70,6 +70,7 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public string GeoFileSourceUrl { get; set; }
[Reactive] public string SrsFileSourceUrl { get; set; }
[Reactive] public string RoutingRulesSourceUrl { get; set; }
[Reactive] public string IPAPIUrl { get; set; }
#endregion UI
@ -186,6 +187,7 @@ public class OptionSettingViewModel : MyReactiveObject
GeoFileSourceUrl = _config.ConstItem.GeoSourceUrl;
SrsFileSourceUrl = _config.ConstItem.SrsSourceUrl;
RoutingRulesSourceUrl = _config.ConstItem.RouteRulesTemplateSourceUrl;
IPAPIUrl = _config.SpeedTestItem.IPAPIUrl;
#endregion UI
@ -344,6 +346,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.ConstItem.GeoSourceUrl = GeoFileSourceUrl;
_config.ConstItem.SrsSourceUrl = SrsFileSourceUrl;
_config.ConstItem.RouteRulesTemplateSourceUrl = RoutingRulesSourceUrl;
_config.SpeedTestItem.IPAPIUrl = IPAPIUrl;
//systemProxy
_config.SystemProxyItem.SystemProxyExceptions = systemProxyExceptions;
@ -356,7 +359,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
//coreType
await SaveCoreType();

View file

@ -320,7 +320,7 @@ public class StatusBarViewModel : MyReactiveObject
var msg = await Task.Run(async () =>
{
return await (new UpdateService()).RunAvailabilityCheck();
return await ConnectionHandler.Instance.RunAvailabilityCheck();
});
NoticeHandler.Instance.SendMessageEx(msg);

View file

@ -343,7 +343,7 @@
<Grid
Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock
x:Name="tbAutoRun"
@ -655,6 +655,20 @@
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="25"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
<ComboBox
x:Name="cmbIPAPIUrl"
Grid.Row="25"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}" />
</Grid>
</ScrollViewer>
</TabItem>

View file

@ -92,6 +92,10 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
{
cmbRoutingRulesSourceUrl.Items.Add(it);
});
Global.IPAPIUrls.ForEach(it =>
{
cmbIPAPIUrl.Items.Add(it);
});
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
{
cmbMainGirdOrientation.Items.Add(it.ToString());
@ -143,6 +147,7 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.IPAPIUrl, v => v.cmbIPAPIUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.SelectedValue).DisposeWith(disposables);

View file

@ -552,6 +552,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@ -942,6 +943,22 @@
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="25"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
<ComboBox
x:Name="cmbIPAPIUrl"
Grid.Row="25"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin8}"
IsEditable="True"
Style="{StaticResource DefComboBox}" />
</Grid>
</ScrollViewer>
</TabItem>

View file

@ -101,6 +101,10 @@ public partial class OptionSettingWindow
{
cmbRoutingRulesSourceUrl.Items.Add(it);
});
Global.IPAPIUrls.ForEach(it =>
{
cmbIPAPIUrl.Items.Add(it);
});
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
{
cmbMainGirdOrientation.Items.Add(it.ToString());
@ -162,6 +166,7 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.IPAPIUrl, v => v.cmbIPAPIUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);