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}}"; } } }