Add QoS beacon
This commit is contained in:
@@ -0,0 +1,79 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
namespace Prospect.Server.Api.Services.Qos;
|
||||||
|
|
||||||
|
public class QosServer : IAsyncDisposable
|
||||||
|
{
|
||||||
|
private readonly ILogger<QosServer> _logger;
|
||||||
|
private readonly UdpClient _client;
|
||||||
|
|
||||||
|
private bool _isStopping;
|
||||||
|
private Task? _runTask;
|
||||||
|
|
||||||
|
public QosServer(ILogger<QosServer> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_client = new UdpClient(new IPEndPoint(IPAddress.Any, 3075));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_runTask = RunAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StopAsync()
|
||||||
|
{
|
||||||
|
_isStopping = true;
|
||||||
|
_client.Dispose();
|
||||||
|
|
||||||
|
if (_runTask != null)
|
||||||
|
{
|
||||||
|
await _runTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var result = await _client.ReceiveAsync();
|
||||||
|
|
||||||
|
_logger.LogInformation("Received {Data} from {Address}", result.Buffer, result.RemoteEndPoint);
|
||||||
|
|
||||||
|
if (result.Buffer.Length == 22)
|
||||||
|
{
|
||||||
|
// The server will reply with a single datagram, with the message contents having the
|
||||||
|
// first 2 bytes "flipped" to 0x0000 (0000 0000 0000 0000).
|
||||||
|
// The rest of the datagram contents will be copied from the initial ping.
|
||||||
|
result.Buffer[0] = 0x00;
|
||||||
|
result.Buffer[1] = 0x00;
|
||||||
|
result.Buffer[2] = 0x00;
|
||||||
|
result.Buffer[3] = 0x00;
|
||||||
|
|
||||||
|
await _client.SendAsync(result.Buffer, result.RemoteEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SocketException e) when (e.SocketErrorCode == SocketError.OperationAborted ||
|
||||||
|
e.SocketErrorCode == SocketError.Interrupted ||
|
||||||
|
e.SocketErrorCode == SocketError.InvalidArgument && !OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
if (!_isStopping)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "SocketException caught in QosServer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Exception caught in QosServer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
await StopAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
namespace Prospect.Server.Api.Services.Qos;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of a QoS beacon.
|
||||||
|
/// https://docs.microsoft.com/en-us/gaming/playfab/features/multiplayer/servers/using-qos-beacons-to-measure-player-latency-to-azure#quality-of-service-beacons
|
||||||
|
/// </summary>
|
||||||
|
public class QosService : IHostedService
|
||||||
|
{
|
||||||
|
private readonly ILogger<QosService> _logger;
|
||||||
|
private readonly QosServer _server;
|
||||||
|
|
||||||
|
public QosService(ILogger<QosService> logger, QosServer server)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Starting QoS beacon");
|
||||||
|
_server.Start();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Stopping QoS beacon");
|
||||||
|
await _server.StopAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using Prospect.Server.Api.Converters;
|
|||||||
using Prospect.Server.Api.Middleware;
|
using Prospect.Server.Api.Middleware;
|
||||||
using Prospect.Server.Api.Services.Auth;
|
using Prospect.Server.Api.Services.Auth;
|
||||||
using Prospect.Server.Api.Services.Database;
|
using Prospect.Server.Api.Services.Database;
|
||||||
|
using Prospect.Server.Api.Services.Qos;
|
||||||
using Prospect.Server.Api.Services.UserData;
|
using Prospect.Server.Api.Services.UserData;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
@@ -32,6 +33,9 @@ public class Startup
|
|||||||
|
|
||||||
services.AddSingleton<DbUserDataService>();
|
services.AddSingleton<DbUserDataService>();
|
||||||
|
|
||||||
|
services.AddHostedService<QosService>();
|
||||||
|
services.AddSingleton<QosServer>();
|
||||||
|
|
||||||
services.AddAuthentication(_ =>
|
services.AddAuthentication(_ =>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user