Files
Finlytic/FinlyticBackend/Hubs/FavoritesPriceHub.cs
T

80 lines
2.8 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
namespace FinlyticBackend.Hubs;
/// <summary>
/// SignalR Hub streaming real-time stock prices & daily % growth updates for favorite assets every 10 seconds.
/// </summary>
[Authorize]
public class FavoritesPriceHub : Hub
{
private readonly ILogger<FavoritesPriceHub> _logger;
// Speichert thread-sicher, wie viele aktive Verbindungen ein User hat (UserId -> ConnectionCount)
private static readonly ConcurrentDictionary<string, int> ActiveUserConnections = new();
public FavoritesPriceHub(ILogger<FavoritesPriceHub> logger)
{
_logger = logger;
}
/// <summary>
/// Liefert eine Übersicht aller aktuell mit dem Hub verbundenen User-IDs.
/// </summary>
public static string[] GetActiveUserIds() => [.. ActiveUserConnections.Keys];
public override async Task OnConnectedAsync()
{
var userId = Context.UserIdentifier;
if (!string.IsNullOrEmpty(userId))
{
// Füge die Verbindung der benutzerspezifischen Gruppe hinzu
await Groups.AddToGroupAsync(Context.ConnectionId, GetGroupName(userId));
ActiveUserConnections.AddOrUpdate(userId, 1, (_, count) => count + 1);
_logger.LogInformation("[FavoritesPriceHub] User '{UserId}' connected (ConnectionId={ConnectionId}). Active connections for user: {Count}",
userId, Context.ConnectionId, ActiveUserConnections[userId]);
}
else
{
_logger.LogWarning("[FavoritesPriceHub] Anonymous SignalR client connected without UserIdentifier: ConnectionId={ConnectionId}", Context.ConnectionId);
}
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
var userId = Context.UserIdentifier;
if (!string.IsNullOrEmpty(userId))
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, GetGroupName(userId));
ActiveUserConnections.AddOrUpdate(userId, 0, (_, count) =>
{
var newCount = count - 1;
return newCount < 0 ? 0 : newCount;
});
// Wenn keine aktiven Verbindungen mehr bestehen, aus Dictionary entfernen
if (ActiveUserConnections.TryGetValue(userId, out var remainingCount) && remainingCount <= 0)
{
ActiveUserConnections.TryRemove(userId, out _);
}
_logger.LogInformation("[FavoritesPriceHub] User '{UserId}' disconnected (ConnectionId={ConnectionId})", userId, Context.ConnectionId);
}
await base.OnDisconnectedAsync(exception);
}
public static string GetGroupName(string userId) => $"User_{userId.Trim()}";
}