2
0

DomainResolver.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. using Microsoft.Extensions.Logging;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Runtime.CompilerServices;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace FastGithub.DomainResolve
  11. {
  12. /// <summary>
  13. /// 域名解析器
  14. /// </summary>
  15. sealed class DomainResolver : IDomainResolver
  16. {
  17. private const int MAX_IP_COUNT = 3;
  18. private readonly DnsClient dnsClient;
  19. private readonly PersistenceService persistence;
  20. private readonly IPAddressService addressService;
  21. private readonly ILogger<DomainResolver> logger;
  22. private readonly ConcurrentDictionary<DnsEndPoint, IPAddress[]> dnsEndPointAddress = new();
  23. /// <summary>
  24. /// 域名解析器
  25. /// </summary>
  26. /// <param name="dnsClient"></param>
  27. /// <param name="persistence"></param>
  28. /// <param name="addressService"></param>
  29. /// <param name="logger"></param>
  30. public DomainResolver(
  31. DnsClient dnsClient,
  32. PersistenceService persistence,
  33. IPAddressService addressService,
  34. ILogger<DomainResolver> logger)
  35. {
  36. this.dnsClient = dnsClient;
  37. this.persistence = persistence;
  38. this.addressService = addressService;
  39. this.logger = logger;
  40. foreach (var endPoint in persistence.ReadDnsEndPoints())
  41. {
  42. this.dnsEndPointAddress.TryAdd(endPoint, Array.Empty<IPAddress>());
  43. }
  44. }
  45. /// <summary>
  46. /// 解析域名
  47. /// </summary>
  48. /// <param name="endPoint">节点</param>
  49. /// <param name="cancellationToken"></param>
  50. /// <returns></returns>
  51. public async IAsyncEnumerable<IPAddress> ResolveAsync(DnsEndPoint endPoint, [EnumeratorCancellation] CancellationToken cancellationToken)
  52. {
  53. if (this.dnsEndPointAddress.TryGetValue(endPoint, out var addresses) && addresses.Length > 0)
  54. {
  55. foreach (var address in addresses)
  56. {
  57. yield return address;
  58. }
  59. }
  60. else
  61. {
  62. if (this.dnsEndPointAddress.TryAdd(endPoint, Array.Empty<IPAddress>()))
  63. {
  64. await this.persistence.WriteDnsEndPointsAsync(this.dnsEndPointAddress.Keys, cancellationToken);
  65. }
  66. await foreach (var adddress in this.dnsClient.ResolveAsync(endPoint, fastSort: true, cancellationToken))
  67. {
  68. yield return adddress;
  69. }
  70. }
  71. }
  72. /// <summary>
  73. /// 对所有节点进行测速
  74. /// </summary>
  75. /// <param name="cancellationToken"></param>
  76. /// <returns></returns>
  77. public async Task TestSpeedAsync(CancellationToken cancellationToken)
  78. {
  79. foreach (var keyValue in this.dnsEndPointAddress.OrderBy(item => item.Value.Length))
  80. {
  81. var dnsEndPoint = keyValue.Key;
  82. var oldAddresses = keyValue.Value;
  83. var newAddresses = await this.addressService.GetAddressesAsync(dnsEndPoint, oldAddresses, cancellationToken);
  84. this.dnsEndPointAddress[dnsEndPoint] = newAddresses;
  85. var oldSegmentums = oldAddresses.Take(MAX_IP_COUNT);
  86. var newSegmentums = newAddresses.Take(MAX_IP_COUNT);
  87. if (oldSegmentums.SequenceEqual(newSegmentums) == false)
  88. {
  89. var addressArray = string.Join(", ", newSegmentums.Select(item => item.ToString()));
  90. this.logger.LogInformation($"{dnsEndPoint.Host}:{dnsEndPoint.Port}->[{addressArray}]");
  91. }
  92. }
  93. }
  94. }
  95. }