using Microsoft.AspNetCore.SignalR; using System.Collections.Concurrent; using System.Security.Claims; using Microsoft.AspNetCore.Authorization; namespace vendorApproverBackend.Hubs { [Authorize] // Add authorization if needed public class NotificationHub : Hub { private static readonly ConcurrentDictionary _userConnections = new(); public override async Task OnConnectedAsync() { var userId = GetUserIdFromContext(); if (userId.HasValue) { _userConnections.AddOrUpdate(userId.Value, Context.ConnectionId, (key, oldValue) => Context.ConnectionId); await Groups.AddToGroupAsync(Context.ConnectionId, $"user_{userId}"); Console.WriteLine($"User {userId} connected with connection {Context.ConnectionId}"); } await base.OnConnectedAsync(); } public override async Task OnDisconnectedAsync(Exception exception) { var userId = GetUserIdFromContext(); if (userId.HasValue) { _userConnections.TryRemove(userId.Value, out _); await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"user_{userId}"); Console.WriteLine($"User {userId} disconnected"); } await base.OnDisconnectedAsync(exception); } public async Task JoinUserGroup(long userId) { await Groups.AddToGroupAsync(Context.ConnectionId, $"user_{userId}"); Console.WriteLine($"User {userId} joined group user_{userId}"); } public async Task LeaveUserGroup(long userId) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"user_{userId}"); } private long? GetUserIdFromContext() { if (Context.User?.Identity?.IsAuthenticated == true) { var userIdClaim = Context.User.FindFirst(ClaimTypes.NameIdentifier) ?? Context.User.FindFirst("userId") ?? Context.User.FindFirst("sub"); if (long.TryParse(userIdClaim?.Value, out long userId)) { return userId; } } return null; } public static string GetConnectionIdForUser(long userId) { _userConnections.TryGetValue(userId, out string connectionId); return connectionId; } } }