使用IDispose接口来关闭服务
This commit is contained in:
parent
249ff7a081
commit
60784caa76
@ -145,10 +145,16 @@ namespace FastGithub.DomainResolve
|
|||||||
RecursionDesired = true,
|
RecursionDesired = true,
|
||||||
OperationCode = OperationCode.Query
|
OperationCode = OperationCode.Query
|
||||||
};
|
};
|
||||||
|
|
||||||
request.Questions.Add(new Question(new Domain(domain), RecordType.A));
|
request.Questions.Add(new Question(new Domain(domain), RecordType.A));
|
||||||
var clientRequest = new ClientRequest(resolver, request);
|
var clientRequest = new ClientRequest(resolver, request);
|
||||||
var response = await clientRequest.Resolve(cancellationToken);
|
var response = await clientRequest.Resolve(cancellationToken);
|
||||||
return response.AnswerRecords.OfType<IPAddressResourceRecord>().Select(item => item.IPAddress).ToArray();
|
|
||||||
|
return response.AnswerRecords
|
||||||
|
.OfType<IPAddressResourceRecord>()
|
||||||
|
.Where(item => IPAddress.IsLoopback(item.IPAddress) == false)
|
||||||
|
.Select(item => item.IPAddress)
|
||||||
|
.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using FastGithub.Configuration;
|
using FastGithub.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -15,11 +16,13 @@ namespace FastGithub.DomainResolve
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// DnscryptProxy服务
|
/// DnscryptProxy服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
sealed class DnscryptProxy
|
sealed class DnscryptProxy : IDisposable
|
||||||
{
|
{
|
||||||
private const string PATH = "dnscrypt-proxy";
|
private const string PATH = "dnscrypt-proxy";
|
||||||
private const string NAME = "dnscrypt-proxy";
|
private const string NAME = "dnscrypt-proxy";
|
||||||
|
|
||||||
|
private readonly ILogger<DnscryptProxy> logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 相关进程
|
/// 相关进程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -30,12 +33,38 @@ namespace FastGithub.DomainResolve
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IPEndPoint? LocalEndPoint { get; private set; }
|
public IPEndPoint? LocalEndPoint { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DnscryptProxy服务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger"></param>
|
||||||
|
public DnscryptProxy(ILogger<DnscryptProxy> logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动dnscrypt-proxy
|
/// 启动dnscrypt-proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
public async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.StartCoreAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.logger.LogWarning($"{NAME}启动失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动dnscrypt-proxy
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task StartCoreAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tomlPath = Path.Combine(PATH, $"{NAME}.toml");
|
var tomlPath = Path.Combine(PATH, $"{NAME}.toml");
|
||||||
var port = GetAvailablePort(IPAddress.Loopback.AddressFamily);
|
var port = GetAvailablePort(IPAddress.Loopback.AddressFamily);
|
||||||
@ -70,8 +99,6 @@ namespace FastGithub.DomainResolve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取可用的随机端口
|
/// 获取可用的随机端口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -113,35 +140,6 @@ namespace FastGithub.DomainResolve
|
|||||||
this.LocalEndPoint = null;
|
this.LocalEndPoint = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 停止dnscrypt-proxy
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Stop()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
{
|
|
||||||
StartDnscryptProxy("-service stop")?.WaitForExit();
|
|
||||||
StartDnscryptProxy("-service uninstall")?.WaitForExit();
|
|
||||||
}
|
|
||||||
if (this.process != null && this.process.HasExited == false)
|
|
||||||
{
|
|
||||||
this.process.Kill();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
this.LocalEndPoint = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动DnscryptProxy进程
|
/// 启动DnscryptProxy进程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -160,6 +158,41 @@ namespace FastGithub.DomainResolve
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 释放资源
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.Stop();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.logger.LogWarning($"{NAME}停止失败:{ex.Message }");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.LocalEndPoint = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止服务
|
||||||
|
/// </summary>
|
||||||
|
private void Stop()
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
StartDnscryptProxy("-service stop")?.WaitForExit();
|
||||||
|
StartDnscryptProxy("-service uninstall")?.WaitForExit();
|
||||||
|
}
|
||||||
|
if (this.process != null && this.process.HasExited == false)
|
||||||
|
{
|
||||||
|
this.process.Kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换为字符串
|
/// 转换为字符串
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -13,7 +12,6 @@ namespace FastGithub.DomainResolve
|
|||||||
{
|
{
|
||||||
private readonly DnscryptProxy dnscryptProxy;
|
private readonly DnscryptProxy dnscryptProxy;
|
||||||
private readonly DomainSpeedTester speedTester;
|
private readonly DomainSpeedTester speedTester;
|
||||||
private readonly ILogger<DomainResolveHostedService> logger;
|
|
||||||
|
|
||||||
private readonly TimeSpan speedTestDueTime = TimeSpan.FromSeconds(10d);
|
private readonly TimeSpan speedTestDueTime = TimeSpan.FromSeconds(10d);
|
||||||
private readonly TimeSpan speedTestPeriod = TimeSpan.FromMinutes(2d);
|
private readonly TimeSpan speedTestPeriod = TimeSpan.FromMinutes(2d);
|
||||||
@ -22,29 +20,14 @@ namespace FastGithub.DomainResolve
|
|||||||
/// 域名解析后台服务
|
/// 域名解析后台服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dnscryptProxy"></param>
|
/// <param name="dnscryptProxy"></param>
|
||||||
/// <param name="speedTester"></param>
|
/// <param name="speedTester"></param>
|
||||||
/// <param name="logger"></param>
|
|
||||||
public DomainResolveHostedService(
|
public DomainResolveHostedService(
|
||||||
DnscryptProxy dnscryptProxy,
|
DnscryptProxy dnscryptProxy,
|
||||||
DomainSpeedTester speedTester,
|
DomainSpeedTester speedTester)
|
||||||
ILogger<DomainResolveHostedService> logger)
|
|
||||||
{
|
{
|
||||||
this.dnscryptProxy = dnscryptProxy;
|
this.dnscryptProxy = dnscryptProxy;
|
||||||
this.speedTester = speedTester;
|
this.speedTester = speedTester;
|
||||||
this.logger = logger;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 停止时
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await this.speedTester.SaveDomainsAsync();
|
|
||||||
this.dnscryptProxy.Stop();
|
|
||||||
await base.StopAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 后台任务
|
/// 后台任务
|
||||||
@ -53,17 +36,9 @@ namespace FastGithub.DomainResolve
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
try
|
await this.dnscryptProxy.StartAsync(stoppingToken);
|
||||||
{
|
|
||||||
await this.dnscryptProxy.StartAsync(stoppingToken);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
this.logger.LogWarning($"{this.dnscryptProxy}启动失败:{ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(this.speedTestDueTime, stoppingToken);
|
await Task.Delay(this.speedTestDueTime, stoppingToken);
|
||||||
await this.speedTester.LoadDomainsAsync(stoppingToken);
|
|
||||||
while (stoppingToken.IsCancellationRequested == false)
|
while (stoppingToken.IsCancellationRequested == false)
|
||||||
{
|
{
|
||||||
await this.speedTester.TestSpeedAsync(stoppingToken);
|
await this.speedTester.TestSpeedAsync(stoppingToken);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using FastGithub.Configuration;
|
using FastGithub.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -13,10 +14,12 @@ namespace FastGithub.DomainResolve
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 域名的IP测速服务
|
/// 域名的IP测速服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
sealed class DomainSpeedTester
|
sealed class DomainSpeedTester : IDisposable
|
||||||
{
|
{
|
||||||
private const string DOMAINS_JSON_FILE = "domains.json";
|
private const string DOMAINS_JSON_FILE = "domains.json";
|
||||||
|
|
||||||
private readonly DnsClient dnsClient;
|
private readonly DnsClient dnsClient;
|
||||||
|
private readonly ILogger<DomainSpeedTester> logger;
|
||||||
|
|
||||||
private readonly object syncRoot = new();
|
private readonly object syncRoot = new();
|
||||||
private readonly Dictionary<string, IPAddressItemHashSet> domainIPAddressHashSet = new();
|
private readonly Dictionary<string, IPAddressItemHashSet> domainIPAddressHashSet = new();
|
||||||
@ -25,9 +28,45 @@ namespace FastGithub.DomainResolve
|
|||||||
/// 域名的IP测速服务
|
/// 域名的IP测速服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dnsClient"></param>
|
/// <param name="dnsClient"></param>
|
||||||
public DomainSpeedTester(DnsClient dnsClient)
|
/// <param name="logger"></param>
|
||||||
|
public DomainSpeedTester(
|
||||||
|
DnsClient dnsClient,
|
||||||
|
ILogger<DomainSpeedTester> logger)
|
||||||
{
|
{
|
||||||
this.dnsClient = dnsClient;
|
this.dnsClient = dnsClient;
|
||||||
|
this.logger = logger;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.LoadDomains();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogWarning($"加载域名数据失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载域名数据
|
||||||
|
/// </summary>
|
||||||
|
private void LoadDomains()
|
||||||
|
{
|
||||||
|
if (File.Exists(DOMAINS_JSON_FILE) == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var utf8Json = File.ReadAllBytes(DOMAINS_JSON_FILE);
|
||||||
|
var domains = JsonSerializer.Deserialize<string[]>(utf8Json);
|
||||||
|
if (domains == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var domain in domains)
|
||||||
|
{
|
||||||
|
this.domainIPAddressHashSet.TryAdd(domain, new IPAddressItemHashSet());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -60,58 +99,6 @@ namespace FastGithub.DomainResolve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载域名数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task LoadDomainsAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (File.Exists(DOMAINS_JSON_FILE) == false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var fileStream = File.OpenRead(DOMAINS_JSON_FILE);
|
|
||||||
var domains = await JsonSerializer.DeserializeAsync<string[]>(fileStream, cancellationToken: cancellationToken);
|
|
||||||
if (domains == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (this.syncRoot)
|
|
||||||
{
|
|
||||||
foreach (var domain in domains)
|
|
||||||
{
|
|
||||||
this.domainIPAddressHashSet.TryAdd(domain, new IPAddressItemHashSet());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存域名数据
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> SaveDomainsAsync()
|
|
||||||
{
|
|
||||||
var domains = this.domainIPAddressHashSet.Keys
|
|
||||||
.Select(item => new DomainPattern(item))
|
|
||||||
.OrderBy(item => item)
|
|
||||||
.Select(item => item.ToString())
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var fileStream = File.OpenWrite(DOMAINS_JSON_FILE);
|
|
||||||
await JsonSerializer.SerializeAsync(fileStream, domains, new JsonSerializerOptions { WriteIndented = true });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 进行一轮IP测速
|
/// 进行一轮IP测速
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -136,5 +123,35 @@ namespace FastGithub.DomainResolve
|
|||||||
await hashSet.PingAllAsync();
|
await hashSet.PingAllAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 释放资源
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.SaveDomains();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.logger.LogWarning($"保存域名数据失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存域名
|
||||||
|
/// </summary>
|
||||||
|
private void SaveDomains()
|
||||||
|
{
|
||||||
|
var domains = this.domainIPAddressHashSet.Keys
|
||||||
|
.Select(item => new DomainPattern(item))
|
||||||
|
.OrderBy(item => item)
|
||||||
|
.Select(item => item.ToString())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var utf8Json = JsonSerializer.SerializeToUtf8Bytes(domains, new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
File.WriteAllBytes(DOMAINS_JSON_FILE, utf8Json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user