Pārlūkot izejas kodu

使用IDispose接口来关闭服务

陈国伟 3 gadi atpakaļ
vecāks
revīzija
60784caa76

+ 7 - 1
FastGithub.DomainResolve/DnsClient.cs

@@ -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();
         }
         }
     }
     }
 }
 }

+ 63 - 30
FastGithub.DomainResolve/DnscryptProxy.cs

@@ -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>
@@ -114,27 +141,35 @@ namespace FastGithub.DomainResolve
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// 停止dnscrypt-proxy
+        /// 启动DnscryptProxy进程
         /// </summary>
         /// </summary>
-        /// <returns></returns>
-        public bool Stop()
+        /// <param name="arguments"></param> 
+        private static Process? StartDnscryptProxy(string arguments)
+        {
+            var fileName = OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME;
+            return Process.Start(new ProcessStartInfo
+            {
+                FileName = Path.Combine(PATH, fileName),
+                Arguments = arguments,
+                WorkingDirectory = PATH,
+                UseShellExecute = false,
+                CreateNoWindow = true,
+                WindowStyle = ProcessWindowStyle.Hidden
+            });
+        }
+
+        /// <summary>
+        /// 释放资源
+        /// </summary>
+        public void Dispose()
         {
         {
             try
             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;
+                this.Stop();
             }
             }
-            catch (Exception)
+            catch (Exception ex)
             {
             {
-                return false;
+                this.logger.LogWarning($"{NAME}停止失败:{ex.Message }");
             }
             }
             finally
             finally
             {
             {
@@ -143,21 +178,19 @@ namespace FastGithub.DomainResolve
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// 启动DnscryptProxy进程
+        /// 停止服务
         /// </summary>
         /// </summary>
-        /// <param name="arguments"></param> 
-        private static Process? StartDnscryptProxy(string arguments)
+        private void Stop()
         {
         {
-            var fileName = OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME;
-            return Process.Start(new ProcessStartInfo
+            if (OperatingSystem.IsWindows())
             {
             {
-                FileName = Path.Combine(PATH, fileName),
-                Arguments = arguments,
-                WorkingDirectory = PATH,
-                UseShellExecute = false,
-                CreateNoWindow = true,
-                WindowStyle = ProcessWindowStyle.Hidden
-            });
+                StartDnscryptProxy("-service stop")?.WaitForExit();
+                StartDnscryptProxy("-service uninstall")?.WaitForExit();
+            }
+            if (this.process != null && this.process.HasExited == false)
+            {
+                this.process.Kill();
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 5 - 30
FastGithub.DomainResolve/DomainResolveHostedService.cs

@@ -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="logger"></param>
+        /// <param name="speedTester"></param> 
         public DomainResolveHostedService(
         public DomainResolveHostedService(
             DnscryptProxy dnscryptProxy,
             DnscryptProxy dnscryptProxy,
-            DomainSpeedTester speedTester,
-            ILogger<DomainResolveHostedService> logger)
+            DomainSpeedTester speedTester)
         {
         {
             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);
-            }
-            catch (Exception ex)
-            {
-                this.logger.LogWarning($"{this.dnscryptProxy}启动失败:{ex.Message}");
-            }
-
+            await this.dnscryptProxy.StartAsync(stoppingToken);
             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);

+ 66 - 49
FastGithub.DomainResolve/DomainSpeedTester.cs

@@ -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>
@@ -61,80 +100,58 @@ namespace FastGithub.DomainResolve
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// 加载域名数据
+        /// 进行一轮IP测速
         /// </summary>
         /// </summary>
         /// <param name="cancellationToken"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         /// <returns></returns>
-        public async Task LoadDomainsAsync(CancellationToken cancellationToken)
+        public async Task TestSpeedAsync(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)
+            KeyValuePair<string, IPAddressItemHashSet>[] keyValues;
+            lock (this.syncRoot)
             {
             {
-                return;
+                keyValues = this.domainIPAddressHashSet.ToArray();
             }
             }
 
 
-            lock (this.syncRoot)
+            foreach (var keyValue in keyValues)
             {
             {
-                foreach (var domain in domains)
+                var domain = keyValue.Key;
+                var hashSet = keyValue.Value;
+                await foreach (var address in this.dnsClient.ResolveAsync(domain, cancellationToken))
                 {
                 {
-                    this.domainIPAddressHashSet.TryAdd(domain, new IPAddressItemHashSet());
+                    hashSet.Add(new IPAddressItem(address));
                 }
                 }
+                await hashSet.PingAllAsync();
             }
             }
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// 保存域名数据
+        /// 释放资源
         /// </summary>
         /// </summary>
-        /// <returns></returns>
-        public async Task<bool> SaveDomainsAsync()
+        public void Dispose()
         {
         {
-            var domains = this.domainIPAddressHashSet.Keys
-                .Select(item => new DomainPattern(item))
-                .OrderBy(item => item)
-                .Select(item => item.ToString())
-                .ToArray();
-
             try
             try
             {
             {
-                using var fileStream = File.OpenWrite(DOMAINS_JSON_FILE);
-                await JsonSerializer.SerializeAsync(fileStream, domains, new JsonSerializerOptions { WriteIndented = true });
-                return true;
+                this.SaveDomains();
             }
             }
-            catch (Exception)
+            catch (Exception ex)
             {
             {
-                return false;
+                this.logger.LogWarning($"保存域名数据失败:{ex.Message}");
             }
             }
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// 进行一轮IP测速
+        /// 保存域名
         /// </summary>
         /// </summary>
-        /// <param name="cancellationToken"></param>
-        /// <returns></returns>
-        public async Task TestSpeedAsync(CancellationToken cancellationToken)
+        private void SaveDomains()
         {
         {
-            KeyValuePair<string, IPAddressItemHashSet>[] keyValues;
-            lock (this.syncRoot)
-            {
-                keyValues = this.domainIPAddressHashSet.ToArray();
-            }
+            var domains = this.domainIPAddressHashSet.Keys
+               .Select(item => new DomainPattern(item))
+               .OrderBy(item => item)
+               .Select(item => item.ToString())
+               .ToArray();
 
 
-            foreach (var keyValue in keyValues)
-            {
-                var domain = keyValue.Key;
-                var hashSet = keyValue.Value;
-                await foreach (var address in this.dnsClient.ResolveAsync(domain, cancellationToken))
-                {
-                    hashSet.Add(new IPAddressItem(address));
-                }
-                await hashSet.PingAllAsync();
-            }
+            var utf8Json = JsonSerializer.SerializeToUtf8Bytes(domains, new JsonSerializerOptions { WriteIndented = true });
+            File.WriteAllBytes(DOMAINS_JSON_FILE, utf8Json);
         }
         }
     }
     }
 }
 }