using FastGithub.Configuration; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; namespace FastGithub.DomainResolve { /// /// 域名持久化 /// sealed partial class PersistenceService { private static readonly string dataFile = "dnsendpoints.json"; private static readonly SemaphoreSlim dataLocker = new(1, 1); private readonly FastGithubConfig fastGithubConfig; private readonly ILogger logger; private record EndPointItem(string Host, int Port); [JsonSerializable(typeof(EndPointItem[]))] [JsonSourceGenerationOptions( WriteIndented = true, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] private partial class EndPointItemsContext : JsonSerializerContext { } /// /// 域名持久化 /// /// /// public PersistenceService( FastGithubConfig fastGithubConfig, ILogger logger) { this.fastGithubConfig = fastGithubConfig; this.logger = logger; } /// /// 读取保存的节点 /// /// public IList ReadDnsEndPoints() { if (File.Exists(dataFile) == false) { return Array.Empty(); } try { dataLocker.Wait(); var utf8Json = File.ReadAllBytes(dataFile); var endPointItems = JsonSerializer.Deserialize(utf8Json, EndPointItemsContext.Default.EndPointItemArray); if (endPointItems == null) { return Array.Empty(); } var dnsEndPoints = new List(); foreach (var item in endPointItems) { if (this.fastGithubConfig.IsMatch(item.Host) == true) { dnsEndPoints.Add(new DnsEndPoint(item.Host, item.Port)); } } return dnsEndPoints; } catch (Exception ex) { this.logger.LogWarning(ex.Message, "读取dns记录异常"); return Array.Empty(); } finally { dataLocker.Release(); } } /// /// 保存节点到文件 /// /// /// /// public async Task WriteDnsEndPointsAsync(IEnumerable dnsEndPoints, CancellationToken cancellationToken) { try { await dataLocker.WaitAsync(CancellationToken.None); var endPointItems = dnsEndPoints.Select(item => new EndPointItem(item.Host, item.Port)).ToArray(); var utf8Json = JsonSerializer.SerializeToUtf8Bytes(endPointItems, EndPointItemsContext.Default.EndPointItemArray); await File.WriteAllBytesAsync(dataFile, utf8Json, cancellationToken); } catch (Exception ex) { this.logger.LogWarning(ex.Message, "保存dns记录异常"); } finally { dataLocker.Release(); } } } }