Skip to content

Commit

Permalink
Merge pull request #3495 from BeyondDimension/refactor_NetworkCheck
Browse files Browse the repository at this point in the history
💄 网络测试子页面重构
  • Loading branch information
rmbadmin authored Oct 9, 2024
2 parents 95c10da + 9a2bd1a commit e0c36a9
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
using AppResources = BD.WTTS.Client.Resources.Strings;

using BD.WTTS.UI.Views.Pages;
using STUN.StunResult;
using STUN.Enums;
using AppResources = BD.WTTS.Client.Resources.Strings;

namespace BD.WTTS.UI.ViewModels;

public sealed partial class AcceleratorPageViewModel
{
public NetworkCheckControlViewModel NetworkCheckControlViewModel { get; } = new();

DateTime _initializeTime;
readonly IHostsFileService? hostsFileService;
readonly IPlatformService platformService = IPlatformService.Instance;
readonly IReverseProxyService reverseProxyService = IReverseProxyService.Constants.Instance;
readonly ICertificateManager certificateManager = ICertificateManager.Constants.Instance;
readonly INetworkTestService networkTestService = INetworkTestService.Instance;

public AcceleratorPageViewModel()
{
Expand Down Expand Up @@ -71,82 +69,6 @@ public AcceleratorPageViewModel()
GameAcceleratorService.Current.LoadGames();
});

SelectedSTUNAddress = STUNAddress[0];

NATCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var natCheckResult = await networkTestService.TestStunClient3489Async(testServerHostName: SelectedSTUNAddress) ?? new ClassicStunResult { NatType = NatType.Unknown };
var (netSucc, _) = await networkTestService.TestOpenUrlAsync("https://www.baidu.com");

var natStatus = natCheckResult.NatType switch
{
NatType.OpenInternet or NatType.FullCone => NatTypeSimple.Open,
NatType.RestrictedCone or NatType.PortRestrictedCone or NatType.SymmetricUdpFirewall => NatTypeSimple.Moderate,
NatType.Symmetric or NatType.UdpBlocked => NatTypeSimple.Strict,
NatType.Unknown or NatType.UnsupportedServer or _ => NatTypeSimple.Unknown,
};

PublicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown";
LocalEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown";

return (natStatus, netSucc);
});
NATCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsNATChecking);

DNSCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var testDomain = DomainPendingTest == string.Empty ? "store.steampowered.com" : DomainPendingTest;
try
{
long delayMs;
IPAddress[] address;
if (ProxySettings.UseDoh)
{
var configDoh = ProxySettings.CustomDohAddres2.Value ?? ProxySettingsWindowViewModel.DohAddress.FirstOrDefault() ?? string.Empty;
(delayMs, address) = await networkTestService.TestDNSOverHttpsAsync(testDomain, configDoh);
}
else
{
var configDns = ProxySettings.ProxyMasterDns.Value ?? string.Empty;
(delayMs, address) = await networkTestService.TestDNSAsync(testDomain, configDns, 53);
}
if (address.Length == 0)
throw new Exception("Parsing failed. Return empty ip address.");

DNSTestDelay = delayMs + "ms ";
DNSTestResult = string.Empty + address.FirstOrDefault();
}
catch (Exception ex)
{
Log.Error(nameof(AcceleratorPageViewModel), ex.ToString());
DNSTestDelay = string.Empty;
DNSTestResult = "error";
}
});
DNSCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsDNSChecking);

IPv6CheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var result = await IMicroServiceClient.Instance.Accelerate.GetMyIP(ipV6: true);
if (result.IsSuccess)
{
IsSupportIPv6 = true;
IPv6Address = result.Content ?? string.Empty;
}
else
{
IsSupportIPv6 = false;
IPv6Address = string.Empty;
}
});
IPv6CheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsIPv6Checking);

