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}");