Files
EchoHub/src/EchoHub.Server/Services/SignalRBroadcaster.cs
T
HueByte 0c16f44db6 feat: enhance user presence and channel interaction features
- Fix userlist not refreshing after creating a new channel.
- Implement unmute timer with a background job to automatically unmute users.
- Improve userlist display by filtering invisible users and ensuring proper transitions between statuses.
- Add clickable usernames, @mentions, and #channels for easier navigation.
- Embed theme colors from source sites for a more cohesive UI.
- Introduce a stateful userlist that updates incrementally via SignalR events.
- Restrict auto-opening of files to safe types only, enhancing security.
- Refactor user management into a dedicated service to reduce code duplication.
- Add a MuteExpirationService to handle timed mutes.
- Update documentation with Mermaid diagrams for major flows.
2026-02-24 20:56:40 +01:00

86 lines
3.3 KiB
C#

using EchoHub.Core.Contracts;
using EchoHub.Core.DTOs;
using EchoHub.Server.Hubs;
using Microsoft.AspNetCore.SignalR;
namespace EchoHub.Server.Services;
public class SignalRBroadcaster : IChatBroadcaster
{
private readonly IServiceProvider _serviceProvider;
private readonly PresenceTracker _presenceTracker;
private IHubContext<ChatHub, IEchoHubClient>? _hubContext;
private IHubContext<ChatHub, IEchoHubClient> HubContext
=> _hubContext ??= _serviceProvider.GetRequiredService<IHubContext<ChatHub, IEchoHubClient>>();
public SignalRBroadcaster(IServiceProvider serviceProvider, PresenceTracker presenceTracker)
{
_serviceProvider = serviceProvider;
_presenceTracker = presenceTracker;
}
public Task SendMessageToChannelAsync(string channelName, MessageDto message)
=> HubContext.Clients.Group(channelName).ReceiveMessage(message);
public Task SendUserJoinedAsync(string channelName, string username, UserPresenceDto? presence, string? excludeConnectionId = null)
{
if (excludeConnectionId is not null && !excludeConnectionId.StartsWith("irc-"))
return HubContext.Clients.GroupExcept(channelName, [excludeConnectionId]).UserJoined(channelName, username, presence);
return HubContext.Clients.Group(channelName).UserJoined(channelName, username, presence);
}
public Task SendUserLeftAsync(string channelName, string username)
=> HubContext.Clients.Group(channelName).UserLeft(channelName, username);
public Task SendChannelUpdatedAsync(ChannelDto channel, string? channelName = null)
{
if (channelName is not null)
return HubContext.Clients.Group(channelName).ChannelUpdated(channel);
return HubContext.Clients.All.ChannelUpdated(channel);
}
public Task SendUserStatusChangedAsync(List<string> channelNames, UserPresenceDto presence)
{
var connections = _presenceTracker.GetConnectionsInChannels(channelNames)
.Where(c => !c.StartsWith("irc-"))
.ToList();
if (connections.Count == 0)
return Task.CompletedTask;
return HubContext.Clients.Clients(connections).UserStatusChanged(presence);
}
public Task SendUserKickedAsync(string channelName, string username, string? reason)
=> HubContext.Clients.Group(channelName).UserKicked(channelName, username, reason);
public Task SendUserBannedAsync(string username, string? reason)
=> HubContext.Clients.All.UserBanned(username, reason);
public Task SendMessageDeletedAsync(string channelName, Guid messageId)
=> HubContext.Clients.Group(channelName).MessageDeleted(channelName, messageId);
public Task SendChannelNukedAsync(string channelName)
=> HubContext.Clients.Group(channelName).ChannelNuked(channelName);
public Task SendErrorAsync(string connectionId, string message)
{
if (connectionId.StartsWith("irc-"))
return Task.CompletedTask;
return HubContext.Clients.Client(connectionId).Error(message);
}
public Task ForceDisconnectUserAsync(List<string> connectionIds, string reason)
{
var signalRIds = connectionIds.Where(c => !c.StartsWith("irc-")).ToList();
if (signalRIds.Count == 0)
return Task.CompletedTask;
return HubContext.Clients.Clients(signalRIds).ForceDisconnect(reason);
}
}