Skip to content

Commit a271bd2

Browse files
authored
Merge branch 'main' into feat/hint
2 parents 9fa1841 + 7ef1473 commit a271bd2

File tree

7 files changed

+139
-15
lines changed

7 files changed

+139
-15
lines changed

.github/workflows/reusable_build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ jobs:
2222
uses: actions/checkout@v4
2323

2424
- name: Setup .NET SDK
25-
uses: actions/setup-dotnet@v4
25+
uses: actions/setup-dotnet@v5
2626
with:
27-
dotnet-version: '9.0.x'
27+
dotnet-version: '10.0.x'
2828

2929
- name: Build
3030
env:

App/Config.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,6 @@ public static partial class Config
4848
/// </summary>
4949
[ConfigItem<bool>("HintHandInstall", false)] public partial bool ManualInstall { get; set; }
5050

51-
/// <summary>
52-
/// 购买正版提示。
53-
/// </summary>
54-
[ConfigItem<bool>("HintBuy", false)] public partial bool BuyGame { get; set; }
55-
5651
/// <summary>
5752
/// 清理垃圾提示。
5853
/// </summary>
@@ -285,6 +280,12 @@ public static partial class Config
285280
[ConfigItem<string>("SystemHttpProxyCustomPassword", "")] public partial string CustomPassword { get; set; }
286281
}
287282

