PlotDirector/PlotLine/Hubs/WordCompanionFollowHub.cs

69 lines
2.5 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using PlotLine.Models;
using PlotLine.Services;
using System.Security.Claims;
namespace PlotLine.Hubs;
[Authorize]
public sealed class WordCompanionFollowHub(IWordCompanionPresenceService presence) : Hub
{
public override async Task OnConnectedAsync()
{
if (TryGetUserId(out var userId))
{
await Groups.AddToGroupAsync(Context.ConnectionId, PresenceGroup(userId));
}
await base.OnConnectedAsync();
}
public async Task<WordCompanionPresenceStatus> WatchCompanionPresence()
{
var userId = RequireUserId();
await Groups.AddToGroupAsync(Context.ConnectionId, PresenceGroup(userId));
return await presence.GetStatusAsync(userId);
}
public async Task<WordCompanionPresenceStatus> RegisterCompanion(WordCompanionPresenceRegistration registration)
{
var userId = RequireUserId();
if (registration.UserID.HasValue && registration.UserID.Value != userId)
{
throw new HubException("The Companion is signed in as a different user.");
}
var status = await presence.RegisterAsync(userId, Context.ConnectionId, registration);
await Clients.Group(PresenceGroup(userId)).SendAsync("WordCompanionPresenceChanged", status);
return status;
}
public async Task<WordCompanionPresenceStatus> CompanionHeartbeat(WordCompanionPresenceHeartbeat heartbeat)
{
var userId = RequireUserId();
var status = await presence.HeartbeatAsync(userId, Context.ConnectionId, heartbeat);
await Clients.Group(PresenceGroup(userId)).SendAsync("WordCompanionPresenceChanged", status);
return status;
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
var status = await presence.DisconnectAsync(Context.ConnectionId);
if (status is not null)
{
await Clients.Group(PresenceGroup(status.UserID)).SendAsync("WordCompanionPresenceChanged", status);
}
await base.OnDisconnectedAsync(exception);
}
private int RequireUserId()
=> TryGetUserId(out var userId) ? userId : throw new HubException("Sign in to use the Word Companion.");
private bool TryGetUserId(out int userId)
=> int.TryParse(Context.User?.FindFirstValue(ClaimTypes.NameIdentifier), out userId);
private static string PresenceGroup(int userId) => $"word-companion-presence:{userId}";
}