Skip to content

Commit b7e31d1

Browse files
authored
Merge pull request #3461 from BeyondDimension/feature/networktestservice
Feature/networktestservice
2 parents 3574725 + 1d0b168 commit b7e31d1

File tree

21 files changed

+1479
-146
lines changed

21 files changed

+1479
-146
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
using Avalonia.Reactive;
2+
using Avalonia.Xaml.Interactions.Responsive;
3+
using Avalonia.Xaml.Interactivity;
4+
5+
namespace BD.WTTS.Behaviors;
6+
7+
/// <summary>
8+
/// Observes <see cref="Behavior{T}.AssociatedObject"/> control or <see cref="SourceControl"/> control <see cref="Visual.Bounds"/> property changes and if triggered sets or removes style classes when conditions from <see cref="AdaptiveClassSetter"/> are met.
9+
/// </summary>
10+
public class AdaptiveBehavior : Behavior<Control>
11+
{
12+
private IDisposable? _disposable;
13+
private AvaloniaList<AdaptiveClassSetter>? _setters;
14+
15+
/// <summary>
16+
/// Identifies the <seealso cref="SourceControl"/> avalonia property.
17+
/// </summary>
18+
public static readonly StyledProperty<Control?> SourceControlProperty =
19+
AvaloniaProperty.Register<AdaptiveBehavior, Control?>(nameof(SourceControl));
20+
21+
/// <summary>
22+
/// Identifies the <seealso cref="TargetControl"/> avalonia property.
23+
/// </summary>
24+
public static readonly StyledProperty<Control?> TargetControlProperty =
25+
AvaloniaProperty.Register<AdaptiveBehavior, Control?>(nameof(TargetControl));
26+
27+
/// <summary>
28+
/// Identifies the <seealso cref="Setters"/> avalonia property.
29+
/// </summary>
30+
public static readonly DirectProperty<AdaptiveBehavior, AvaloniaList<AdaptiveClassSetter>> SettersProperty =
31+
AvaloniaProperty.RegisterDirect<AdaptiveBehavior, AvaloniaList<AdaptiveClassSetter>>(nameof(Setters), t => t.Setters);
32+
33+
/// <summary>
34+
/// Gets or sets the the source control that <see cref="Visual.BoundsProperty"/> property are observed from, if not set <see cref="Behavior{T}.AssociatedObject"/> is used. This is a avalonia property.
35+
/// </summary>
36+
[ResolveByName]
37+
public Control? SourceControl
38+
{
39+
get => GetValue(SourceControlProperty);
40+
set => SetValue(SourceControlProperty, value);
41+
}
42+
43+
/// <summary>
44+
/// Gets or sets the target control that class name that should be added or removed when triggered, if not set <see cref="Behavior{T}.AssociatedObject"/> is used or <see cref="AdaptiveClassSetter.TargetControl"/> from <see cref="AdaptiveClassSetter"/>. This is a avalonia property.
45+
/// </summary>
46+
[ResolveByName]
47+
public Control? TargetControl
48+
{
49+
get => GetValue(TargetControlProperty);
50+
set => SetValue(TargetControlProperty, value);
51+
}
52+
53+
/// <summary>
54+
/// Gets adaptive class setters collection. This is a avalonia property.
55+
/// </summary>
56+
[Content]
57+
public AvaloniaList<AdaptiveClassSetter> Setters => _setters ??= new AvaloniaList<AdaptiveClassSetter>();
58+
59+
/// <inheritdoc/>
60+
protected override void OnAttachedToVisualTree()
61+
{
62+
base.OnAttachedToVisualTree();
63+
64+
StopObserving();
65+
StartObserving();
66+
}
67+
68+
/// <inheritdoc/>
69+
protected override void OnDetachedFromVisualTree()
70+
{
71+
base.OnDetachedFromVisualTree();
72+
73+
StopObserving();
74+
}
75+
76+
private void StartObserving()
77+
{
78+
var sourceControl = GetValue(SourceControlProperty) is not null
79+
? SourceControl
80+
: AssociatedObject;
81+
82+
if (sourceControl is not null)
83+
{
84+
_disposable = ObserveBounds(sourceControl);
85+
}
86+
}
87+
88+
private void StopObserving()
89+
{
90+
_disposable?.Dispose();
91+
}
92+
93+
private IDisposable ObserveBounds(Control sourceControl)
94+
{
95+
if (sourceControl is null)
96+
{
97+
throw new ArgumentNullException(nameof(sourceControl));
98+
}
99+
100+
return sourceControl.GetObservable(Visual.BoundsProperty)
101+
.Subscribe(new AnonymousObserver<Rect>(bounds => ValueChanged(sourceControl, Setters, bounds)));
102+
}
103+
104+
private void ValueChanged(Control? sourceControl, AvaloniaList<AdaptiveClassSetter>? setters, Rect bounds)
105+
{
106+
if (sourceControl is null || setters is null)
107+
{
108+
return;
109+
}
110+
111+
foreach (var setter in setters)
112+
{
113+
var isMinOrMaxWidthSet = setter.IsSet(AdaptiveClassSetter.MinWidthProperty)
114+
|| setter.IsSet(AdaptiveClassSetter.MaxWidthProperty);
115+
var widthConditionTriggered = GetResult(setter.MinWidthOperator, bounds.Width, setter.MinWidth)
116+
&& GetResult(setter.MaxWidthOperator, bounds.Width, setter.MaxWidth);
117+
118+
var isMinOrMaxHeightSet = setter.IsSet(AdaptiveClassSetter.MinHeightProperty)
119+
|| setter.IsSet(AdaptiveClassSetter.MaxHeightProperty);
120+
var heightConditionTriggered = GetResult(setter.MinHeightOperator, bounds.Height, setter.MinHeight)
121+
&& GetResult(setter.MaxHeightOperator, bounds.Height, setter.MaxHeight);
122+
123+
var isAddClassTriggered = isMinOrMaxWidthSet switch
124+
{
125+
true when !isMinOrMaxHeightSet => widthConditionTriggered,
126+
false when isMinOrMaxHeightSet => heightConditionTriggered,
127+
true when isMinOrMaxHeightSet => widthConditionTriggered && heightConditionTriggered,
128+
_ => false
129+
};
130+
131+
var targetControl = setter.GetValue(AdaptiveClassSetter.TargetControlProperty) is not null
132+
? setter.TargetControl
133+
: GetValue(TargetControlProperty) is not null
134+
? TargetControl
135+
: AssociatedObject;
136+
137+
if (targetControl is not null)
138+
{
139+
var className = setter.ClassName;
140+
var isPseudoClass = setter.IsPseudoClass;
141+
142+
if (isAddClassTriggered)
143+
{
144+
Add(targetControl, className, isPseudoClass);
145+
}
146+
else
147+
{
148+
Remove(targetControl, className, isPseudoClass);
149+
}
150+
}
151+
}
152+
}
153+
154+
private bool GetResult(ComparisonConditionType comparisonConditionType, double property, double value)
155+
{
156+
return comparisonConditionType switch
157+
{
158+
// ReSharper disable once CompareOfFloatsByEqualityOperator
159+
ComparisonConditionType.Equal => property == value,
160+
// ReSharper disable once CompareOfFloatsByEqualityOperator
161+
ComparisonConditionType.NotEqual => property != value,
162+
ComparisonConditionType.LessThan => property < value,
163+
ComparisonConditionType.LessThanOrEqual => property <= value,
164+
ComparisonConditionType.GreaterThan => property > value,
165+
ComparisonConditionType.GreaterThanOrEqual => property >= value,
166+
_ => throw new ArgumentOutOfRangeException()
167+
};
168+
}
169+
170+
private static void Add(Control targetControl, string? className, bool isPseudoClass)
171+
{
172+
if (className is null || string.IsNullOrEmpty(className) || targetControl.Classes.Contains(className))
173+
{
174+
return;
175+
}
176+
177+
if (isPseudoClass)
178+
{
179+
((IPseudoClasses)targetControl.Classes).Add(className);
180+
}
181+
else
182+
{
183+
targetControl.Classes.Add(className);
184+
}
185+
}
186+
187+
private static void Remove(Control targetControl, string? className, bool isPseudoClass)
188+
{
189+
if (className is null || string.IsNullOrEmpty(className) || !targetControl.Classes.Contains(className))
190+
{
191+
return;
192+
}
193+
194+
if (isPseudoClass)
195+
{
196+
((IPseudoClasses)targetControl.Classes).Remove(className);
197+
}
198+
else
199+
{
200+
targetControl.Classes.Remove(className);
201+
}
202+
}
203+
}

