From 34653a754f067c4cac103398d90d135bd5e1111f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E4=B9=9D?= <366193849@qq.com> Date: Thu, 18 Nov 2021 22:58:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E4=BF=9D=E5=AD=98dns?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.DomainResolve/DomainResolver.cs | 102 ++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/FastGithub.DomainResolve/DomainResolver.cs b/FastGithub.DomainResolve/DomainResolver.cs index ea8313a..d4ac96f 100644 --- a/FastGithub.DomainResolve/DomainResolver.cs +++ b/FastGithub.DomainResolve/DomainResolver.cs @@ -3,9 +3,11 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Runtime.CompilerServices; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -16,7 +18,18 @@ namespace FastGithub.DomainResolve /// sealed class DomainResolver : IDomainResolver { + private record EndPointItem(string Host, int Port); + private static readonly string dnsEndpointFile = "dnsendpoints.json"; + private static readonly SemaphoreSlim dnsEndpointLocker = new(1, 1); + private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions + { + WriteIndented = true, + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + private readonly DnsClient dnsClient; + private readonly FastGithubConfig fastGithubConfig; private readonly ILogger logger; private readonly ConcurrentDictionary dnsEndPointAddressElapseds = new(); @@ -24,13 +37,94 @@ namespace FastGithub.DomainResolve /// 域名解析器 /// /// + /// /// - public DomainResolver(DnsClient dnsClient, ILogger logger) + public DomainResolver( + DnsClient dnsClient, + FastGithubConfig fastGithubConfig, + ILogger logger) { this.dnsClient = dnsClient; + this.fastGithubConfig = fastGithubConfig; this.logger = logger; + + foreach (var endPoint in this.ReadDnsEndPoints()) + { + this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty); + } } + + /// + /// 读取保存的节点 + /// + /// + private IList ReadDnsEndPoints() + { + if (File.Exists(dnsEndpointFile) == false) + { + return Array.Empty(); + } + + try + { + dnsEndpointLocker.Wait(); + + var utf8Json = File.ReadAllBytes(dnsEndpointFile); + var endPointItems = JsonSerializer.Deserialize(utf8Json, jsonOptions); + if (endPointItems == null) + { + return Array.Empty(); + } + + var dnsEndPoints = new List(); + foreach (var item in endPointItems) + { + if (this.fastGithubConfig.IsMatch(item.Host)) + { + dnsEndPoints.Add(new DnsEndPoint(item.Host, item.Port)); + } + } + return dnsEndPoints; + } + catch (Exception ex) + { + this.logger.LogWarning(ex.Message, "读取dns记录异常"); + return Array.Empty(); + } + finally + { + dnsEndpointLocker.Release(); + } + } + + /// + /// 保存节点到文件 + /// + /// + /// + /// + private async Task WriteDnsEndPointsAsync(IEnumerable dnsEndPoints, CancellationToken cancellationToken) + { + try + { + await dnsEndpointLocker.WaitAsync(CancellationToken.None); + + var endPointItems = dnsEndPoints.Select(item => new EndPointItem(item.Host, item.Port)).ToArray(); + var utf8Json = JsonSerializer.SerializeToUtf8Bytes(endPointItems, jsonOptions); + await File.WriteAllBytesAsync(dnsEndpointFile, utf8Json, cancellationToken); + } + catch (Exception ex) + { + this.logger.LogWarning(ex.Message, "保存dns记录异常"); + } + finally + { + dnsEndpointLocker.Release(); + } + } + + /// /// 解析ip /// @@ -64,7 +158,11 @@ namespace FastGithub.DomainResolve } else { - this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty); + if (this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty)) + { + await this.WriteDnsEndPointsAsync(this.dnsEndPointAddressElapseds.Keys, cancellationToken); + } + await foreach (var adddress in this.dnsClient.ResolveAsync(endPoint, fastSort: true, cancellationToken)) { this.logger.LogInformation($"{endPoint.Host}->{adddress}");