FastGithubConfig.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using Microsoft.Extensions.Options;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.Linq;
  6. using System.Net;
  7. namespace FastGithub.Configuration
  8. {
  9. /// <summary>
  10. /// FastGithub配置
  11. /// </summary>
  12. public class FastGithubConfig
  13. {
  14. private SortedDictionary<DomainPattern, DomainConfig> domainConfigs;
  15. private ConcurrentDictionary<string, DomainConfig?> domainConfigCache;
  16. /// <summary>
  17. /// http代理端口
  18. /// </summary>
  19. public int HttpProxyPort { get; set; }
  20. /// <summary>
  21. /// 回退的dns
  22. /// </summary>
  23. public IPEndPoint[] FallbackDns { get; set; }
  24. /// <summary>
  25. /// FastGithub配置
  26. /// </summary>
  27. /// <param name="options"></param>
  28. /// <param name="logger"></param>
  29. public FastGithubConfig(IOptionsMonitor<FastGithubOptions> options)
  30. {
  31. var opt = options.CurrentValue;
  32. this.HttpProxyPort = opt.HttpProxyPort;
  33. this.FallbackDns = ConvertToIPEndPoints(opt.FallbackDns).ToArray();
  34. this.domainConfigs = ConvertDomainConfigs(opt.DomainConfigs);
  35. this.domainConfigCache = new ConcurrentDictionary<string, DomainConfig?>();
  36. options.OnChange(opt => this.Update(opt));
  37. }
  38. /// <summary>
  39. /// 更新配置
  40. /// </summary>
  41. /// <param name="options"></param>
  42. private void Update(FastGithubOptions options)
  43. {
  44. this.HttpProxyPort = options.HttpProxyPort;
  45. this.FallbackDns = ConvertToIPEndPoints(options.FallbackDns).ToArray();
  46. this.domainConfigs = ConvertDomainConfigs(options.DomainConfigs);
  47. this.domainConfigCache = new ConcurrentDictionary<string, DomainConfig?>();
  48. }
  49. /// <summary>
  50. /// 转换为IPEndPoint
  51. /// </summary>
  52. /// <param name="ipEndPoints"></param>
  53. /// <returns></returns>
  54. private static IEnumerable<IPEndPoint> ConvertToIPEndPoints(IEnumerable<string> ipEndPoints)
  55. {
  56. foreach (var item in ipEndPoints)
  57. {
  58. if (IPEndPoint.TryParse(item, out var endPoint))
  59. {
  60. yield return endPoint;
  61. }
  62. }
  63. }
  64. /// <summary>
  65. /// 配置转换
  66. /// </summary>
  67. /// <param name="domainConfigs"></param>
  68. /// <returns></returns>
  69. private static SortedDictionary<DomainPattern, DomainConfig> ConvertDomainConfigs(Dictionary<string, DomainConfig> domainConfigs)
  70. {
  71. var result = new SortedDictionary<DomainPattern, DomainConfig>();
  72. foreach (var kv in domainConfigs)
  73. {
  74. result.Add(new DomainPattern(kv.Key), kv.Value);
  75. }
  76. return result;
  77. }
  78. /// <summary>
  79. /// 是否匹配指定的域名
  80. /// </summary>
  81. /// <param name="domain"></param>
  82. /// <returns></returns>
  83. public bool IsMatch(string domain)
  84. {
  85. return this.TryGetDomainConfig(domain, out _);
  86. }
  87. /// <summary>
  88. /// 尝试获取域名配置
  89. /// </summary>
  90. /// <param name="domain"></param>
  91. /// <param name="value"></param>
  92. /// <returns></returns>
  93. public bool TryGetDomainConfig(string domain, [MaybeNullWhen(false)] out DomainConfig value)
  94. {
  95. value = this.domainConfigCache.GetOrAdd(domain, GetDomainConfig);
  96. return value != null;
  97. DomainConfig? GetDomainConfig(string domain)
  98. {
  99. var key = this.domainConfigs.Keys.FirstOrDefault(item => item.IsMatch(domain));
  100. return key == null ? null : this.domainConfigs[key];
  101. }
  102. }
  103. /// <summary>
  104. /// 获取所有域名表达式
  105. /// </summary>
  106. /// <returns></returns>
  107. public string[] GetDomainPatterns()
  108. {
  109. return this.domainConfigs.Keys.Select(item => item.ToString()).ToArray();
  110. }
  111. }
  112. }