重构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.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
@ -10,9 +12,21 @@ namespace FastGithub.Scanner
sealed class GithubContext : DomainAddress, IEquatable<GithubContext>
{
/// <summary>
/// 获取或设置是否可用
/// 最多保存最的近的10条记录
/// </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>
/// 设置取消令牌
@ -20,9 +34,21 @@ namespace FastGithub.Scanner
public CancellationToken CancellationToken { get; }
/// <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>
@ -47,19 +73,74 @@ namespace FastGithub.Scanner
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)
{
return base.Equals(other);
}
/// <summary>
/// 转换为为统计信息
/// 转换为统计信息
/// </summary>
/// <returns></returns>
public string ToStatisticsString()
{
var rate = Math.Round(this.History.AvailableRate * 100, 2);
return $"{{Address={this.Address}, AvailableRate={rate}%, AvgElapsed={this.History.AvgElapsed.TotalSeconds}s}}";
var availableRate = Math.Round(this.AvailableRate * 100, 2);
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)]
sealed class GithubDnsHttpHandler : DelegatingHandler
{
private readonly GithubContextCollection scanResults;
private readonly GithubScanResults scanResults;
/// <summary>
/// Github的dns解析的httpHandler
/// </summary>
public GithubDnsHttpHandler(GithubContextCollection scanResults)
public GithubDnsHttpHandler(GithubScanResults scanResults)
{
this.scanResults = scanResults;
}

View File

@ -9,10 +9,10 @@ namespace FastGithub.Scanner
/// GithubContext集合
/// </summary>
[Service(ServiceLifetime.Singleton)]
sealed class GithubContextCollection : IGithubScanResults
sealed class GithubScanResults : IGithubScanResults
{
private readonly object syncRoot = new();
private readonly List<GithubContext> contextList = new();
private readonly List<GithubContext> contexts = new();
/// <summary>
/// 添加GithubContext
@ -23,11 +23,11 @@ namespace FastGithub.Scanner
{
lock (this.syncRoot)
{
if (this.contextList.Contains(context))
if (this.contexts.Contains(context))
{
return false;
}
this.contextList.Add(context);
this.contexts.Add(context);
return true;
}
}
@ -40,23 +40,7 @@ namespace FastGithub.Scanner
{
lock (this.syncRoot)
{
return this.contextList.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;
return this.contexts.ToArray();
}
}
@ -69,11 +53,11 @@ namespace FastGithub.Scanner
{
lock (this.syncRoot)
{
return this.contextList
.Where(item => item.Domain == domain && item.History.AvailableRate > 0d)
.OrderByDescending(item => item.History.AvailableRate)
return this.contexts
.Where(item => item.Domain == domain && item.AvailableRate > 0d)
.OrderByDescending(item => item.AvailableRate)
.ThenByDescending(item => item.Available)
.ThenBy(item => item.History.AvgElapsed)
.ThenBy(item => item.AvgElapsed)
.Select(item => item.Address)
.FirstOrDefault();
}

View File

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

View File

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

View File

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

View File

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