ProxySettingsCommand = ReactiveCommand.Create(() =>
{
var vm = new ProxySettingsWindowViewModel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,11 @@ namespace BD.WTTS.UI.ViewModels;

public sealed partial class AcceleratorPageViewModel : TabItemViewModel
{
public enum NatTypeSimple
{
Unknown,
Open,
Moderate,
Strict,
}

public override string Name => Strings.Welcome;

[Reactive]
public string SelectedSTUNAddress { get; set; }

public string[] STUNAddress { get; } =
[
"stun.syncthing.net",
"stun.hot-chilli.net",
"stun.fitauto.ru",
"stun.miwifi.com",
];

[ObservableAsProperty]
public bool IsNATChecking { get; }

[ObservableAsProperty]
public bool IsDNSChecking { get; }

[ObservableAsProperty]
public bool IsIPv6Checking { get; }

[Reactive]
public string DomainPendingTest { get; set; } = string.Empty;

[Reactive]
public ReadOnlyCollection<ProxyDomainGroupViewModel>? EnableProxyDomainGroupVMs { get; set; }

[Reactive]
public string LocalEndPoint { get; set; } = string.Empty;

[Reactive]
public string PublicEndPoint { get; set; } = string.Empty;

[Reactive]
public string DNSTestDelay { get; set; } = string.Empty;

[Reactive]
public string DNSTestResult { get; set; } = string.Empty;

[Reactive]
public string IPv6Address { get; set; } = string.Empty;

[Reactive]
public bool IsSupportIPv6 { get; set; }

public ReactiveCommand<Unit, (NatTypeSimple Nat, bool PingSuccess)> NATCheckCommand { get; }

public ReactiveCommand<Unit, Unit> DNSCheckCommand { get; }

public ReactiveCommand<Unit, Unit> IPv6CheckCommand { get; }

public ICommand StartProxyCommand { get; }

public ICommand RefreshCommand { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
using STUN.Enums;
using STUN.StunResult;
using System.Reactive;

namespace BD.WTTS.UI.ViewModels;

public class NetworkCheckControlViewModel : ViewModelBase
{
private readonly INetworkTestService _networkTestService = INetworkTestService.Instance;

public record NATFetchResult(string PublicEndPoint, string LocalEndPoint, string NATLevel, string NATTypeTip, bool PingResult);

[Reactive]
public string SelectedSTUNAddress { get; set; }

public string[] STUNAddress { get; } =
[
"stun.syncthing.net",
"stun.hot-chilli.net",
"stun.fitauto.ru",
"stun.miwifi.com",
];

[ObservableAsProperty]
public string NATLevel { get; } = string.Empty;

[ObservableAsProperty]
public string NATTypeTip { get; } = string.Empty;

[ObservableAsProperty]
public string LocalEndPoint { get; } = string.Empty;

[ObservableAsProperty]
public string PublicEndPoint { get; } = string.Empty;

[ObservableAsProperty]
public bool PingOkVisible { get; }

[ObservableAsProperty]
public bool PingErrorVisible { get; }

[ObservableAsProperty]
public bool IsNATChecking { get; }

[ObservableAsProperty]
public bool IsDNSChecking { get; }

[ObservableAsProperty]
public bool IsIPv6Checking { get; }

[Reactive]
public string DomainPendingTest { get; set; } = string.Empty;

[Reactive]
public string DNSTestDelay { get; set; } = string.Empty;

[Reactive]
public string DNSTestResult { get; set; } = string.Empty;

[Reactive]
public string IPv6Address { get; set; } = string.Empty;

[Reactive]
public bool IsSupportIPv6 { get; set; }

public ReactiveCommand<Unit, NATFetchResult> NATCheckCommand { get; }

public ReactiveCommand<Unit, Unit> DNSCheckCommand { get; }

public ReactiveCommand<Unit, Unit> IPv6CheckCommand { get; }

public NetworkCheckControlViewModel()
{
SelectedSTUNAddress = STUNAddress[0];

NATCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var natCheckResult = await _networkTestService.TestStunClient3489Async(testServerHostName: SelectedSTUNAddress) ?? new ClassicStunResult { NatType = NatType.Unknown };
var (netSucc, _) = await _networkTestService.TestOpenUrlAsync("https://www.baidu.com");

var publicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown";
var localEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown";

var (natLevel, natTypeTip) = natCheckResult.NatType switch
{
// Open
NatType.OpenInternet or NatType.FullCone => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"),
// Moderate
NatType.RestrictedCone or NatType.PortRestrictedCone or NatType.SymmetricUdpFirewall => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"),
// Strict
NatType.Symmetric or NatType.UdpBlocked => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"),
// Unknown
NatType.Unknown or NatType.UnsupportedServer or _ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"),
};

return new NATFetchResult(publicEndPoint, localEndPoint, natLevel, natTypeTip, netSucc);
});
NATCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsNATChecking);
NATCheckCommand
.Select(x => x.PublicEndPoint)
.ToPropertyEx(this, x => x.PublicEndPoint);
NATCheckCommand
.Select(x => x.LocalEndPoint)
.ToPropertyEx(this, x => x.LocalEndPoint);
NATCheckCommand
.Select(x => x.NATLevel)
.Merge(Observable.Return("未知"))
.ToPropertyEx(this, x => x.NATLevel);
NATCheckCommand
.Select(x => x.NATTypeTip)
.Merge(Observable.Return("未知类型"))
.ToPropertyEx(this, x => x.NATTypeTip);

var hidePingResultStream = NATCheckCommand
.IsExecuting
.Where(x => x == true)
.Select(x => false);
NATCheckCommand
.Select(x => x.PingResult == true)
.Merge(hidePingResultStream)
.ToPropertyEx(this, x => x.PingOkVisible);
NATCheckCommand
.Select(x => x.PingResult == false)
.Merge(hidePingResultStream)
.ToPropertyEx(this, x => x.PingErrorVisible);

DNSCheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var testDomain = DomainPendingTest == string.Empty ? "store.steampowered.com" : DomainPendingTest;
try
{
long delayMs;
IPAddress[] address;
if (ProxySettings.UseDoh)
{
var configDoh = ProxySettings.CustomDohAddres2.Value ?? ProxySettingsWindowViewModel.DohAddress.FirstOrDefault() ?? string.Empty;
(delayMs, address) = await _networkTestService.TestDNSOverHttpsAsync(testDomain, configDoh);
}
else
{
var configDns = ProxySettings.ProxyMasterDns.Value ?? string.Empty;
(delayMs, address) = await _networkTestService.TestDNSAsync(testDomain, configDns, 53);
}
if (address.Length == 0)
throw new Exception("Parsing failed. Return empty ip address.");

DNSTestDelay = delayMs + "ms ";
DNSTestResult = string.Empty + address.FirstOrDefault();
}
catch (Exception ex)
{
Log.Error(nameof(AcceleratorPageViewModel), ex.ToString());
DNSTestDelay = string.Empty;
DNSTestResult = "error";
}
});
DNSCheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsDNSChecking);

IPv6CheckCommand = ReactiveCommand.CreateFromTask(async () =>
{
var result = await IMicroServiceClient.Instance.Accelerate.GetMyIP(ipV6: true);
if (result.IsSuccess)
{
IsSupportIPv6 = true;
IPv6Address = result.Content ?? string.Empty;
}
else
{
IsSupportIPv6 = false;
IPv6Address = string.Empty;
}
});
IPv6CheckCommand
.IsExecuting
.ToPropertyEx(this, x => x.IsIPv6Checking);

IPv6CheckCommand.Execute().Subscribe();
}
}
Loading

0 comments on commit e0c36a9

Please sign in to comment.