应用CancellationToken

This commit is contained in:
xljiulang 2021-06-18 22:37:53 +08:00
parent 01fac4fcb8
commit 9882e73678
16 changed files with 74 additions and 42 deletions

View File

@ -11,7 +11,7 @@ namespace FastGithub
public class PipelineBuilder<TContext> : IPipelineBuilder<TContext> public class PipelineBuilder<TContext> : IPipelineBuilder<TContext>
{ {
private readonly InvokeDelegate<TContext> completedHandler; private readonly InvokeDelegate<TContext> completedHandler;
private readonly List<Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>>> middlewares = new List<Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>>>(); private readonly List<Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>>> middlewares = new();
/// <summary> /// <summary>
/// 获取服务提供者 /// 获取服务提供者

View File

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastGithub.Scanner namespace FastGithub.Scanner
@ -26,12 +27,12 @@ namespace FastGithub.Scanner
/// 创建域名与ip的关系 /// 创建域名与ip的关系
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync() public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync(CancellationToken cancellationToken)
{ {
var hashSet = new HashSet<DomainAddress>(); var hashSet = new HashSet<DomainAddress>();
foreach (var provider in this.providers) foreach (var provider in this.providers)
{ {
var domainAddresses = await provider.CreateDomainAddressesAsync(); var domainAddresses = await provider.CreateDomainAddressesAsync(cancellationToken);
foreach (var item in domainAddresses) foreach (var item in domainAddresses)
{ {
hashSet.Add(item); hashSet.Add(item);

View File

@ -8,6 +8,7 @@ using System.Net.Http;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastGithub.Scanner.DomainAddressProviders namespace FastGithub.Scanner.DomainAddressProviders
@ -47,7 +48,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
/// 创建域名与ip的关系 /// 创建域名与ip的关系
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync() public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync(CancellationToken cancellationToken)
{ {
var setting = this.options.CurrentValue.DominAddressProviders.GithubMetaProvider; var setting = this.options.CurrentValue.DominAddressProviders.GithubMetaProvider;
if (setting.Enable == false) if (setting.Enable == false)
@ -58,7 +59,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
try try
{ {
var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub)); var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub));
var meta = await this.GetMetaAsync(httpClient, setting.MetaUri); var meta = await GetMetaAsync(httpClient, setting.MetaUri, cancellationToken);
if (meta != null) if (meta != null)
{ {
return meta.ToDomainAddresses(); return meta.ToDomainAddresses();
@ -66,6 +67,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
} }
catch (Exception ex) catch (Exception ex)
{ {
cancellationToken.ThrowIfCancellationRequested();
this.logger.LogWarning($"加载远程的ip列表异常{ex.Message}"); this.logger.LogWarning($"加载远程的ip列表异常{ex.Message}");
} }
@ -79,15 +81,16 @@ namespace FastGithub.Scanner.DomainAddressProviders
/// <param name="httpClient"></param> /// <param name="httpClient"></param>
/// <param name="metaUri"></param> /// <param name="metaUri"></param>
/// <returns></returns> /// <returns></returns>
private async Task<Meta?> GetMetaAsync(HttpClient httpClient, Uri metaUri) private static async Task<Meta?> GetMetaAsync(HttpClient httpClient, Uri metaUri, CancellationToken cancellationToken)
{ {
try try
{ {
return await httpClient.GetFromJsonAsync<Meta>(META_URI); return await httpClient.GetFromJsonAsync<Meta>(META_URI, cancellationToken);
} }
catch (Exception) catch (Exception)
{ {
return await httpClient.GetFromJsonAsync<Meta>(metaUri); cancellationToken.ThrowIfCancellationRequested();
return await httpClient.GetFromJsonAsync<Meta>(metaUri, cancellationToken);
} }
} }

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastGithub.Scanner.DomainAddressProviders namespace FastGithub.Scanner.DomainAddressProviders
@ -46,7 +47,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
/// 创建域名与ip的关系 /// 创建域名与ip的关系
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync() public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync(CancellationToken cancellationToken)
{ {
var setting = this.options.CurrentValue.DominAddressProviders.IPAddressComProvider; var setting = this.options.CurrentValue.DominAddressProviders.IPAddressComProvider;
if (setting.Enable == false) if (setting.Enable == false)
@ -60,7 +61,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
{ {
try try
{ {
var addresses = await this.LookupAsync(httpClient, domain); var addresses = await this.LookupAsync(httpClient, domain, cancellationToken);
foreach (var address in addresses) foreach (var address in addresses)
{ {
result.Add(new DomainAddress(domain, address)); result.Add(new DomainAddress(domain, address));
@ -68,6 +69,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
} }
catch (Exception) catch (Exception)
{ {
cancellationToken.ThrowIfCancellationRequested();
this.logger.LogWarning($"ipaddress.com无法解析{domain}"); this.logger.LogWarning($"ipaddress.com无法解析{domain}");
} }
} }
@ -80,7 +82,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
/// <param name="httpClient"></param> /// <param name="httpClient"></param>
/// <param name="domain"></param> /// <param name="domain"></param>
/// <returns></returns> /// <returns></returns>
private async Task<List<IPAddress>> LookupAsync(HttpClient httpClient, string domain) private async Task<List<IPAddress>> LookupAsync(HttpClient httpClient, string domain, CancellationToken cancellationToken)
{ {
var keyValue = new KeyValuePair<string?, string?>("host", domain); var keyValue = new KeyValuePair<string?, string?>("host", domain);
var content = new FormUrlEncodedContent(Enumerable.Repeat(keyValue, 1)); var content = new FormUrlEncodedContent(Enumerable.Repeat(keyValue, 1));
@ -91,8 +93,8 @@ namespace FastGithub.Scanner.DomainAddressProviders
Content = content Content = content
}; };
using var response = await httpClient.SendAsync(request); using var response = await httpClient.SendAsync(request, cancellationToken);
var html = await response.Content.ReadAsStringAsync(); var html = await response.Content.ReadAsStringAsync(cancellationToken);
var match = Regex.Match(html, @"(?<=<h1>IP Lookup : )\d+\.\d+\.\d+\.\d+", RegexOptions.IgnoreCase); var match = Regex.Match(html, @"(?<=<h1>IP Lookup : )\d+\.\d+\.\d+\.\d+", RegexOptions.IgnoreCase);
if (match.Success && IPAddress.TryParse(match.Value, out var address)) if (match.Success && IPAddress.TryParse(match.Value, out var address))

View File

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastGithub.Scanner.DomainAddressProviders namespace FastGithub.Scanner.DomainAddressProviders
@ -41,7 +42,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
/// 创建域名与ip的关系 /// 创建域名与ip的关系
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync() public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync(CancellationToken cancellationToken)
{ {
var setting = this.options.CurrentValue.DominAddressProviders.PublicDnsProvider; var setting = this.options.CurrentValue.DominAddressProviders.PublicDnsProvider;
if (setting.Enable == false) if (setting.Enable == false)
@ -52,7 +53,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
var result = new HashSet<DomainAddress>(); var result = new HashSet<DomainAddress>();
foreach (var dns in setting.Dnss) foreach (var dns in setting.Dnss)
{ {
var domainAddresses = await this.LookupAsync(dns, setting.Domains); var domainAddresses = await this.LookupAsync(dns, setting.Domains, cancellationToken);
foreach (var item in domainAddresses) foreach (var item in domainAddresses)
{ {
result.Add(item); result.Add(item);
@ -68,7 +69,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
/// <param name="dns">dns服务器</param> /// <param name="dns">dns服务器</param>
/// <param name="domains">域名</param> /// <param name="domains">域名</param>
/// <returns></returns> /// <returns></returns>
private async Task<List<DomainAddress>> LookupAsync(string dns, IEnumerable<string> domains) private async Task<List<DomainAddress>> LookupAsync(string dns, IEnumerable<string> domains, CancellationToken cancellationToken)
{ {
var client = new DnsClient(dns); var client = new DnsClient(dns);
var result = new List<DomainAddress>(); var result = new List<DomainAddress>();
@ -77,7 +78,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
{ {
try try
{ {
var addresses = await client.Lookup(domain); var addresses = await client.Lookup(domain, cancellationToken: cancellationToken);
foreach (var address in addresses) foreach (var address in addresses)
{ {
if (address.AddressFamily == AddressFamily.InterNetwork) if (address.AddressFamily == AddressFamily.InterNetwork)
@ -88,6 +89,7 @@ namespace FastGithub.Scanner.DomainAddressProviders
} }
catch (Exception) catch (Exception)
{ {
cancellationToken.ThrowIfCancellationRequested();
this.logger.LogWarning($"dns({dns})无法解析{domain}"); this.logger.LogWarning($"dns({dns})无法解析{domain}");
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Net; using System.Net;
using System.Threading;
namespace FastGithub.Scanner namespace FastGithub.Scanner
{ {
@ -13,6 +14,11 @@ namespace FastGithub.Scanner
/// </summary> /// </summary>
public bool Available { get; set; } public bool Available { get; set; }
/// <summary>
/// 设置取消令牌
/// </summary>
public CancellationToken CancellationToken { get; }
/// <summary> /// <summary>
/// 获取扫描历史信息 /// 获取扫描历史信息
/// </summary> /// </summary>
@ -25,8 +31,20 @@ namespace FastGithub.Scanner
/// <param name="domain"></param> /// <param name="domain"></param>
/// <param name="address"></param> /// <param name="address"></param>
public GithubContext(string domain, IPAddress address) 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) : base(domain, address)
{ {
this.CancellationToken = cancellationToken;
} }
public bool Equals(GithubContext? other) public bool Equals(GithubContext? other)

View File

@ -36,7 +36,7 @@ namespace FastGithub
{ {
while (stoppingToken.IsCancellationRequested == false) while (stoppingToken.IsCancellationRequested == false)
{ {
await githubScanService.ScanAllAsync(); await githubScanService.ScanAllAsync(stoppingToken);
await Task.Delay(this.options.CurrentValue.Scan.FullScanInterval, stoppingToken); await Task.Delay(this.options.CurrentValue.Scan.FullScanInterval, stoppingToken);
} }
} }

View File

@ -39,6 +39,6 @@ namespace FastGithub
await Task.Delay(this.options.CurrentValue.Scan.ResultScanInterval, stoppingToken); await Task.Delay(this.options.CurrentValue.Scan.ResultScanInterval, stoppingToken);
await githubScanService.ScanResultAsync(); await githubScanService.ScanResultAsync();
} }
} }
} }
} }

View File

@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastGithub.Scanner namespace FastGithub.Scanner
@ -54,13 +55,13 @@ namespace FastGithub.Scanner
/// 扫描所有的ip /// 扫描所有的ip
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task ScanAllAsync() public async Task ScanAllAsync(CancellationToken cancellationToken)
{ {
this.logger.LogInformation("完整扫描开始.."); this.logger.LogInformation("完整扫描开始..");
var domainAddresses = await this.domainAddressFactory.CreateDomainAddressesAsync(); var domainAddresses = await this.domainAddressFactory.CreateDomainAddressesAsync(cancellationToken);
var scanTasks = domainAddresses var scanTasks = domainAddresses
.Select(item => new GithubContext(item.Domain, item.Address)) .Select(item => new GithubContext(item.Domain, item.Address, cancellationToken))
.Select(ctx => ScanAsync(ctx)); .Select(ctx => ScanAsync(ctx));
var results = await Task.WhenAll(scanTasks); var results = await Task.WhenAll(scanTasks);

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastGithub.Scanner namespace FastGithub.Scanner
@ -17,6 +18,6 @@ namespace FastGithub.Scanner
/// 创建域名与ip的关系 /// 创建域名与ip的关系
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync(); Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync(CancellationToken cancellationToken);
} }
} }

View File

@ -73,7 +73,7 @@ namespace FastGithub.Scanner
if (index >= 0) if (index >= 0)
{ {
var start = range.Slice(0, index); var start = range.Slice(0, index);
var end = range.Slice(index + 1); var end = range[(index + 1)..];
if (IPAddress.TryParse(start, out var startIp) && if (IPAddress.TryParse(start, out var startIp) &&
IPAddress.TryParse(end, out var endIp) && IPAddress.TryParse(end, out var endIp) &&

View File

@ -32,7 +32,7 @@ namespace FastGithub.Scanner.ScanMiddlewares
{ {
try try
{ {
await this.semaphoreSlim.WaitAsync(); await this.semaphoreSlim.WaitAsync(context.CancellationToken);
await next(); await next();
} }
finally finally

View File

@ -53,26 +53,24 @@ namespace FastGithub.Scanner.ScanMiddlewares
Method = HttpMethod.Head, Method = HttpMethod.Head,
RequestUri = new Uri($"https://{context.Address}"), RequestUri = new Uri($"https://{context.Address}"),
}; };
request.Headers.Host = context.Domain; request.Headers.Host = context.Domain;
var timeout = this.options.CurrentValue.Scan.HttpsScanTimeout; var timeout = this.options.CurrentValue.Scan.HttpsScanTimeout;
using var cancellationTokenSource = new CancellationTokenSource(timeout); using var timeoutTokenSource = new CancellationTokenSource(timeout);
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, context.CancellationToken);
var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub)); var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub));
using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token); using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, linkedTokenSource.Token);
VerifyHttpsResponse(context.Domain, response); VerifyHttpsResponse(context.Domain, response);
context.Available = true; context.Available = true;
await next(); await next();
} }
catch (TaskCanceledException)
{
this.logger.LogTrace($"{context.Domain} {context.Address}连接超时");
}
catch (Exception ex) catch (Exception ex)
{ {
var message = GetInnerMessage(ex); context.CancellationToken.ThrowIfCancellationRequested();
this.logger.LogTrace($"{context.Domain} {context.Address} {message}"); this.logger.LogTrace($"{context.Domain} {context.Address} { GetInnerMessage(ex)}");
} }
} }

View File

@ -32,20 +32,23 @@ namespace FastGithub.Scanner.ScanMiddlewares
public async Task InvokeAsync(GithubContext context, Func<Task> next) public async Task InvokeAsync(GithubContext context, Func<Task> next)
{ {
var stopwatch = new Stopwatch(); var stopwatch = new Stopwatch();
stopwatch.Start();
try try
{ {
stopwatch.Start();
await next(); await next();
} }
finally finally
{ {
stopwatch.Stop(); stopwatch.Stop();
context.History.Add(context.Available, stopwatch.Elapsed);
if (context.History.AvailableRate > 0d) if (context.CancellationToken.IsCancellationRequested == false)
{ {
this.logger.LogInformation(context.ToString()); context.History.Add(context.Available, stopwatch.Elapsed);
if (context.History.AvailableRate > 0d)
{
this.logger.LogInformation(context.ToString());
}
} }
} }
} }

View File

@ -71,14 +71,17 @@ namespace FastGithub.Scanner.ScanMiddlewares
{ {
try try
{ {
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var timeout = this.options.CurrentValue.Scan.TcpScanTimeout; var timeout = this.options.CurrentValue.Scan.TcpScanTimeout;
using var cancellationTokenSource = new CancellationTokenSource(timeout); using var timeoutTokenSource = new CancellationTokenSource(timeout);
await socket.ConnectAsync(context.Address, PORT, cancellationTokenSource.Token); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, context.CancellationToken);
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync(context.Address, PORT, linkedTokenSource.Token);
return true; return true;
} }
catch (Exception) catch (Exception)
{ {
context.CancellationToken.ThrowIfCancellationRequested();
return false; return false;
} }
} }

View File

@ -31,7 +31,7 @@ namespace FastGithub
c.Service<IHost>(service => service c.Service<IHost>(service => service
.ConstructUsing(() => hostBuilder.Build()) .ConstructUsing(() => hostBuilder.Build())
.WhenStarted(service => service.Start()) .WhenStarted(service => service.Start())
.WhenStopped(service => service.StopAsync()) .WhenStopped(service => service.StopAsync().Wait())
); );
}); });
} }