重构GithubContext

This commit is contained in:
xljiulang 2021-06-21 03:33:08 +08:00
parent b486f551cf
commit 922d47fdab
8 changed files with 105 additions and 125 deletions

View File

@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
@ -10,9 +12,21 @@ namespace FastGithub.Scanner
sealed class GithubContext : DomainAddress, IEquatable<GithubContext> sealed class GithubContext : DomainAddress, IEquatable<GithubContext>
{ {
/// <summary> /// <summary>
/// 获取或设置是否可用 /// 最多保存最的近的10条记录
/// </summary> /// </summary>
public bool Available { get; set; } private const int MAX_LOG_COUNT = 10;
/// <summary>
/// 扫描记录
/// </summary>
private record ScanLog(bool Available, TimeSpan Elapsed);
/// <summary>
/// 扫描历史记录
/// </summary>
private readonly Queue<ScanLog> history = new();
/// <summary> /// <summary>
/// 设置取消令牌 /// 设置取消令牌
@ -20,9 +34,21 @@ namespace FastGithub.Scanner
public CancellationToken CancellationToken { get; } public CancellationToken CancellationToken { get; }
/// <summary> /// <summary>
/// 获取扫描历史信息 /// 获取可用率
/// </summary> /// </summary>
public GithubContextHistory History { get; } = new(); /// <returns></returns>
public double AvailableRate => this.GetAvailableRate();
/// <summary>
/// 获取平均耗时
/// </summary>
/// <returns></returns>
public TimeSpan AvgElapsed => this.GetAvgElapsed();
/// <summary>
/// 获取或设置是否可用
/// </summary>
public bool Available { get; set; }
/// <summary> /// <summary>
@ -47,19 +73,74 @@ namespace FastGithub.Scanner
this.CancellationToken = cancellationToken; this.CancellationToken = cancellationToken;
} }
/// <summary>
/// 获取可用率
/// </summary>
/// <returns></returns>
private double GetAvailableRate()
{
if (this.history.Count == 0)
{
return 0d;
}
var availableCount = this.history.Count(item => item.Available);
return (double)availableCount / this.history.Count;
}
/// <summary>
/// 获取平均耗时
/// </summary>
/// <returns></returns>
private TimeSpan GetAvgElapsed()
{
var availableCount = 0;
var availableElapsed = TimeSpan.Zero;
foreach (var item in this.history)
{
if (item.Available == true)
{
availableCount += 1;
availableElapsed = availableElapsed.Add(item.Elapsed);
}
}
return availableCount == 0 ? TimeSpan.MaxValue : availableElapsed / availableCount;
}
/// <summary>
/// 添加扫描记录
/// </summary>
/// <param name="elapsed">扫描耗时</param>
public void AddScanLog(TimeSpan elapsed)
{
var log = new ScanLog(this.Available, elapsed);
this.history.Enqueue(log);
while (this.history.Count > MAX_LOG_COUNT)
{
this.history.Dequeue();
}
}
/// <summary>
/// 是否相等
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public bool Equals(GithubContext? other) public bool Equals(GithubContext? other)
{ {
return base.Equals(other); return base.Equals(other);
} }
/// <summary> /// <summary>
/// 转换为为统计信息 /// 转换为统计信息
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public string ToStatisticsString() public string ToStatisticsString()
{ {
var rate = Math.Round(this.History.AvailableRate * 100, 2); var availableRate = Math.Round(this.AvailableRate * 100, 2);
return $"{{Address={this.Address}, AvailableRate={rate}%, AvgElapsed={this.History.AvgElapsed.TotalSeconds}s}}"; return $"{{{nameof(Address)}={this.Address}, {nameof(AvailableRate)}={availableRate}%, {nameof(AvgElapsed)}={this.AvgElapsed.TotalSeconds}s}}";
} }
} }
} }

View File

@ -1,77 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace FastGithub.Scanner
{
/// <summary>
/// GithubContext的扫描历史
/// </summary>
sealed class GithubContextHistory
{
/// <summary>
/// 最多保存最的近的10条记录
/// </summary>
private const int MAX_LOG_COUNT = 10;
private record ScanLog(bool Available, TimeSpan Elapsed);
private readonly Queue<ScanLog> scanLogs = new();
/// <summary>
/// 获取可用率
/// </summary>
/// <returns></returns>
public double AvailableRate
{
get
{
if (this.scanLogs.Count == 0)
{
return 0d;
}
var availableCount = this.scanLogs.Count(item => item.Available);
return (double)availableCount / this.scanLogs.Count;
}
}
/// <summary>
/// 获取平均耗时
/// </summary>
/// <returns></returns>
public TimeSpan AvgElapsed
{
get
{
var availableCount = 0;
var availableElapsed = TimeSpan.Zero;
foreach (var item in this.scanLogs)
{
if (item.Available == true)
{
availableCount += 1;
availableElapsed = availableElapsed.Add(item.Elapsed);
}
}
return availableCount == 0 ? TimeSpan.MaxValue : availableElapsed / availableCount;
}
}
/// <summary>
/// 添加记录
/// </summary>
/// <param name="available">是否可用</param>
/// <param name="elapsed">扫描耗时</param>
public void Add(bool available, TimeSpan elapsed)
{
this.scanLogs.Enqueue(new ScanLog(available, elapsed));
while (this.scanLogs.Count > MAX_LOG_COUNT)
{
this.scanLogs.Dequeue();
}
}
}
}

View File

@ -13,12 +13,12 @@ namespace FastGithub.Scanner
[Service(ServiceLifetime.Transient)] [Service(ServiceLifetime.Transient)]
sealed class GithubDnsHttpHandler : DelegatingHandler sealed class GithubDnsHttpHandler : DelegatingHandler
{ {
private readonly GithubContextCollection scanResults; private readonly GithubScanResults scanResults;
/// <summary> /// <summary>
/// Github的dns解析的httpHandler /// Github的dns解析的httpHandler
/// </summary> /// </summary>
public GithubDnsHttpHandler(GithubContextCollection scanResults) public GithubDnsHttpHandler(GithubScanResults scanResults)
{ {
this.scanResults = scanResults; this.scanResults = scanResults;
} }

View File

@ -9,10 +9,10 @@ namespace FastGithub.Scanner
/// GithubContext集合 /// GithubContext集合
/// </summary> /// </summary>
[Service(ServiceLifetime.Singleton)] [Service(ServiceLifetime.Singleton)]
sealed class GithubContextCollection : IGithubScanResults sealed class GithubScanResults : IGithubScanResults
{ {
private readonly object syncRoot = new(); private readonly object syncRoot = new();
private readonly List<GithubContext> contextList = new(); private readonly List<GithubContext> contexts = new();
/// <summary> /// <summary>
/// 添加GithubContext /// 添加GithubContext
@ -23,11 +23,11 @@ namespace FastGithub.Scanner
{ {
lock (this.syncRoot) lock (this.syncRoot)
{ {
if (this.contextList.Contains(context)) if (this.contexts.Contains(context))
{ {
return false; return false;
} }
this.contextList.Add(context); this.contexts.Add(context);
return true; return true;
} }
} }
@ -40,23 +40,7 @@ namespace FastGithub.Scanner
{ {
lock (this.syncRoot) lock (this.syncRoot)
{ {
return this.contextList.ToArray(); return this.contexts.ToArray();
}
}
/// <summary>
/// 查询ip是否可用
/// </summary>
/// <param name="domain"></param>
/// <param name="address"></param>
/// <returns></returns>
public bool IsAvailable(string domain, IPAddress address)
{
lock (this.syncRoot)
{
var target = new GithubContext(domain, address);
var context = this.contextList.Find(item => item.Equals(target));
return context != null && context.Available;
} }
} }
@ -69,11 +53,11 @@ namespace FastGithub.Scanner
{ {
lock (this.syncRoot) lock (this.syncRoot)
{ {
return this.contextList return this.contexts
.Where(item => item.Domain == domain && item.History.AvailableRate > 0d) .Where(item => item.Domain == domain && item.AvailableRate > 0d)
.OrderByDescending(item => item.History.AvailableRate) .OrderByDescending(item => item.AvailableRate)
.ThenByDescending(item => item.Available) .ThenByDescending(item => item.Available)
.ThenBy(item => item.History.AvgElapsed) .ThenBy(item => item.AvgElapsed)
.Select(item => item.Address) .Select(item => item.Address)
.FirstOrDefault(); .FirstOrDefault();
} }

View File

@ -15,7 +15,7 @@ namespace FastGithub.Scanner
sealed class GithubScanService sealed class GithubScanService
{ {
private readonly GithubLookupFacotry lookupFactory; private readonly GithubLookupFacotry lookupFactory;
private readonly GithubContextCollection scanResults; private readonly GithubScanResults scanResults;
private readonly ILoggerFactory loggerFactory; private readonly ILoggerFactory loggerFactory;
private readonly ILogger<GithubScanService> logger; private readonly ILogger<GithubScanService> logger;
@ -31,7 +31,7 @@ namespace FastGithub.Scanner
/// <param name="logger"></param> /// <param name="logger"></param>
public GithubScanService( public GithubScanService(
GithubLookupFacotry lookupFactory, GithubLookupFacotry lookupFactory,
GithubContextCollection scanResults, GithubScanResults scanResults,
IServiceProvider appService, IServiceProvider appService,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
ILogger<GithubScanService> logger) ILogger<GithubScanService> logger)
@ -94,8 +94,8 @@ namespace FastGithub.Scanner
var results = this.scanResults.ToArray(); var results = this.scanResults.ToArray();
var contexts = results var contexts = results
.OrderBy(item => item.Domain) .OrderBy(item => item.Domain)
.ThenByDescending(item => item.History.AvailableRate) .ThenByDescending(item => item.AvailableRate)
.ThenBy(item => item.History.AvgElapsed); .ThenBy(item => item.AvgElapsed);
foreach (var context in contexts) foreach (var context in contexts)
{ {

View File

@ -7,14 +7,6 @@ namespace FastGithub.Scanner
/// </summary> /// </summary>
public interface IGithubScanResults public interface IGithubScanResults
{ {
/// <summary>
/// 查询ip是否可用
/// </summary>
/// <param name="domain"></param>
/// <param name="address"></param>
/// <returns></returns>
bool IsAvailable(string domain, IPAddress address);
/// <summary> /// <summary>
/// 查找最优的ip /// 查找最优的ip
/// </summary> /// </summary>

View File

@ -31,7 +31,7 @@ namespace FastGithub.Scanner.ScanMiddlewares
stopwatch.Stop(); stopwatch.Stop();
} }
context.History.Add(context.Available, stopwatch.Elapsed); context.AddScanLog(stopwatch.Elapsed);
} }
} }
} }

View File

@ -44,7 +44,7 @@ namespace FastGithub
.AddServiceAndOptions(assembly, configuration) .AddServiceAndOptions(assembly, configuration)
.AddHostedService<GithubFullScanHostedService>() .AddHostedService<GithubFullScanHostedService>()
.AddHostedService<GithubResultScanHostedService>() .AddHostedService<GithubResultScanHostedService>()
.AddSingleton<IGithubScanResults>(appService => appService.GetRequiredService<GithubContextCollection>()); .AddSingleton<IGithubScanResults>(appService => appService.GetRequiredService<GithubScanResults>());
; ;
} }
} }