using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; namespace FastGithub.DnscryptProxy { /// /// DnscryptProxy后台服务 /// sealed class DnscryptProxyHostedService : IHostedService { private readonly DnscryptProxyService dnscryptProxyService; private readonly ILogger logger; private readonly TimeSpan dnsOKTimeout = TimeSpan.FromSeconds(60d); /// /// DnscryptProxy后台服务 /// /// /// public DnscryptProxyHostedService( DnscryptProxyService dnscryptProxyService, ILogger logger) { this.dnscryptProxyService = dnscryptProxyService; this.logger = logger; } /// /// 启动dnscrypt-proxy /// /// /// public async Task StartAsync(CancellationToken cancellationToken) { try { await this.dnscryptProxyService.StartAsync(cancellationToken); this.logger.LogInformation($"{this.dnscryptProxyService}启动成功"); // 监听意外退出 var process = this.dnscryptProxyService.Process; if (process == null) { this.OnProcessExit(null, new EventArgs()); } else { process.EnableRaisingEvents = true; process.Exited += this.OnProcessExit; await this.WaitForDnsOKAsync(cancellationToken); } } catch (Exception ex) { this.logger.LogWarning($"{this.dnscryptProxyService}启动失败:{ex.Message}"); } } /// /// 等待dns服务初始化 /// /// /// private async Task WaitForDnsOKAsync(CancellationToken cancellationToken) { this.logger.LogInformation($"{this.dnscryptProxyService}正在初始化"); using var timeoutTokenSource = new CancellationTokenSource(this.dnsOKTimeout); try { using var linkeTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token); await this.dnscryptProxyService.WaitForDnsOKAsync(linkeTokenSource.Token); this.logger.LogInformation($"{this.dnscryptProxyService}初始化完成"); } catch (Exception) { if (timeoutTokenSource.IsCancellationRequested) { this.logger.LogWarning($"{this.dnscryptProxyService}在{this.dnsOKTimeout.TotalSeconds}秒内未能初始化完成"); } } } /// /// 进程退出时 /// /// /// private void OnProcessExit(object? sender, EventArgs e) { if (this.dnscryptProxyService.ControllState != ControllState.Stopped) { this.logger.LogCritical($"{this.dnscryptProxyService}已意外停止,{nameof(FastGithub)}将无法解析域名。你可以把配置文件的{nameof(FastGithubOptions.PureDns)}修改为其它可用的DNS以临时使用。"); } } /// /// 停止dnscrypt-proxy /// /// /// public Task StopAsync(CancellationToken cancellationToken) { try { this.dnscryptProxyService.Stop(); this.logger.LogInformation($"{this.dnscryptProxyService}已停止"); } catch (Exception ex) { this.logger.LogWarning($"{this.dnscryptProxyService}停止失败:{ex.Message}"); } return Task.CompletedTask; } } }