build: bootstrap solution and quality gates (#3)
quality-gate / quality (push) Successful in 58s

Closes #3
This commit is contained in:
KyuubiYoru
2026-07-16 04:25:54 +02:00
parent 286fbfeb36
commit e626b89909
28 changed files with 803 additions and 0 deletions
@@ -0,0 +1,116 @@
using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.Options;
namespace FinalFactory.Rendezvous.Server.Transport;
/// <summary>
/// Owns the cancellable UDP socket used by the future NAT mediator.
/// </summary>
public sealed partial class UdpMediatorService : BackgroundService
{
private readonly ILogger<UdpMediatorService> _logger;
private readonly UdpMediatorOptions _options;
private UdpClient? _udpClient;
/// <summary>
/// Initializes a new UDP mediator service.
/// </summary>
public UdpMediatorService(
IOptions<UdpMediatorOptions> options,
ILogger<UdpMediatorService> logger)
{
_options = options.Value;
_logger = logger;
}
/// <summary>
/// Gets the bound endpoint after startup completes.
/// </summary>
public IPEndPoint? LocalEndpoint { get; private set; }
/// <inheritdoc />
public override Task StartAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (_udpClient is not null)
{
throw new InvalidOperationException("The UDP mediator is already running.");
}
IPAddress listenAddress = IPAddress.Parse(_options.ListenAddress);
UdpClient udpClient = new(new IPEndPoint(listenAddress, _options.Port));
_udpClient = udpClient;
IPEndPoint localEndpoint =
(IPEndPoint?)udpClient.Client.LocalEndPoint
?? throw new InvalidOperationException("The UDP socket did not expose its bound endpoint.");
LocalEndpoint = localEndpoint;
LogMediatorListening(_logger, localEndpoint.Address, localEndpoint.Port);
return base.StartAsync(cancellationToken);
}
/// <inheritdoc />
public override async Task StopAsync(CancellationToken cancellationToken)
{
await base.StopAsync(cancellationToken).ConfigureAwait(false);
_udpClient?.Dispose();
_udpClient = null;
LocalEndpoint = null;
LogMediatorStopped(_logger);
}
/// <inheritdoc />
public override void Dispose()
{
_udpClient?.Dispose();
_udpClient = null;
LocalEndpoint = null;
base.Dispose();
}
/// <inheritdoc />
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
UdpClient udpClient = _udpClient
?? throw new InvalidOperationException("The UDP mediator socket was not initialized.");
try
{
while (!stoppingToken.IsCancellationRequested)
{
_ = await udpClient.ReceiveAsync(stoppingToken).ConfigureAwait(false);
// Bootstrap deliberately emits no UDP response. Protocol handling lands in #11.
}
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
// Expected during normal shutdown.
}
catch (ObjectDisposedException) when (stoppingToken.IsCancellationRequested)
{
// Disposing the socket is the fallback that releases a blocked receive.
}
finally
{
LocalEndpoint = null;
}
}
[LoggerMessage(
EventId = 1,
Level = LogLevel.Information,
Message = "UDP mediator listening on {ListenAddress}:{ListenPort}")]
private static partial void LogMediatorListening(
ILogger logger,
IPAddress listenAddress,
int listenPort);
[LoggerMessage(
EventId = 2,
Level = LogLevel.Information,
Message = "UDP mediator stopped")]
private static partial void LogMediatorStopped(ILogger logger);
}