147 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Linq;
 | 
						|
using System.Net;
 | 
						|
using System.Threading;
 | 
						|
 | 
						|
namespace FastGithub.Scanner
 | 
						|
{
 | 
						|
    /// <summary>
 | 
						|
    /// Github扫描上下文
 | 
						|
    /// </summary>
 | 
						|
    sealed class GithubContext : DomainAddress, IEquatable<GithubContext>
 | 
						|
    {
 | 
						|
        /// <summary>
 | 
						|
        /// 最多保存最的近的20条记录
 | 
						|
        /// </summary>
 | 
						|
        private const int MAX_LOG_COUNT = 20;
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 扫描记录
 | 
						|
        /// </summary>
 | 
						|
        private record ScanLog(bool Available, TimeSpan Elapsed);
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 扫描历史记录
 | 
						|
        /// </summary>
 | 
						|
        private readonly Queue<ScanLog> history = new();
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 设置取消令牌
 | 
						|
        /// </summary>
 | 
						|
        public CancellationToken CancellationToken { get; }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 获取可用率
 | 
						|
        /// </summary>
 | 
						|
        /// <returns></returns>
 | 
						|
        public double AvailableRate => this.GetAvailableRate();
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 获取平均耗时
 | 
						|
        /// </summary>
 | 
						|
        /// <returns></returns>
 | 
						|
        public TimeSpan AvgElapsed => this.GetAvgElapsed();
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 获取或设置是否可用
 | 
						|
        /// </summary>
 | 
						|
        public bool Available { get; set; }
 | 
						|
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Github扫描上下文
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="domain"></param>
 | 
						|
        /// <param name="address"></param>
 | 
						|
        public GithubContext(string domain, IPAddress address)
 | 
						|
            : this(domain, address, CancellationToken.None)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Github扫描上下文
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="domain"></param>
 | 
						|
        /// <param name="address"></param>
 | 
						|
        /// <param name="cancellationToken"></param>
 | 
						|
        public GithubContext(string domain, IPAddress address, CancellationToken cancellationToken)
 | 
						|
            : base(domain, address)
 | 
						|
        {
 | 
						|
            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 availableRate = Math.Round(this.AvailableRate * 100, 2);
 | 
						|
            return $"{{{nameof(Address)}={this.Address}, {nameof(AvailableRate)}={availableRate}%, {nameof(AvgElapsed)}={this.AvgElapsed.TotalSeconds}s}}";
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |