using FastGithub.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.PacketIntercept.Dns
{
///
/// host文件冲解决者
///
[SupportedOSPlatform("windows")]
sealed class HostsConflictSolver : IDnsConflictSolver
{
private readonly FastGithubConfig fastGithubConfig;
private readonly ILogger logger;
///
/// host文件冲解决者
///
///
///
public HostsConflictSolver(
FastGithubConfig fastGithubConfig,
ILogger logger)
{
this.fastGithubConfig = fastGithubConfig;
this.logger = logger;
}
///
/// 解决冲突
///
///
///
public async Task SolveAsync(CancellationToken cancellationToken)
{
var hostsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "drivers/etc/hosts");
if (File.Exists(hostsPath) == false)
{
return;
}
Encoding hostsEncoding;
var hasConflicting = false;
var hostsBuilder = new StringBuilder();
using (var fileStream = new FileStream(hostsPath, FileMode.Open, FileAccess.Read))
{
using var streamReader = new StreamReader(fileStream);
while (streamReader.EndOfStream == false)
{
var line = await streamReader.ReadLineAsync(cancellationToken);
if (this.IsConflictingLine(line))
{
hasConflicting = true;
hostsBuilder.AppendLine($"# {line}");
}
else
{
hostsBuilder.AppendLine(line);
}
}
hostsEncoding = streamReader.CurrentEncoding;
}
if (hasConflicting == true)
{
try
{
await File.WriteAllTextAsync(hostsPath, hostsBuilder.ToString(), hostsEncoding, cancellationToken);
}
catch (Exception ex)
{
this.logger.LogWarning($"无法解决hosts文件冲突:{ex.Message}");
}
}
}
///
/// 恢复冲突
///
///
///
public Task RestoreAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
///
/// 是否为冲突的行
///
///
///
private bool IsConflictingLine(string? line)
{
if (line == null || line.TrimStart().StartsWith("#"))
{
return false;
}
var items = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (items.Length < 2)
{
return false;
}
var domain = items[1];
return this.fastGithubConfig.IsMatch(domain);
}
}
}