using FastGithub.Configuration; using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace FastGithub.DomainResolve { /// /// 域名解析器 /// sealed class DomainResolver : IDomainResolver { private readonly DnsClient dnsClient; private readonly ILogger logger; private readonly ConcurrentDictionary dnsEndPointAddressElapseds = new(); /// /// 域名解析器 /// /// /// public DomainResolver(DnsClient dnsClient, ILogger logger) { this.dnsClient = dnsClient; this.logger = logger; } /// /// 解析ip /// /// 节点 /// /// public async Task ResolveAnyAsync(DnsEndPoint endPoint, CancellationToken cancellationToken = default) { await foreach (var address in this.ResolveAllAsync(endPoint, cancellationToken)) { return address; } throw new FastGithubException($"解析不到{endPoint.Host}的IP"); } /// /// 解析域名 /// /// 节点 /// /// public async IAsyncEnumerable ResolveAllAsync(DnsEndPoint endPoint, [EnumeratorCancellation] CancellationToken cancellationToken) { if (this.dnsEndPointAddressElapseds.TryGetValue(endPoint, out var addressElapseds) && addressElapseds.IsEmpty == false) { this.logger.LogInformation($"{endPoint.Host}: {addressElapseds}"); foreach (var addressElapsed in addressElapseds) { yield return addressElapsed.Adddress; } } else { this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty); await foreach (var adddress in this.dnsClient.ResolveAsync(endPoint, cancellationToken)) { yield return adddress; } } } /// /// 对所有节点进行测速 /// /// /// public async Task TestAllEndPointsAsync(CancellationToken cancellationToken) { foreach (var keyValue in this.dnsEndPointAddressElapseds) { if (keyValue.Value.IsEmpty || keyValue.Value.IsExpired) { var dnsEndPoint = keyValue.Key; var addresses = new List(); await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint, cancellationToken)) { addresses.Add(adddress); } var addressElapseds = IPAddressElapsedCollection.Empty; if (addresses.Count == 1) { var addressElapsed = new IPAddressElapsed(addresses[0], TimeSpan.Zero); addressElapseds = new IPAddressElapsedCollection(addressElapsed); } else if (addresses.Count > 1) { var tasks = addresses.Select(address => IPAddressElapsed.ParseAsync(address, dnsEndPoint.Port, cancellationToken)); addressElapseds = new IPAddressElapsedCollection(await Task.WhenAll(tasks)); } this.dnsEndPointAddressElapseds[dnsEndPoint] = addressElapseds; } } } } }