From 3ec726fed5ff29a4fc6416746ab8759beea34ff8 Mon Sep 17 00:00:00 2001 From: k1mlka Date: Wed, 25 Sep 2024 15:52:17 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=92=84=20=E7=BD=91=E7=BB=9C=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=AD=90=E9=A1=B5=E9=9D=A2NAT=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E9=83=A8=E5=88=86=E9=80=BB=E8=BE=91=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UI/ViewModels/AcceleratorPageViewModel.cs | 43 +++++++++++++++---- .../AcceleratorPageViewModel.props.cs | 34 +++++++++------ .../UI/Views/Controls/NetworkCheck.axaml | 4 +- .../UI/Views/Controls/NetworkCheck.axaml.cs | 19 ++++++-- .../UI/Views/Pages/AcceleratorPage2.axaml.cs | 25 +---------- 5 files changed, 73 insertions(+), 52 deletions(-) diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs index 8e67da5e5d0..927cb32128f 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs @@ -78,22 +78,47 @@ public AcceleratorPageViewModel() 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 + var publicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown"; + var localEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown"; + + var (natLevel, natTypeTip) = 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, + // 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 游戏的多人游戏。"), }; - PublicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown"; - LocalEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown"; - - return (natStatus, netSucc); + 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) + .ToPropertyEx(this, x => x.NATLevel); + NATCheckCommand + .Select(x => x.NATTypeTip) + .ToPropertyEx(this, x => x.NATTypeTip); + + var hidePingResultStream = NATCheckCommand + .IsExecuting + .Where(x => x == true) + .Select(x => PingStatus.Blank); + NATCheckCommand + .Select(x => x.PingResult == true ? PingStatus.Ok : PingStatus.Error) + .Merge(hidePingResultStream) + .ToPropertyEx(this, x => x.PingResultStatus); DNSCheckCommand = ReactiveCommand.CreateFromTask(async () => { diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs index 7ae8707dd4a..3ae539c4be7 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs @@ -4,12 +4,13 @@ namespace BD.WTTS.UI.ViewModels; public sealed partial class AcceleratorPageViewModel : TabItemViewModel { - public enum NatTypeSimple + public record NATFetchResult(string PublicEndPoint, string LocalEndPoint, string NATLevel, string NATTypeTip, bool PingResult); + + public enum PingStatus { - Unknown, - Open, - Moderate, - Strict, + Blank, + Ok, + Error, } public override string Name => Strings.Welcome; @@ -25,6 +26,21 @@ public enum NatTypeSimple "stun.miwifi.com", ]; + [ObservableAsProperty] + public string NATLevel { get; } = string.Empty; + + [ObservableAsProperty] + public string NATTypeTip { get; } = string.Empty; + + [ObservableAsProperty] + public string LocalEndPoint { get; set; } = string.Empty; + + [ObservableAsProperty] + public string PublicEndPoint { get; set; } = string.Empty; + + [ObservableAsProperty] + public PingStatus PingResultStatus { get; } + [ObservableAsProperty] public bool IsNATChecking { get; } @@ -40,12 +56,6 @@ public enum NatTypeSimple [Reactive] public ReadOnlyCollection? 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; @@ -58,7 +68,7 @@ public enum NatTypeSimple [Reactive] public bool IsSupportIPv6 { get; set; } - public ReactiveCommand NATCheckCommand { get; } + public ReactiveCommand NATCheckCommand { get; } public ReactiveCommand DNSCheckCommand { get; } diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml index 952f15c5adf..247b035553e 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml @@ -42,7 +42,6 @@ x:Name="NATCheckButton" Width="100" Margin="0,0,0,4" - x:FieldModifier="public" Command="{Binding NATCheckCommand}" Content="检测" IsEnabled="True" /> @@ -126,13 +125,12 @@ - + { public NetworkCheck() { InitializeComponent(); + + Loaded += (_, _) => + { + ViewModel = DataContext as AcceleratorPageViewModel; + + this.OneWayBind(ViewModel, vm => vm.PingResultStatus, v => v.PingOK.IsVisible, result => result == AcceleratorPageViewModel.PingStatus.Ok); + this.OneWayBind(ViewModel, vm => vm.PingResultStatus, v => v.PingError.IsVisible, result => result == AcceleratorPageViewModel.PingStatus.Error); + this.OneWayBind(ViewModel, vm => vm.NATLevel, v => v.NATTextBlock.Text); + this.OneWayBind(ViewModel, vm => vm.NATTypeTip, v => v.NATTypeTip.Text); + }; } + + public AcceleratorPageViewModel? ViewModel { get; set; } + + object? IViewFor.ViewModel { get; set; } } \ No newline at end of file diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs index ebf109666a8..0c0c883f9f7 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs @@ -74,30 +74,7 @@ public AcceleratorPage2() AcceleratorTabs.SelectedIndex = 0; } - NetworkCheckControl.PingOK.IsVisible = false; - NetworkCheckControl.PingError.IsVisible = false; - NetworkCheckControl.NATCheckButton.Click += (_, _) => NetworkCheckControl.PingError.IsVisible = NetworkCheckControl.PingOK.IsVisible = false; - ViewModel!.NATCheckCommand - .Subscribe(result => - { - (NetworkCheckControl.NATTextBlock.Text, NetworkCheckControl.NATTypeTip.Text) = result.Nat switch - { - AcceleratorPageViewModel.NatTypeSimple.Open => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"), - AcceleratorPageViewModel.NatTypeSimple.Moderate => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"), - AcceleratorPageViewModel.NatTypeSimple.Strict => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"), - _ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"), - }; - - if (result.PingSuccess) - { - NetworkCheckControl.PingOK.IsVisible = true; - } - else - { - NetworkCheckControl.PingError.IsVisible = true; - } - }).DisposeWith(disposables); - ViewModel.IPv6CheckCommand.Execute().Subscribe(); + ViewModel!.IPv6CheckCommand.Execute().Subscribe(); }); SearchGameBox.DropDownClosed += SearchGameBox_DropDownClosed; From f6b4e0298a6fd380c52829a0cedaa63a03d17ba7 Mon Sep 17 00:00:00 2001 From: k1mlka Date: Wed, 25 Sep 2024 15:52:17 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=92=84=20=E7=BD=91=E7=BB=9C=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=AD=90=E9=A1=B5=E9=9D=A2NAT=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E9=83=A8=E5=88=86=E9=80=BB=E8=BE=91=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UI/ViewModels/AcceleratorPageViewModel.cs | 43 +++++++++++++++---- .../AcceleratorPageViewModel.props.cs | 34 +++++++++------ .../UI/Views/Controls/NetworkCheck.axaml | 4 +- .../UI/Views/Controls/NetworkCheck.axaml.cs | 19 ++++++-- .../UI/Views/Pages/AcceleratorPage2.axaml.cs | 25 +---------- 5 files changed, 73 insertions(+), 52 deletions(-) diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs index 8e67da5e5d0..927cb32128f 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs @@ -78,22 +78,47 @@ public AcceleratorPageViewModel() 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 + var publicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown"; + var localEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown"; + + var (natLevel, natTypeTip) = 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, + // 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 游戏的多人游戏。"), }; - PublicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown"; - LocalEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown"; - - return (natStatus, netSucc); + 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) + .ToPropertyEx(this, x => x.NATLevel); + NATCheckCommand + .Select(x => x.NATTypeTip) + .ToPropertyEx(this, x => x.NATTypeTip); + + var hidePingResultStream = NATCheckCommand + .IsExecuting + .Where(x => x == true) + .Select(x => PingStatus.Blank); + NATCheckCommand + .Select(x => x.PingResult == true ? PingStatus.Ok : PingStatus.Error) + .Merge(hidePingResultStream) + .ToPropertyEx(this, x => x.PingResultStatus); DNSCheckCommand = ReactiveCommand.CreateFromTask(async () => { diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs index 7ae8707dd4a..378b13cec8b 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs @@ -4,12 +4,13 @@ namespace BD.WTTS.UI.ViewModels; public sealed partial class AcceleratorPageViewModel : TabItemViewModel { - public enum NatTypeSimple + public record NATFetchResult(string PublicEndPoint, string LocalEndPoint, string NATLevel, string NATTypeTip, bool PingResult); + + public enum PingStatus { - Unknown, - Open, - Moderate, - Strict, + Blank, + Ok, + Error, } public override string Name => Strings.Welcome; @@ -25,6 +26,21 @@ public enum NatTypeSimple "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 PingStatus PingResultStatus { get; } + [ObservableAsProperty] public bool IsNATChecking { get; } @@ -40,12 +56,6 @@ public enum NatTypeSimple [Reactive] public ReadOnlyCollection? 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; @@ -58,7 +68,7 @@ public enum NatTypeSimple [Reactive] public bool IsSupportIPv6 { get; set; } - public ReactiveCommand NATCheckCommand { get; } + public ReactiveCommand NATCheckCommand { get; } public ReactiveCommand DNSCheckCommand { get; } diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml index 952f15c5adf..247b035553e 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml @@ -42,7 +42,6 @@ x:Name="NATCheckButton" Width="100" Margin="0,0,0,4" - x:FieldModifier="public" Command="{Binding NATCheckCommand}" Content="检测" IsEnabled="True" /> @@ -126,13 +125,12 @@ - + { public NetworkCheck() { InitializeComponent(); + + Loaded += (_, _) => + { + ViewModel = DataContext as AcceleratorPageViewModel; + + this.OneWayBind(ViewModel, vm => vm.PingResultStatus, v => v.PingOK.IsVisible, result => result == AcceleratorPageViewModel.PingStatus.Ok); + this.OneWayBind(ViewModel, vm => vm.PingResultStatus, v => v.PingError.IsVisible, result => result == AcceleratorPageViewModel.PingStatus.Error); + this.OneWayBind(ViewModel, vm => vm.NATLevel, v => v.NATTextBlock.Text); + this.OneWayBind(ViewModel, vm => vm.NATTypeTip, v => v.NATTypeTip.Text); + }; } + + public AcceleratorPageViewModel? ViewModel { get; set; } + + object? IViewFor.ViewModel { get; set; } } \ No newline at end of file diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs index ebf109666a8..0c0c883f9f7 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs @@ -74,30 +74,7 @@ public AcceleratorPage2() AcceleratorTabs.SelectedIndex = 0; } - NetworkCheckControl.PingOK.IsVisible = false; - NetworkCheckControl.PingError.IsVisible = false; - NetworkCheckControl.NATCheckButton.Click += (_, _) => NetworkCheckControl.PingError.IsVisible = NetworkCheckControl.PingOK.IsVisible = false; - ViewModel!.NATCheckCommand - .Subscribe(result => - { - (NetworkCheckControl.NATTextBlock.Text, NetworkCheckControl.NATTypeTip.Text) = result.Nat switch - { - AcceleratorPageViewModel.NatTypeSimple.Open => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"), - AcceleratorPageViewModel.NatTypeSimple.Moderate => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"), - AcceleratorPageViewModel.NatTypeSimple.Strict => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"), - _ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"), - }; - - if (result.PingSuccess) - { - NetworkCheckControl.PingOK.IsVisible = true; - } - else - { - NetworkCheckControl.PingError.IsVisible = true; - } - }).DisposeWith(disposables); - ViewModel.IPv6CheckCommand.Execute().Subscribe(); + ViewModel!.IPv6CheckCommand.Execute().Subscribe(); }); SearchGameBox.DropDownClosed += SearchGameBox_DropDownClosed; From 4c976ab6ea96e90b724219b95eabde064f8a499e Mon Sep 17 00:00:00 2001 From: k1mlka Date: Wed, 25 Sep 2024 17:49:23 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=92=84=20=E7=BD=91=E7=BB=9C=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=AD=90=E9=A1=B5=E9=9D=A2ViewModel=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UI/ViewModels/AcceleratorPageViewModel.cs | 104 +--------- .../AcceleratorPageViewModel.props.cs | 65 ------ .../NetworkCheckControlViewModel.cs | 190 ++++++++++++++++++ .../UI/Views/Controls/NetworkCheck.axaml | 11 +- .../UI/Views/Controls/NetworkCheck.axaml.cs | 16 +- .../UI/Views/Pages/AcceleratorPage2.axaml | 2 +- .../UI/Views/Pages/AcceleratorPage2.axaml.cs | 2 - 7 files changed, 200 insertions(+), 190 deletions(-) create mode 100644 src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs index 927cb32128f..6dfa6ee71c5 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs @@ -8,12 +8,13 @@ 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() { @@ -71,107 +72,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 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) - .ToPropertyEx(this, x => x.NATLevel); - NATCheckCommand - .Select(x => x.NATTypeTip) - .ToPropertyEx(this, x => x.NATTypeTip); - - var hidePingResultStream = NATCheckCommand - .IsExecuting - .Where(x => x == true) - .Select(x => PingStatus.Blank); - NATCheckCommand - .Select(x => x.PingResult == true ? PingStatus.Ok : PingStatus.Error) - .Merge(hidePingResultStream) - .ToPropertyEx(this, x => x.PingResultStatus); - - 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(); diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs index 378b13cec8b..d0c4bf29fa9 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.props.cs @@ -4,76 +4,11 @@ namespace BD.WTTS.UI.ViewModels; public sealed partial class AcceleratorPageViewModel : TabItemViewModel { - public record NATFetchResult(string PublicEndPoint, string LocalEndPoint, string NATLevel, string NATTypeTip, bool PingResult); - - public enum PingStatus - { - Blank, - Ok, - Error, - } - 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 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 PingStatus PingResultStatus { 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 ReadOnlyCollection? EnableProxyDomainGroupVMs { get; set; } - [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 NATCheckCommand { get; } - - public ReactiveCommand DNSCheckCommand { get; } - - public ReactiveCommand IPv6CheckCommand { get; } - public ICommand StartProxyCommand { get; } public ICommand RefreshCommand { get; } diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs new file mode 100644 index 00000000000..1d5d8323f00 --- /dev/null +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs @@ -0,0 +1,190 @@ +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); + + public enum PingStatus + { + Blank, + Ok, + Error, + } + + [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 NATCheckCommand { get; } + + public ReactiveCommand DNSCheckCommand { get; } + + public ReactiveCommand 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(); + } +} \ No newline at end of file diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml index 247b035553e..dd217d38212 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Controls/NetworkCheck.axaml @@ -11,7 +11,7 @@ xmlns:ui="using:FluentAvalonia.UI.Controls" d:DesignHeight="450" d:DesignWidth="800" - x:DataType="spp:AcceleratorPageViewModel" + x:DataType="spp:NetworkCheckControlViewModel" mc:Ignorable="d"> + Text="{Binding NATLevel}" /> - + @@ -128,9 +128,10 @@ FontFamily="{StaticResource SymbolThemeFontFamily}" FontSize="26" Foreground="Green" - Glyph="" /> + Glyph="" + IsVisible="{Binding PingOkVisible}" /> - + +public partial class NetworkCheck : UserControl { public NetworkCheck() { InitializeComponent(); - - Loaded += (_, _) => - { - ViewModel = DataContext as AcceleratorPageViewModel; - - this.OneWayBind(ViewModel, vm => vm.PingResultStatus, v => v.PingOK.IsVisible, result => result == AcceleratorPageViewModel.PingStatus.Ok); - this.OneWayBind(ViewModel, vm => vm.PingResultStatus, v => v.PingError.IsVisible, result => result == AcceleratorPageViewModel.PingStatus.Error); - this.OneWayBind(ViewModel, vm => vm.NATLevel, v => v.NATTextBlock.Text); - this.OneWayBind(ViewModel, vm => vm.NATTypeTip, v => v.NATTypeTip.Text); - }; } - - public AcceleratorPageViewModel? ViewModel { get; set; } - - object? IViewFor.ViewModel { get; set; } } \ No newline at end of file diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml index e286f1c7aee..7315660509e 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml @@ -648,7 +648,7 @@ - + diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs index 0c0c883f9f7..441eef8035b 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/Views/Pages/AcceleratorPage2.axaml.cs @@ -73,8 +73,6 @@ public AcceleratorPage2() GameAccTab.IsVisible = false; AcceleratorTabs.SelectedIndex = 0; } - - ViewModel!.IPv6CheckCommand.Execute().Subscribe(); }); SearchGameBox.DropDownClosed += SearchGameBox_DropDownClosed; From 2c82d413892533d815774f04877554dc3821beb1 Mon Sep 17 00:00:00 2001 From: k1mlka Date: Wed, 25 Sep 2024 18:01:49 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=92=84=E4=BB=A3=E7=A0=81Clean?= =?UTF-8?q?=EF=BC=8C=E6=B2=A1=E6=9C=89=E5=BC=95=E7=94=A8=E5=88=B0=E7=9A=84?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E7=A9=BA=E9=97=B4=E4=B8=8E=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UI/ViewModels/AcceleratorPageViewModel.cs | 5 +---- .../UI/ViewModels/NetworkCheckControlViewModel.cs | 7 ------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs index 6dfa6ee71c5..2dd74a1e1f6 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/AcceleratorPageViewModel.cs @@ -1,8 +1,5 @@ -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; diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs index 1d5d8323f00..ab7c574cb6a 100644 --- a/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs +++ b/src/BD.WTTS.Client.Plugins.Accelerator/UI/ViewModels/NetworkCheckControlViewModel.cs @@ -10,13 +10,6 @@ public class NetworkCheckControlViewModel : ViewModelBase public record NATFetchResult(string PublicEndPoint, string LocalEndPoint, string NATLevel, string NATTypeTip, bool PingResult); - public enum PingStatus - { - Blank, - Ok, - Error, - } - [Reactive] public string SelectedSTUNAddress { get; set; }