1
0
Fork 0

Migrate existing code

This commit is contained in:
Jöran Malek 2025-01-29 23:53:57 +01:00
parent 384ff4a6f3
commit 9b49f880a2
30 changed files with 1789 additions and 5 deletions

View file

@ -0,0 +1,36 @@
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Channels;
namespace DotNetDDI.Services.Dhcp;
public class DhcpLeaseQueue
{
private readonly Channel<DhcpLeaseChange> _pipe;
private readonly ChannelReader<DhcpLeaseChange> _reader;
private readonly ChannelWriter<DhcpLeaseChange> _writer;
public ref readonly ChannelReader<DhcpLeaseChange> Reader => ref _reader;
public DhcpLeaseQueue()
{
_pipe = Channel.CreateUnbounded<DhcpLeaseChange>();
_reader = _pipe.Reader;
_writer = _pipe.Writer;
}
public ValueTask Write(DhcpLeaseChange change, CancellationToken cancellationToken = default)
{
return _writer.WriteAsync(change, cancellationToken);
}
}
public readonly record struct DhcpLeaseChange(IPAddress Address, string FQDN, DhcpLeaseIdentifier Identifier, TimeSpan Lifetime)
{
public AddressFamily LeaseType { get; } = Address.AddressFamily;
}
public record DhcpLeaseIdentifier;
public record DhcpLeaseClientIdentifier(string ClientId) : DhcpLeaseIdentifier;
public record DhcpLeaseHWAddrIdentifier(PhysicalAddress HWAddr) : DhcpLeaseIdentifier;

View file

@ -0,0 +1,44 @@
using System.Threading.Channels;
using DotNetDDI.Services.Dns;
using Microsoft.Extensions.Hosting;
namespace DotNetDDI.Services.Dhcp;
public class DhcpQueueWorker : BackgroundService
{
private readonly ChannelReader<DhcpLeaseChange> _channelReader;
private readonly DnsRepository _repository;
public DhcpQueueWorker(DhcpLeaseQueue queue, DnsRepository repository)
{
_channelReader = queue.Reader;
_repository = repository;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (await _channelReader.WaitToReadAsync(stoppingToken).ConfigureAwait(false))
{
while (_channelReader.TryRead(out var lease))
{
DnsRecordIdentifier identifier = lease.Identifier switch
{
DhcpLeaseClientIdentifier clientId => new DnsRecordClientIdentifier(clientId.ClientId),
DhcpLeaseHWAddrIdentifier hwAddr => new DnsRecordHWAddrIdentifier(hwAddr.HWAddr),
_ => throw new ArgumentException(nameof(lease.Identifier))
};
TimeSpan lifetime = lease.Lifetime.TotalSeconds switch
{
<= 1800 => TimeSpan.FromSeconds(600),
>= 10800 => TimeSpan.FromSeconds(3600),
{ } seconds => TimeSpan.FromSeconds(seconds / 3)
};
await _repository.Record(new DnsRecord(lease.Address, lease.FQDN, identifier, lifetime), stoppingToken).ConfigureAwait(false);
}
}
}
}

View file

@ -0,0 +1,50 @@
using System.Collections.Immutable;
using DotNetDDI.Options;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace DotNetDDI.Services.Dhcp;
public class DhcpWatcher : IHostedService
{
private readonly ImmutableArray<IHostedService> _services;
public DhcpWatcher(IOptions<DhcpOptions> options, IDhcpWatcherFactory factory)
{
var dhcpOptions = options.Value;
var services = ImmutableArray.CreateBuilder<IHostedService>();
if (dhcpOptions.Kea is { } keaOptions)
{
services.Add(factory.KeaService(keaOptions));
}
_services = services.DrainToImmutable();
}
public Task StartAsync(CancellationToken cancellationToken = default)
{
Task[] tasks = new Task[_services.Length];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = _services[i].StartAsync(cancellationToken);
}
return Task.WhenAll(tasks);
}
public async Task StopAsync(CancellationToken cancellationToken = default)
{
Task[] tasks = new Task[_services.Length];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = _services[i].StopAsync(cancellationToken);
}
var waitTask = Task.WhenAll(tasks);
TaskCompletionSource taskCompletionSource = new();
using var registration = cancellationToken.Register(s => ((TaskCompletionSource)s!).SetCanceled(), taskCompletionSource);
await Task.WhenAny(waitTask, taskCompletionSource.Task).ConfigureAwait(false);
}
}

View file

@ -0,0 +1,26 @@
using DotNetDDI.Integrations.Kea;
using DotNetDDI.Options;
using Microsoft.Extensions.DependencyInjection;
namespace DotNetDDI.Services.Dhcp;
public static class DhcpWatcherFactoryServices
{
public static IServiceCollection AddDhcpWatcherFactory(this IServiceCollection services)
{
services.AddTransient<IDhcpWatcherFactory, DhcpWatcherFactory>();
return services;
}
private class DhcpWatcherFactory(IServiceProvider services) : IDhcpWatcherFactory
{
private ObjectFactory<KeaService>? _cachedKeaService;
KeaService IDhcpWatcherFactory.KeaService(KeaDhcpOptions options)
{
_cachedKeaService ??= ActivatorUtilities.CreateFactory<KeaService>([typeof(KeaDhcpOptions)]);
return _cachedKeaService(services, [options]);
}
}
}

View file

@ -0,0 +1,9 @@
using DotNetDDI.Integrations.Kea;
using DotNetDDI.Options;
namespace DotNetDDI.Services.Dhcp;
public interface IDhcpWatcherFactory
{
KeaService KeaService(KeaDhcpOptions options);
}