283+
[ConfigGroup("NetworkConfig")]
284+
partial class NetworkConfigGroup
285+
{
286+
[ConfigItem<bool>("SystemNetEnableDoH", true)] public partial bool EnableDoH { get; set; }
287+
}
288+
288289
[ConfigGroup("Debug")] partial class DebugConfigGroup
289290
{
290291
[ConfigItem<bool>("SystemDebugMode", false)] public partial bool Enabled { get; set; }

Link/McPing.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ private byte[] _BuildHandshakePacket(string serverIp, int serverPort)
226226
if (binaryIp.Length > 255) throw new Exception("服务器地址过长");
227227
handshake.AddRange(VarIntHelper.Encode((uint)binaryIp.Length)); //服务器地址长度
228228
handshake.AddRange(binaryIp); //服务器地址
229-
handshake.AddRange(BitConverter.GetBytes((ushort)serverPort).Reverse()); //服务器端口
229+
handshake.AddRange(BitConverter.GetBytes((ushort)serverPort).AsEnumerable().Reverse()); //服务器端口
230230
handshake.AddRange(VarIntHelper.Encode(1)); //1 表明当前状态为 ping 2 表明当前的状态为连接
231231

232232
handshake.InsertRange(0, VarIntHelper.Encode((uint)handshake.Count)); //包长度

Net/HostConnectionHandler.cs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Net.Http;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using System.Net.Sockets;
9+
using Ae.Dns.Client;
10+
using Ae.Dns.Protocol;
11+
using Ae.Dns.Protocol.Enums;
12+
using Ae.Dns.Protocol.Records;
13+
using PCL.Core.Logging;
14+
using System.Runtime.Caching;
15+
16+
namespace PCL.Core.Net;
17+
18+
public class HostConnectionHandler
19+
{
20+
public static HostConnectionHandler Instance { get; } = new();
21+
private const string ModuleName = "DoH";
22+
23+
private static IDnsClient? _resolver;
24+
25+
private HostConnectionHandler()
26+
{
27+
// 使用Ae.Dns创建DoH客户端,支持多个DoH服务器
28+
IDnsClient[] clients =
29+
[
30+
new DnsHttpClient(new HttpClient()
31+
{
32+
BaseAddress = new Uri("https://doh.pub/")
33+
}),
34+
new DnsHttpClient(new HttpClient()
35+
{
36+
BaseAddress = new Uri("https://doh.pysio.online/")
37+
}),
38+
new DnsHttpClient(new HttpClient()
39+
{
40+
BaseAddress = new Uri("https://cloudflare-dns.com/")
41+
})
42+
];
43+
44+
// 使用DnsRacerClient实现快速获胜策略
45+
_resolver = new DnsCachingClient(new DnsRacerClient(clients), new MemoryCache("DNS Query Cache"));
46+
}
47+
48+
public async ValueTask<Stream> GetConnectionAsync(SocketsHttpConnectionContext context, CancellationToken cts)
49+
{
50+
ArgumentNullException.ThrowIfNull(_resolver, "_resolver != null");
51+
// 获取主机名和端口
52+
var host = context.DnsEndPoint.Host;
53+
var port = context.DnsEndPoint.Port;
54+
55+
// 使用Ae.Dns解析IPv4和IPv6地址
56+
57+
var queryA = _resolver.Query(DnsQueryFactory.CreateQuery(host), cts);
58+
var queryAAAA = _resolver.Query(DnsQueryFactory.CreateQuery(host, DnsQueryType.AAAA), cts);
59+
60+
var resolveTasks = new List<Task<DnsMessage>>()
61+
{
62+
queryA,
63+
queryAAAA
64+
};
65+
66+
var results = await Task.WhenAll(resolveTasks).ConfigureAwait(false);
67+
var addresses = (from result in results
68+
from answer in result.Answers
69+
where answer.Resource is DnsIpAddressResource
70+
select ((answer.Resource as DnsIpAddressResource)!).IPAddress).ToArray();
71+
72+
if (addresses.Length == 0)
73+
throw new HttpRequestException($"No IP address for {host}");
74+
75+
// 并行连接所有地址,返回第一个成功的连接
76+
var connectionTasks = addresses.Select(ip => _ConnectToAddressAsync(ip.ToString(), port, cts)).ToList();
77+
78+
try
79+
{
80+
var completedTask = await Task.WhenAny(connectionTasks).ConfigureAwait(false);
81+
var stream = await completedTask.ConfigureAwait(false);
82+
83+
// 取消其他连接任务
84+
foreach (var task in connectionTasks.Where(task => task != completedTask))
85+
{
86+
_ = task.ContinueWith(t => {
87+
if (t.IsCompletedSuccessfully)
88+
{
89+
t.Result?.Dispose();
90+
}
91+
}, cts);
92+
}
93+
94+
LogWrapper.Debug(ModuleName, $"Success resolve DoH endpoint: {host} -> {stream.Socket.RemoteEndPoint}");
95+
return stream;
96+
}
97+
catch
98+
{
99+
throw new HttpRequestException($"No address reachable: {host} -> {string.Join(", ", addresses.Select(x => x.ToString()))}");
100+
}
101+
}
102+
103+
private static async Task<NetworkStream> _ConnectToAddressAsync(string ip, int port, CancellationToken cts)
104+
{
105+
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
106+
try
107+
{
108+
using var ctsSocket = CancellationTokenSource.CreateLinkedTokenSource(cts);
109+
ctsSocket.CancelAfter(5000); // 5秒超时
110+
111+
await socket.ConnectAsync(ip, port, ctsSocket.Token);
112+
return new NetworkStream(socket, ownsSocket: true);
113+
}
114+
catch
115+
{
116+
socket.Dispose();
117+
throw;
118+
}
119+
}
120+
}

Net/NetworkService.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Threading.Tasks;
44
using Microsoft.Extensions.DependencyInjection;
55
using System;
6+
using System.Net.Security;
67
using System.Security.Authentication;
78
using PCL.Core.App;
89
using PCL.Core.Logging;
@@ -21,16 +22,17 @@ private NetworkService() : base("network", "网络服务") {}
2122
public override void Start()
2223
{
2324
var services = new ServiceCollection();
24-
services.AddHttpClient("default").ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
25+
services.AddHttpClient("default").ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
2526
{
2627
UseProxy = true,
27-
AutomaticDecompression = DecompressionMethods.All, //在这里添加 None 的给我重学二进制去 😡
28-
SslProtocols = SslProtocols.None,
28+
AutomaticDecompression = DecompressionMethods.All,
2929
Proxy = HttpProxyManager.Instance,
3030
AllowAutoRedirect = true,
3131
MaxAutomaticRedirections = 25,
3232
UseCookies = false, //禁止自动 Cookie 管理
33-
MaxConnectionsPerServer = 64,
33+
ConnectCallback = Config.System.NetworkConfig.EnableDoH
34+
? HostConnectionHandler.Instance.GetConnectionAsync
35+
: null
3436
}
3537
);
3638
_provider = services.BuildServiceProvider();

PCL.Core.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<UseWPF>true</UseWPF>
2222
<EnableWindowsTargeting>true</EnableWindowsTargeting>
2323
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
24-
<LangVersion>13.0</LangVersion>
24+
<LangVersion>14.0</LangVersion>
2525
<Nullable>enable</Nullable>
2626
<ErrorReport>prompt</ErrorReport>
2727
<WarningLevel>4</WarningLevel>
@@ -39,12 +39,13 @@
3939
<PropertyGroup Condition="'$(Configuration)' == 'Beta' Or '$(Configuration)' == 'Release' Or '$(Configuration)' == 'Publish'">
4040
<DebugType>none</DebugType>
4141
<Optimize>true</Optimize>
42-
<DefineConstants Condition="'$(Configuration)' == 'Release'">RELEASE;PUBLISH</DefineConstants>
42+
<DefineConstants Condition="'$(Configuration)' == 'Release' Or '$(Configuration)' == 'Publish'">RELEASE;PUBLISH</DefineConstants>
4343
<DefineConstants Condition="'$(Configuration)' == 'Beta'">BETA;PUBLISH</DefineConstants>
4444
</PropertyGroup>
4545
<!-- NuGet 引用 -->
4646
<ItemGroup>
4747
<!-- WPF Behaviors -->
48+
<PackageReference Include="Ae.Dns.Client" Version="3.1.0" />
4849
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
4950
<!-- 语言和系统特性 -->
5051
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" PrivateAssets="all" />

UI/Controls/MotdRenderer.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
mc:Ignorable="d">
7-
<Canvas x:Name="MotdCanvas" IsHitTestVisible="False" HorizontalAlignment="Center" Width="300" Height="34"/>
7+
<Canvas x:Name="MotdCanvas" IsHitTestVisible="False" HorizontalAlignment="Center" Width="350" Height="34"/>
88
</UserControl>

0 commit comments

Comments
 (0)