src/BD.WTTS.Client.Avalonia/Properties/AssemblyInfo.Xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.UI.Views.Windows")]
1212
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Converters")]
1313
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Markup")]
14+
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Behaviors")]
1415
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Services")]
1516
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Plugins")]
1617
[assembly: XmlnsDefinition("https://steampp.net/services", "BD.WTTS.Plugins.Abstractions")]

src/BD.WTTS.Client.Avalonia/UI/Styling/Controls/PageBase.axaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
</Design.PreviewWith>
9898

9999
<Styles.Resources>
100-
<Thickness x:Key="AppPageMargin">20</Thickness>
100+
<Thickness x:Key="AppPageMargin">20,10,20,20</Thickness>
101101
</Styles.Resources>
102102

103103
<Style Selector="spp|PageBase">
@@ -313,7 +313,7 @@
313313
<Setter Property="Grid.Row" Value="2" />
314314
<Setter Property="VerticalAlignment" Value="Center" />
315315
<Setter Property="HorizontalAlignment" Value="Center" />
316-
<Setter Property="Margin" Value="0 12" />
316+
<Setter Property="Margin" Value="0 12 0 0" />
317317
</Style>
318318

319319
<Style Selector="^ /template/ Panel#PageDetails">

src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/Net/IDnsAnalysisService.Constants.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ public partial interface IDnsAnalysisService // 公共常量定义
88
{
99
#region DNS 常量
1010

11-
const string DNS_Ali_DohAddres = "https://dns.alidns.com";
12-
const string DNS_Ali_DohAddres2 = "https://223.6.6.6/dns-query";
13-
const string DNS_Ali_DohAddres3 = "https://223.5.5.5/dns-query";
11+
const string DNS_Ali_DohAddres = "https://dns.alidns.com/resolve";
12+
const string DNS_Ali_DohAddres2 = "https://223.6.6.6/resolve";
13+
const string DNS_Ali_DohAddres3 = "https://223.5.5.5/resolve";
1414

15-
const string Dnspod_DohAddres = "https://1.12.12.12/dns-query";
16-
const string Dnspod_DohAddres2 = "https://doh.pub/dns-query";
17-
const string Dnspod_DohAddres3 = "https://120.53.53.53/dns-query";
15+
const string Dnspod_DohAddres = "https://1.12.12.12/resolve";
16+
const string Dnspod_DohAddres2 = "https://doh.pub/resolve";
17+
const string Dnspod_DohAddres3 = "https://120.53.53.53/resolve";
1818

19-
const string Google_DohAddres = "https://dns.google";
20-
const string Cloudflare_DohAddres = "https://cloudflare-dns.com";
21-
const string DohAddres_360 = "https://doh.360.cn/dns-query";
22-
const string TUNA_DohAddres = "https://101.6.6.6:8443/dns-query";
19+
const string Google_DohAddres = "https://dns.google/resolve";
20+
const string Cloudflare_DohAddres = "https://cloudflare-dns.com/resolve";
21+
const string DohAddres_360 = "https://doh.360.cn/resolve";
22+
const string TUNA_DohAddres = "https://101.6.6.6:8443/resolve";
2323

2424
const string PrimaryDNS_IPV6_Ali = "2400:3200::1";
2525

@@ -60,5 +60,5 @@ private static class NameServer
6060
public static readonly IPEndPoint Cloudflare2 = new(IPAddress.Parse("1.0.0.1"), 53);
6161
}
6262

63-
#endregion
63+
#endregion DNS 常量
6464
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace BD.WTTS.Enums;
2+
3+
/// <summary>
4+
/// 网络环境检查步骤
5+
/// </summary>
6+
public enum NetworkEnvCheckStep
7+
{
8+
/// <summary>
9+
/// Hosts文件检查
10+
/// </summary>
11+
HostsFileCheck = 1,
12+
13+
/// <summary>
14+
/// 网卡检查
15+
/// </summary>
16+
NetworkInterfaceCheck = 2,
17+
18+
/// <summary>
19+
/// LSP检查
20+
/// </summary>
21+
LSPCheck = 3
22+
}

src/BD.WTTS.Client.Plugins.Accelerator/Plugins/Plugin.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ public override void ConfigureDemandServices(IServiceCollection services, Startu
6666
services.AddSingleton(_ => certificateManager.Task.GetAwaiter().GetResult());
6767
#endif
6868
}
69+
70+
services.AddSingleton<INetworkTestService, NetworkTestService>();
71+
6972
//if (startup.HasIPCRoot)
7073
//{
7174
// services.AddSingleton<IAcceleratorService, BackendAcceleratorServiceImpl>();

0 commit comments

Comments
 (0)