Files
dnsmasq-webui/src/DnsmasqWebUI/Services/HostsFileService.cs
T
alex 92dfa2b170 Refactor: Bootstrap 5.3.8, Bootstrap Icons, Client/Http/Configuration layout
- Update Bootstrap to 5.3.8, add Bootstrap Icons; replace custom SVGs
- Fix settings modal: load editing state only when modal opens (avoid refresh overwrite)
- Home: StatusSection and LogsSection components with own timers
- Move HTTP clients under Client/Http with Abstractions namespace pattern
- Rename Options to Configuration; remove empty Options dir
- Components: Modals/, Home/; consistent Abstractions (Services, Client.Services, Client.Http)
2026-02-01 22:51:05 +10:00

64 lines
2.5 KiB
C#

using System.Text;
using DnsmasqWebUI.Models;
using DnsmasqWebUI.Configuration;
using DnsmasqWebUI.Parsers;
using DnsmasqWebUI.Services.Abstractions;
using Microsoft.Extensions.Options;
namespace DnsmasqWebUI.Services;
public class HostsFileService : IHostsFileService
{
private readonly string _path;
private readonly ILogger<HostsFileService> _logger;
public HostsFileService(IOptions<DnsmasqOptions> options, ILogger<HostsFileService> logger)
{
_path = options.Value.SystemHostsPath?.Trim() ?? "";
_logger = logger;
}
public async Task<IReadOnlyList<HostEntry>> ReadAsync(CancellationToken ct = default)
{
if (string.IsNullOrEmpty(_path))
return Array.Empty<HostEntry>();
if (!File.Exists(_path))
{
_logger.LogWarning("Hosts file not found: {Path}", _path);
return Array.Empty<HostEntry>();
}
var lines = await File.ReadAllLinesAsync(_path, Encoding.UTF8, ct);
var entries = new List<HostEntry>();
var seenContentIds = new HashSet<string>(StringComparer.Ordinal);
for (var i = 0; i < lines.Length; i++)
{
var entry = HostsFileLineParser.ParseLine(lines[i], i + 1);
if (entry == null) continue;
if (entry.IsPassthrough || string.IsNullOrEmpty(entry.Address))
entry.Id = "line:" + entry.LineNumber;
else
{
var contentId = entry.Address + "|" + string.Join(",", entry.Names.OrderBy(x => x, StringComparer.Ordinal));
entry.Id = seenContentIds.Add(contentId) ? contentId : contentId + ":" + entry.LineNumber;
}
entries.Add(entry);
}
return entries;
}
public async Task WriteAsync(IReadOnlyList<HostEntry> entries, CancellationToken ct = default)
{
if (string.IsNullOrEmpty(_path))
throw new InvalidOperationException("No system hosts file configured. Set Dnsmasq:SystemHostsPath to enable hosts editing.");
var dir = Path.GetDirectoryName(_path);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);
var tmpPath = _path + ".tmp";
var lines = entries.Select(HostsFileLineParser.ToLine).ToList();
await File.WriteAllLinesAsync(tmpPath, lines, Encoding.UTF8, ct);
File.Move(tmpPath, _path, overwrite: true);
_logger.LogInformation("Wrote hosts file: {Path}", _path);
}
}