DomainResolver.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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 readonly DnsClient dnsClient;
  18. private readonly DomainPersistence persistence;
  19. private readonly IPAddressService addressService;
  20. private readonly ILogger<DomainResolver> logger;
  21. private readonly ConcurrentDictionary<DnsEndPoint, IPAddress[]> dnsEndPointAddress = new();
  22. /// <summary>
  23. /// 域名解析器
  24. /// </summary>
  25. /// <param name="dnsClient"></param>
  26. /// <param name="persistence"></param>
  27. /// <param name="addressService"></param>
  28. /// <param name="logger"></param>
  29. public DomainResolver(
  30. DnsClient dnsClient,
  31. DomainPersistence persistence,
  32. IPAddressService addressService,
  33. ILogger<DomainResolver> logger)
  34. {
  35. this.dnsClient = dnsClient;
  36. this.persistence = persistence;
  37. this.addressService = addressService;
  38. this.logger = logger;
  39. foreach (var endPoint in persistence.ReadDnsEndPoints())
  40. {
  41. this.dnsEndPointAddress.TryAdd(endPoint, Array.Empty<IPAddress>());
  42. }
  43. }
  44. /// <summary>
  45. /// 解析域名
  46. /// </summary>
  47. /// <param name="endPoint">节点</param>
  48. /// <param name="cancellationToken"></param>
  49. /// <returns></returns>
  50. public async IAsyncEnumerable<IPAddress> ResolveAsync(DnsEndPoint endPoint, [EnumeratorCancellation] CancellationToken cancellationToken)
  51. {
  52. if (this.dnsEndPointAddress.TryGetValue(endPoint, out var addresses) && addresses.Length > 0)
  53. {
  54. foreach (var address in addresses)
  55. {
  56. yield return address;
  57. }
  58. }
  59. else
  60. {
  61. if (this.dnsEndPointAddress.TryAdd(endPoint, Array.Empty<IPAddress>()))
  62. {
  63. await this.persistence.WriteDnsEndPointsAsync(this.dnsEndPointAddress.Keys, cancellationToken);
  64. }
  65. await foreach (var adddress in this.dnsClient.ResolveAsync(endPoint, fastSort: true, cancellationToken))
  66. {
  67. yield return adddress;
  68. }
  69. }
  70. }
  71. /// <summary>
  72. /// 对所有节点进行测速
  73. /// </summary>
  74. /// <param name="cancellationToken"></param>
  75. /// <returns></returns>
  76. public async Task TestAllEndPointsAsync(CancellationToken cancellationToken)
  77. {
  78. foreach (var keyValue in this.dnsEndPointAddress)
  79. {
  80. var dnsEndPoint = keyValue.Key;
  81. var oldAddresses = keyValue.Value;
  82. var newAddresses = await this.addressService.GetAddressesAsync(dnsEndPoint, oldAddresses, cancellationToken);
  83. this.dnsEndPointAddress[dnsEndPoint] = newAddresses;
  84. var oldSegmentum = oldAddresses.Take(5);
  85. var newSegmentum = newAddresses.Take(5);
  86. if (oldSegmentum.SequenceEqual(newSegmentum) == false)
  87. {
  88. var addressArray = string.Join(", ", newSegmentum.Select(item => item.ToString()));
  89. this.logger.LogInformation($"{dnsEndPoint.Host}:{dnsEndPoint.Port}->[{addressArray}]");
  90. }
  91. }
  92. }
  93. }
  94. }