DomainSpeedTestService.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. using FastGithub.Configuration;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Text.Json;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace FastGithub.DomainResolve
  11. {
  12. /// <summary>
  13. /// 域名的IP测速服务
  14. /// </summary>
  15. sealed class DomainSpeedTestService
  16. {
  17. private const string DATA_FILE = "domains.json";
  18. private readonly DnsClient dnsClient;
  19. private readonly object syncRoot = new();
  20. private readonly Dictionary<string, IPAddressItemHashSet> domainIPAddressHashSet = new();
  21. /// <summary>
  22. /// 域名的IP测速服务
  23. /// </summary>
  24. /// <param name="dnsClient"></param>
  25. public DomainSpeedTestService(DnsClient dnsClient)
  26. {
  27. this.dnsClient = dnsClient;
  28. }
  29. /// <summary>
  30. /// 添加要测速的域名
  31. /// </summary>
  32. /// <param name="domain"></param>
  33. /// <returns></returns>
  34. public bool Add(string domain)
  35. {
  36. lock (this.syncRoot)
  37. {
  38. return this.domainIPAddressHashSet.TryAdd(domain, new IPAddressItemHashSet());
  39. }
  40. }
  41. /// <summary>
  42. /// 获取测试后排序的IP
  43. /// </summary>
  44. /// <param name="domain"></param>
  45. /// <returns></returns>
  46. public IPAddress[] GetIPAddresses(string domain)
  47. {
  48. lock (this.syncRoot)
  49. {
  50. if (this.domainIPAddressHashSet.TryGetValue(domain, out var hashSet) && hashSet.Count > 0)
  51. {
  52. return hashSet.ToArray().OrderBy(item => item.PingElapsed).Select(item => item.Address).ToArray();
  53. }
  54. return Array.Empty<IPAddress>();
  55. }
  56. }
  57. /// <summary>
  58. /// 加载数据
  59. /// </summary>
  60. /// <param name="cancellationToken"></param>
  61. /// <returns></returns>
  62. public async Task LoadDataAsync(CancellationToken cancellationToken)
  63. {
  64. if (File.Exists(DATA_FILE) == false)
  65. {
  66. return;
  67. }
  68. using var fileStream = File.OpenRead(DATA_FILE);
  69. var domains = await JsonSerializer.DeserializeAsync<string[]>(fileStream, cancellationToken: cancellationToken);
  70. if (domains == null)
  71. {
  72. return;
  73. }
  74. lock (this.syncRoot)
  75. {
  76. foreach (var domain in domains)
  77. {
  78. this.domainIPAddressHashSet.TryAdd(domain, new IPAddressItemHashSet());
  79. }
  80. }
  81. }
  82. /// <summary>
  83. /// 保存数据
  84. /// </summary>
  85. /// <returns></returns>
  86. public async Task<bool> SaveDataAsync()
  87. {
  88. var domains = this.domainIPAddressHashSet.Keys
  89. .Select(item => new DomainPattern(item))
  90. .OrderBy(item => item)
  91. .Select(item => item.ToString())
  92. .ToArray();
  93. try
  94. {
  95. using var fileStream = File.OpenWrite(DATA_FILE);
  96. await JsonSerializer.SerializeAsync(fileStream, domains, new JsonSerializerOptions { WriteIndented = true });
  97. return true;
  98. }
  99. catch (Exception)
  100. {
  101. return false;
  102. }
  103. }
  104. /// <summary>
  105. /// 进行一轮IP测速
  106. /// </summary>
  107. /// <param name="cancellationToken"></param>
  108. /// <returns></returns>
  109. public async Task TestSpeedAsync(CancellationToken cancellationToken)
  110. {
  111. KeyValuePair<string, IPAddressItemHashSet>[] keyValues;
  112. lock (this.syncRoot)
  113. {
  114. keyValues = this.domainIPAddressHashSet.ToArray();
  115. }
  116. foreach (var keyValue in keyValues)
  117. {
  118. var domain = keyValue.Key;
  119. var hashSet = keyValue.Value;
  120. await foreach (var address in this.dnsClient.ResolveAsync(domain, cancellationToken))
  121. {
  122. hashSet.Add(new IPAddressItem(address));
  123. }
  124. await hashSet.PingAllAsync();
  125. }
  126. }
  127. }
  128. }