57 lines
2.2 KiB
C#
57 lines
2.2 KiB
C#
using RpgRoller.Contracts;
|
|
using RpgRoller.Services;
|
|
|
|
namespace RpgRoller.Api;
|
|
|
|
internal static class StateEventEndpoints
|
|
{
|
|
public static RouteGroupBuilder MapStateEventEndpoints(this RouteGroupBuilder group)
|
|
{
|
|
group.MapGet("/events/state", async Task<IResult> (Guid campaignId, HttpContext context, IGameService game) =>
|
|
{
|
|
var sessionToken = context.GetRequiredSessionToken();
|
|
var versionResult = game.GetCampaignVersion(sessionToken, campaignId);
|
|
if (!versionResult.Succeeded)
|
|
{
|
|
return versionResult.Error!.Code == "unauthorized" ? TypedResults.Unauthorized() : TypedResults.BadRequest(new ApiError(versionResult.Error.Message));
|
|
}
|
|
|
|
context.Response.Headers.CacheControl = "no-cache";
|
|
context.Response.Headers.Connection = "keep-alive";
|
|
context.Response.ContentType = "text/event-stream";
|
|
|
|
var lastVersion = versionResult.Value;
|
|
await context.Response.WriteAsync($"event: state\ndata: {{\"campaignId\":\"{campaignId}\",\"version\":{lastVersion}}}\n\n");
|
|
await context.Response.Body.FlushAsync();
|
|
|
|
try
|
|
{
|
|
while (!context.RequestAborted.IsCancellationRequested)
|
|
{
|
|
await Task.Delay(TimeSpan.FromSeconds(1), context.RequestAborted);
|
|
|
|
var currentVersionResult = game.GetCampaignVersion(sessionToken, campaignId);
|
|
if (!currentVersionResult.Succeeded)
|
|
break;
|
|
|
|
if (currentVersionResult.Value != lastVersion)
|
|
{
|
|
lastVersion = currentVersionResult.Value;
|
|
await context.Response.WriteAsync($"event: state\ndata: {{\"campaignId\":\"{campaignId}\",\"version\":{lastVersion}}}\n\n");
|
|
}
|
|
else
|
|
await context.Response.WriteAsync(": heartbeat\n\n");
|
|
|
|
await context.Response.Body.FlushAsync();
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return TypedResults.Empty;
|
|
});
|
|
|
|
return group;
|
|
}
|
|
} |