添加项目文件。

This commit is contained in:
陈国伟 2021-06-11 13:37:28 +08:00
parent 5b39a543fd
commit 553b7f8c07
16 changed files with 2546 additions and 0 deletions

25
FastGithub.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31320.298
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub", "FastGithub\FastGithub.csproj", "{C1099390-6103-4917-A740-A3002B542FE0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C1099390-6103-4917-A740-A3002B542FE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C1099390-6103-4917-A740-A3002B542FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C1099390-6103-4917-A740-A3002B542FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1099390-6103-4917-A740-A3002B542FE0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AC66D417-C355-4DFD-BC3C-DD0383F855D3}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="meta.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

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

View File

@ -0,0 +1,36 @@
using System;
using System.Threading.Tasks;
namespace FastGithub
{
/// <summary>
/// 中间件创建者扩展
/// </summary>
static class GithubBuilderExtensions
{
/// <summary>
/// 使用中间件
/// </summary>
/// <typeparam name="TMiddleware"></typeparam>
/// <param name="builder"></param>
/// <returns></returns>
public static IGithubBuilder Use<TMiddleware>(this IGithubBuilder builder) where TMiddleware : class, IGithubMiddleware
{
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 IGithubBuilder Use(this IGithubBuilder builder, Func<GithubContext, Func<Task>, Task> middleware)
{
return builder.Use(next => context => middleware(context, () => next(context)));
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net;
namespace FastGithub
{
class GithubContext
{
[AllowNull]
public IPAddress Address { get; set; }
public TimeSpan? HttpElapsed { get; set; }
}
}

View File

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

View File

@ -0,0 +1,68 @@
using FastGithub.Middlewares;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub
{
sealed class GithubHostedService : BackgroundService
{
private readonly GithubDelegate githubDelegate;
private readonly ILogger<GithubHostedService> logger;
public GithubHostedService(
IServiceProvider appServiceProvider,
ILogger<GithubHostedService> logger)
{
this.githubDelegate = new GithubBuilder(appServiceProvider, ctx => Task.CompletedTask)
.Use<ConcurrentMiddleware>()
.Use<PortScanMiddleware>()
.Use<HttpTestMiddleware>()
.Build();
this.logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var stream = File.OpenRead("meta.json");
var meta = await JsonSerializer.DeserializeAsync<Meta>(stream, cancellationToken: stoppingToken);
if (meta != null)
{
var contexts = new List<GithubContext>();
var tasks = this.GetScanTasks(meta, contexts);
await Task.WhenAll(tasks);
var orderByContexts = contexts
.Where(item => item.HttpElapsed != null)
.OrderBy(item => item.HttpElapsed);
foreach (var context in orderByContexts)
{
this.logger.LogInformation($"{context.Address} {context.HttpElapsed}");
}
}
this.logger.LogInformation("扫描结束");
}
private IEnumerable<Task> GetScanTasks(Meta meta, IList<GithubContext> contexts)
{
foreach (var address in meta.ToIPv4Address())
{
var context = new GithubContext
{
Address = address,
};
contexts.Add(context);
yield return this.githubDelegate(context);
}
}
}
}

View File

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

View File

@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;
namespace FastGithub
{
/// <summary>
/// 定义中间件的接口
/// </summary>
interface IGithubMiddleware
{
/// <summary>
/// 执行中间件
/// </summary>
/// <param name="context">上下文</param>
/// <param name="next">下一个中间件</param>
/// <returns></returns>
Task InvokeAsync(GithubContext context, Func<Task> next);
}
}

78
FastGithub/IPv4CIDR.cs Normal file
View File

@ -0,0 +1,78 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Sockets;
namespace FastGithub
{
sealed class IPv4CIDR
{
public IPAddress IPAddress { get; }
public int Mask { get; }
public int Size { get; }
public IPv4CIDR(IPAddress ipAddress, int mask)
{
this.IPAddress = ipAddress;
this.Mask = mask;
this.Size = (int)(uint.MaxValue << mask >> mask);
}
public IEnumerable<IPAddress> GetAllIPAddress()
{
for (var i = 0; i < this.Size; i++)
{
yield return Add(this.IPAddress, i);
}
}
/// <summary>
/// 添加值
/// </summary>
/// <param name="ip"></param>
/// <param name="value"></param>
/// <returns></returns>
private static IPAddress Add(IPAddress ip, int value)
{
var span = ip.GetAddressBytes().AsSpan();
var hostValue = BinaryPrimitives.ReadInt32BigEndian(span);
BinaryPrimitives.WriteInt32BigEndian(span, hostValue + value);
return new IPAddress(span);
}
public static bool TryParse(ReadOnlySpan<char> cidr, [MaybeNullWhen(false)] out IPv4CIDR value)
{
value = null;
var index = cidr.IndexOf('/');
if (index <= 0)
{
return false;
}
var addressSpan = cidr.Slice(0, index);
if (IPAddress.TryParse(addressSpan, out var address) == false
|| address.AddressFamily != AddressFamily.InterNetwork)
{
return false;
}
var maskSpan = cidr.Slice(index + 1);
if (int.TryParse(maskSpan, out var mask) == false)
{
return false;
}
value = new IPv4CIDR(address, mask);
return true;
}
public override string ToString()
{
return $"{this.IPAddress}/{this.Mask}";
}
}
}

54
FastGithub/Meta.cs Normal file
View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.Json.Serialization;
namespace FastGithub
{
class Meta
{
[JsonPropertyName("hooks")]
public string[] Hooks { get; set; } = Array.Empty<string>();
[JsonPropertyName("web")]
public string[] Web { get; set; } = Array.Empty<string>();
[JsonPropertyName("api")]
public string[] Api { get; set; } = Array.Empty<string>();
[JsonPropertyName("git")]
public string[] Git { get; set; } = Array.Empty<string>();
[JsonPropertyName("packages")]
public string[] Packages { get; set; } = Array.Empty<string>();
[JsonPropertyName("pages")]
public string[] Pages { get; set; } = Array.Empty<string>();
[JsonPropertyName("importer")]
public string[] Importer { get; set; } = Array.Empty<string>();
[JsonPropertyName("actions")]
public string[] Actions { get; set; } = Array.Empty<string>();
[JsonPropertyName("dependabot")]
public string[] Dependabot { get; set; } = Array.Empty<string>();
public IEnumerable<IPAddress> ToIPv4Address()
{
var cidrs = this.Web.Concat(this.Api);
foreach (var cidr in cidrs)
{
if (IPv4CIDR.TryParse(cidr, out var value))
{
foreach (var ip in value.GetAllIPAddress())
{
yield return ip;
}
}
}
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Middlewares
{
sealed class ConcurrentMiddleware : IGithubMiddleware
{
private readonly SemaphoreSlim semaphoreSlim = new(50);
public async Task InvokeAsync(GithubContext context, Func<Task> next)
{
try
{
await this.semaphoreSlim.WaitAsync();
await next();
}
finally
{
this.semaphoreSlim.Release();
}
}
}
}

View File

@ -0,0 +1,52 @@
using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Middlewares
{
sealed class HttpTestMiddleware : IGithubMiddleware
{
private readonly TimeSpan timeout = TimeSpan.FromSeconds(5d);
private readonly ILogger<HttpTestMiddleware> logger;
public HttpTestMiddleware(ILogger<HttpTestMiddleware> logger)
{
this.logger = logger;
}
public async Task InvokeAsync(GithubContext context, Func<Task> next)
{
try
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri($"https://{context.Address}/manifest.json"),
};
request.Headers.Host = "github.com";
using var httpClient = new HttpClient(new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
});
var startTime = DateTime.Now;
using var cancellationTokenSource = new CancellationTokenSource(this.timeout);
var response = await httpClient.SendAsync(request, cancellationTokenSource.Token);
var media = response.EnsureSuccessStatusCode().Content.Headers.ContentType?.MediaType;
if (string.Equals(media, "application/manifest+json"))
{
context.HttpElapsed = DateTime.Now.Subtract(startTime);
await next();
}
}
catch (Exception ex)
{
this.logger.LogInformation($"{context.Address} {ex.Message}");
}
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.Extensions.Logging;
using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Middlewares
{
sealed class PortScanMiddleware : IGithubMiddleware
{
private readonly TimeSpan timeout = TimeSpan.FromSeconds(1d);
private readonly ILogger<PortScanMiddleware> logger;
public PortScanMiddleware(ILogger<PortScanMiddleware> logger)
{
this.logger = logger;
}
public async Task InvokeAsync(GithubContext context, Func<Task> next)
{
try
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
using var cancellationTokenSource = new CancellationTokenSource(this.timeout);
await socket.ConnectAsync(context.Address, 443, cancellationTokenSource.Token);
await next();
}
catch (Exception)
{
this.logger.LogInformation($"{context.Address}的443端口未开放");
}
}
}
}

39
FastGithub/Program.cs Normal file
View File

@ -0,0 +1,39 @@
using FastGithub.Middlewares;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace FastGithub
{
class Program
{
/// <summary>
/// 程序入口
/// </summary>
/// <param name="args"></param>
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
/// <summary>
/// 创建host
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host
.CreateDefaultBuilder(args)
.ConfigureServices((ctx, services) =>
{
services
.AddSingleton<PortScanMiddleware>()
.AddSingleton<HttpTestMiddleware>()
.AddSingleton<ConcurrentMiddleware>()
.AddHostedService<GithubHostedService>()
;
});
}
}
}

1977
FastGithub/meta.json Normal file

File diff suppressed because it is too large Load Diff