结果扫描与完整搜索不共用锁

This commit is contained in:
陈国伟 2021-06-16 09:25:16 +08:00
parent 0be061086d
commit a9025be505
15 changed files with 270 additions and 158 deletions

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>FastGithub</RootNamespace>
</PropertyGroup>
<ItemGroup>

View File

@ -1,12 +1,13 @@
using System;
using System.Threading.Tasks;
namespace FastGithub.Scanner
namespace FastGithub
{
/// <summary>
/// 定义中间件的接口
/// </summary>
interface IGithubScanMiddleware
/// <typeparam name="TContext"></typeparam>
public interface IMiddleware<TContext>
{
/// <summary>
/// 执行中间件
@ -14,6 +15,6 @@ namespace FastGithub.Scanner
/// <param name="context">上下文</param>
/// <param name="next">下一个中间件</param>
/// <returns></returns>
Task InvokeAsync(GithubContext context, Func<Task> next);
Task InvokeAsync(TContext context, Func<Task> next);
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Threading.Tasks;
namespace FastGithub
{
/// <summary>
/// 定义中间件管道创建者的接口
/// </summary>
/// <typeparam name="TContext">中间件上下文</typeparam>
public interface IPipelineBuilder<TContext>
{
/// <summary>
/// 获取服务提供者
/// </summary>
IServiceProvider AppServices { get; }
/// <summary>
/// 使用中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <typeparam name="TMiddleware"></typeparam>
/// <param name="builder"></param>
/// <returns></returns>
IPipelineBuilder<TContext> Use<TMiddleware>() where TMiddleware : class, IMiddleware<TContext>;
/// <summary>
/// 使用中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="builder"></param>
/// <param name="middleware"></param>
/// <returns></returns>
IPipelineBuilder<TContext> Use(Func<TContext, Func<Task>, Task> middleware);
/// <summary>
/// 使用中间件
/// </summary>
/// <param name="middleware">中间件</param>
/// <returns></returns>
IPipelineBuilder<TContext> Use(Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>> middleware);
/// <summary>
/// 创建所有中间件执行处理者
/// </summary>
/// <returns></returns>
InvokeDelegate<TContext> Build();
/// <summary>
/// 使用默认配制创建新的PipelineBuilder
/// </summary>
/// <returns></returns>
IPipelineBuilder<TContext> New();
}
}

View File

@ -1,11 +1,12 @@
using System.Threading.Tasks;
namespace FastGithub.Scanner
namespace FastGithub
{
/// <summary>
/// 表示所有中间件执行委托
/// </summary>
/// <typeparam name="TContext">中间件上下文类型</typeparam>
/// <param name="context">中间件上下文</param>
/// <returns></returns>
delegate Task GithubScanDelegate(GithubContext context);
public delegate Task InvokeDelegate<TContext>(TContext context);
}

View File

@ -0,0 +1,103 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FastGithub
{
/// <summary>
/// 表示中间件创建者
/// </summary>
public class PipelineBuilder<TContext> : IPipelineBuilder<TContext>
{
private readonly InvokeDelegate<TContext> completedHandler;
private readonly List<Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>>> middlewares = new List<Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>>>();
/// <summary>
/// 获取服务提供者
/// </summary>
public IServiceProvider AppServices { get; }
/// <summary>
/// 中间件创建者
/// </summary>
/// <param name="appServices"></param>
public PipelineBuilder(IServiceProvider appServices)
: this(appServices, context => Task.CompletedTask)
{
}
/// <summary>
/// 中间件创建者
/// </summary>
/// <param name="appServices"></param>
/// <param name="completedHandler">完成执行内容处理者</param>
public PipelineBuilder(IServiceProvider appServices, InvokeDelegate<TContext> completedHandler)
{
this.AppServices = appServices;
this.completedHandler = completedHandler;
}
/// <summary>
/// 使用中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <typeparam name="TMiddleware"></typeparam>
/// <param name="builder"></param>
/// <returns></returns>
public IPipelineBuilder<TContext> Use<TMiddleware>() where TMiddleware : class, IMiddleware<TContext>
{
var middleware = this.AppServices.GetRequiredService<TMiddleware>();
return this.Use(middleware.InvokeAsync);
}
/// <summary>
/// 使用中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="builder"></param>
/// <param name="middleware"></param>
/// <returns></returns>
public IPipelineBuilder<TContext> Use(Func<TContext, Func<Task>, Task> middleware)
{
return this.Use(next => context => middleware(context, () => next(context)));
}
/// <summary>
/// 使用中间件
/// </summary>
/// <param name="middleware"></param>
/// <returns></returns>
public IPipelineBuilder<TContext> Use(Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>> middleware)
{
this.middlewares.Add(middleware);
return this;
}
/// <summary>
/// 创建所有中间件执行处理者
/// </summary>
/// <returns></returns>
public InvokeDelegate<TContext> Build()
{
var handler = this.completedHandler;
for (var i = this.middlewares.Count - 1; i >= 0; i--)
{
handler = this.middlewares[i](handler);
}
return handler;
}
/// <summary>
/// 使用默认配制创建新的PipelineBuilder
/// </summary>
/// <returns></returns>
public IPipelineBuilder<TContext> New()
{
return new PipelineBuilder<TContext>(this.AppServices, this.completedHandler);
}
}
}

View File

@ -0,0 +1,71 @@
using System;
namespace FastGithub
{
/// <summary>
/// 中间件创建者扩展
/// </summary>
public static class PipelineBuilderExtensions
{
/// <summary>
/// 中断执行中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="builder"></param>
/// <param name="handler">处理者</param>
/// <returns></returns>
public static IPipelineBuilder<TContext> Run<TContext>(this IPipelineBuilder<TContext> builder, InvokeDelegate<TContext> handler)
{
return builder.Use(_ => handler);
}
/// <summary>
/// 条件中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="builder"></param>
/// <param name="predicate"></param>
/// <param name="handler"></param>
/// <returns></returns>
public static IPipelineBuilder<TContext> When<TContext>(this IPipelineBuilder<TContext> builder, Func<TContext, bool> predicate, InvokeDelegate<TContext> handler)
{
return builder.Use(next => async context =>
{
if (predicate.Invoke(context) == true)
{
await handler.Invoke(context);
}
else
{
await next(context);
}
});
}
/// <summary>
/// 条件中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="builder"></param>
/// <param name="predicate"></param>
/// <param name="configureAction"></param>
/// <returns></returns>
public static IPipelineBuilder<TContext> When<TContext>(this IPipelineBuilder<TContext> builder, Func<TContext, bool> predicate, Action<IPipelineBuilder<TContext>> configureAction)
{
return builder.Use(next => async context =>
{
if (predicate.Invoke(context) == true)
{
var branchBuilder = builder.New();
configureAction(branchBuilder);
await branchBuilder.Build().Invoke(context);
}
else
{
await next(context);
}
});
}
}
}

View File

@ -1,66 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FastGithub.Scanner
{
/// <summary>
/// 表示中间件创建者
/// </summary>
sealed class GithubScanBuilder : IGithubScanBuilder
{
private readonly GithubScanDelegate completedHandler;
private readonly List<Func<GithubScanDelegate, GithubScanDelegate>> middlewares = new();
/// <summary>
/// 获取服务提供者
/// </summary>
public IServiceProvider AppServices { get; }
/// <summary>
/// 中间件创建者
/// </summary>
/// <param name="appServices"></param>
public GithubScanBuilder(IServiceProvider appServices)
: this(appServices, context => Task.CompletedTask)
{
}
/// <summary>
/// 中间件创建者
/// </summary>
/// <param name="appServices"></param>
/// <param name="completedHandler">完成执行内容处理者</param>
public GithubScanBuilder(IServiceProvider appServices, GithubScanDelegate completedHandler)
{
this.AppServices = appServices;
this.completedHandler = completedHandler;
}
/// <summary>
/// 使用中间件
/// </summary>
/// <param name="middleware"></param>
/// <returns></returns>
public IGithubScanBuilder Use(Func<GithubScanDelegate, GithubScanDelegate> middleware)
{
this.middlewares.Add(middleware);
return this;
}
/// <summary>
/// 创建所有中间件执行处理者
/// </summary>
/// <returns></returns>
public GithubScanDelegate Build()
{
var handler = this.completedHandler;
for (var i = this.middlewares.Count - 1; i >= 0; i--)
{
handler = this.middlewares[i](handler);
}
return handler;
}
}
}

View File

@ -1,36 +0,0 @@
using System;
using System.Threading.Tasks;
namespace FastGithub.Scanner
{
/// <summary>
/// 中间件创建者扩展
/// </summary>
static class GithubScanBuilderExtensions
{
/// <summary>
/// 使用中间件
/// </summary>
/// <typeparam name="TMiddleware"></typeparam>
/// <param name="builder"></param>
/// <returns></returns>
public static IGithubScanBuilder Use<TMiddleware>(this IGithubScanBuilder builder) where TMiddleware : class, IGithubScanMiddleware
{
return builder.AppServices.GetService(typeof(TMiddleware)) is TMiddleware middleware
? builder.Use(middleware.InvokeAsync)
: throw new InvalidOperationException($"无法获取服务{typeof(TMiddleware)}");
}
/// <summary>
/// 使用中间件
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="builder"></param>
/// <param name="middleware"></param>
/// <returns></returns>
public static IGithubScanBuilder Use(this IGithubScanBuilder builder, Func<GithubContext, Func<Task>, Task> middleware)
{
return builder.Use(next => context => middleware(context, () => next(context)));
}
}
}

View File

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using FastGithub.Scanner.Middlewares;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
@ -12,18 +13,34 @@ namespace FastGithub.Scanner
sealed class GithubScanService : IGithubScanService
{
private readonly GithubMetaService metaService;
private readonly GithubScanDelegate scanDelegate;
private readonly ILogger<GithubScanService> logger;
private readonly GithubContextHashSet results = new();
private readonly InvokeDelegate<GithubContext> fullScanDelegate;
private readonly InvokeDelegate<GithubContext> resultScanDelegate;
public GithubScanService(
GithubMetaService metaService,
GithubScanDelegate scanDelegate,
ILogger<GithubScanService> logger)
ILogger<GithubScanService> logger,
IPipelineBuilder<GithubContext> pipelineBuilder)
{
this.metaService = metaService;
this.scanDelegate = scanDelegate;
this.logger = logger;
this.fullScanDelegate = pipelineBuilder
.New()
.Use<ConcurrentMiddleware>()
.Use<PortScanMiddleware>()
.Use<HttpsScanMiddleware>()
.Use<ScanOkLogMiddleware>()
.Build();
this.resultScanDelegate = pipelineBuilder
.New()
.Use<PortScanMiddleware>()
.Use<HttpsScanMiddleware>()
.Use<ScanOkLogMiddleware>()
.Build();
}
public async Task ScanAllAsync(CancellationToken cancellationToken = default)
@ -40,7 +57,7 @@ namespace FastGithub.Scanner
async Task ScanAsync(GithubContext context)
{
await this.scanDelegate(context);
await this.fullScanDelegate(context);
if (context.HttpElapsed != null)
{
lock (this.results.SyncRoot)
@ -63,7 +80,7 @@ namespace FastGithub.Scanner
foreach (var context in contexts)
{
context.HttpElapsed = null;
await this.scanDelegate(context);
await this.resultScanDelegate(context);
}
this.logger.LogInformation("结果扫描结束");

View File

@ -1,28 +0,0 @@
using System;
namespace FastGithub.Scanner
{
/// <summary>
/// 定义中间件管道创建者的接口
/// </summary>
interface IGithubScanBuilder
{
/// <summary>
/// 获取服务提供者
/// </summary>
IServiceProvider AppServices { get; }
/// <summary>
/// 使用中间件
/// </summary>
/// <param name="middleware">中间件</param>
/// <returns></returns>
IGithubScanBuilder Use(Func<GithubScanDelegate, GithubScanDelegate> middleware);
/// <summary>
/// 创建所有中间件执行处理者
/// </summary>
/// <returns></returns>
GithubScanDelegate Build();
}
}

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace FastGithub.Scanner.Middlewares
{
[Service(ServiceLifetime.Singleton)]
sealed class ConcurrentMiddleware : IGithubScanMiddleware
sealed class ConcurrentMiddleware : IMiddleware<GithubContext>
{
private readonly SemaphoreSlim semaphoreSlim = new(Environment.ProcessorCount * 4);

View File

@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace FastGithub.Scanner.Middlewares
{
[Service(ServiceLifetime.Singleton)]
sealed class HttpsScanMiddleware : IGithubScanMiddleware
sealed class HttpsScanMiddleware : IMiddleware<GithubContext>
{
private readonly IOptionsMonitor<GithubOptions> options;
private readonly ILogger<HttpsScanMiddleware> logger;

View File

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace FastGithub.Scanner.Middlewares
{
[Service(ServiceLifetime.Singleton)]
sealed class PortScanMiddleware : IGithubScanMiddleware
sealed class PortScanMiddleware : IMiddleware<GithubContext>
{
private const int PORT = 443;
private readonly IOptionsMonitor<GithubOptions> options;

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace FastGithub.Scanner.Middlewares
{
[Service(ServiceLifetime.Singleton)]
sealed class ScanOkLogMiddleware : IGithubScanMiddleware
sealed class ScanOkLogMiddleware : IMiddleware<GithubContext>
{
private readonly ILogger<ScanOkLogMiddleware> logger;

View File

@ -1,5 +1,4 @@
using FastGithub.Scanner;
using FastGithub.Scanner.Middlewares;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
@ -22,18 +21,13 @@ namespace FastGithub
var assembly = typeof(ScannerServiceCollectionExtensions).Assembly;
return services
.AddHttpClient()
.AddSingleton(serviceProvider =>
{
return new GithubScanBuilder(serviceProvider, ctx => Task.CompletedTask)
.Use<ConcurrentMiddleware>()
.Use<PortScanMiddleware>()
.Use<HttpsScanMiddleware>()
.Use<ScanOkLogMiddleware>()
.Build();
})
.AddServiceAndOptions(assembly, configuration)
.AddHostedService<GithubFullScanHostedService>()
.AddHostedService<GithubResultScanHostedService>()
.AddSingleton<IPipelineBuilder<GithubContext>>(appService =>
{
return new PipelineBuilder<GithubContext>(appService, ctx => Task.CompletedTask);
})
;
}
}