using System.Security.Claims; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; using PlotLine.Models; using PlotLine.Services; namespace PlotLine.Hubs; [Authorize] public sealed class StoryIntelligenceHub(IStoryIntelligenceService storyIntelligence) : Hub { public override async Task OnConnectedAsync() { if (TryGetUserId(out var userId)) { await Groups.AddToGroupAsync(Context.ConnectionId, UserGroup(userId)); } await base.OnConnectedAsync(); } public async Task WatchStoryIntelligenceJob(Guid jobId) { var userId = RequireUserId(); await Groups.AddToGroupAsync(Context.ConnectionId, UserGroup(userId)); return await storyIntelligence.GetProgressForUserAsync(userId, jobId); } public static string UserGroup(int userId) => $"story-intelligence:{userId}"; private int RequireUserId() => TryGetUserId(out var userId) ? userId : throw new HubException("Sign in to use Story Intelligence."); private bool TryGetUserId(out int userId) => int.TryParse(Context.User?.FindFirstValue(ClaimTypes.NameIdentifier), out userId); }