using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
namespace FastGithub.Scanner
{
///
/// Github扫描上下文
///
sealed class GithubContext : DomainAddress, IEquatable
{
///
/// 最多保存最的近的10条记录
///
private const int MAX_LOG_COUNT = 10;
///
/// 扫描记录
///
private record ScanLog(bool Available, TimeSpan Elapsed);
///
/// 扫描历史记录
///
private readonly Queue history = new();
///
/// 设置取消令牌
///
public CancellationToken CancellationToken { get; }
///
/// 获取可用率
///
///
public double AvailableRate => this.GetAvailableRate();
///
/// 获取平均耗时
///
///
public TimeSpan AvgElapsed => this.GetAvgElapsed();
///
/// 获取或设置是否可用
///
public bool Available { get; set; }
///
/// Github扫描上下文
///
///
///
public GithubContext(string domain, IPAddress address)
: this(domain, address, CancellationToken.None)
{
}
///
/// Github扫描上下文
///
///
///
///
public GithubContext(string domain, IPAddress address, CancellationToken cancellationToken)
: base(domain, address)
{
this.CancellationToken = cancellationToken;
}
///
/// 获取可用率
///
///
private double GetAvailableRate()
{
if (this.history.Count == 0)
{
return 0d;
}
var availableCount = this.history.Count(item => item.Available);
return (double)availableCount / this.history.Count;
}
///
/// 获取平均耗时
///
///
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;
}
///
/// 添加扫描记录
///
/// 扫描耗时
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();
}
}
///
/// 是否相等
///
///
///
public bool Equals(GithubContext? other)
{
return base.Equals(other);
}
///
/// 转换为统计信息
///
///
public string ToStatisticsString()
{
var availableRate = Math.Round(this.AvailableRate * 100, 2);
return $"{{{nameof(Address)}={this.Address}, {nameof(AvailableRate)}={availableRate}%, {nameof(AvgElapsed)}={this.AvgElapsed.TotalSeconds}s}}";
}
}
}