using Govor.API.Common.SignalR.Helpers; using Govor.Application.Interfaces; using Govor.Contracts.Responses.SignalR; using Govor.Core.Repositories.Groups; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; namespace Govor.API.Hubs; [Authorize] public class ProfileHub : Hub { private readonly IGroupsRepository _groupsRepository; private readonly IFriendsService _friendsService; private readonly IProfileService _profileService; private readonly IHubUserAccessor _userAccessor; private readonly ILogger _logger; public ProfileHub( IGroupsRepository groupsRepository, IFriendsService friendsService, IProfileService profileService, IHubUserAccessor userAccessor, ILogger logger) { _groupsRepository = groupsRepository; _friendsService = friendsService; _profileService = profileService; _userAccessor = userAccessor; _logger = logger; } public override async Task OnConnectedAsync() { var userId = _userAccessor.GetUserId(Context); // Добавляем в персональную группу await Groups.AddToGroupAsync(Context.ConnectionId, $"user-{userId}"); // Friends var friendships = await _friendsService.GetFriendsAsync(userId); foreach (var friends in friendships) await Groups.AddToGroupAsync(Context.ConnectionId, $"friends-{friends.Id}"); // Groups var groups = await _groupsRepository.GetByUserIdAsync(userId); foreach (var group in groups) await Groups.AddToGroupAsync(Context.ConnectionId, $"group-{group.Id}"); _logger.LogInformation("User {UserId} connected with ConnectionId {ConnectionId}", userId, Context.ConnectionId); await base.OnConnectedAsync(); } public override async Task OnDisconnectedAsync(Exception exception) { var userId = _userAccessor.GetUserId(Context); await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"user-{userId}"); // Friends var friendships = await _friendsService.GetFriendsAsync(userId); foreach (var friendship in friendships) await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"friends-{friendship.Id}"); // Groups var groups = await _groupsRepository.GetByUserIdAsync(userId); foreach (var group in groups) await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"group-{group.Id}"); await base.OnDisconnectedAsync(exception); } public async Task> SetDescription(string description) { var userId = _userAccessor.GetUserId(Context); try { await _profileService.SetDescription(description, userId); var payload = new { userId, description }; await NotifyFriendsAndGroupsAsync(userId, "DescriptionUpdated", payload); return HubResult.Ok(true); } catch (Exception ex) { _logger.LogError(ex, "An error occurred while updating the user's {userId} descripton!", userId); return HubResult.Error("An unaccounted error on the server!"); } } public async Task> SetAvatar(Guid iconId) { var userId = _userAccessor.GetUserId(Context); try { if (iconId == Guid.Empty) return HubResult.BadRequest("IconId can't be empty!"); await _profileService.SetNewIcon(userId, iconId); var payload = new { userId, iconId }; await NotifyFriendsAndGroupsAsync(userId, "AvatarUpdated", payload); return HubResult.Ok(true); } catch (Exception ex) { _logger.LogError(ex, "An error occurred while updating the user's {userId} avatar {iconId}", userId, iconId); return HubResult.Error("An unaccounted error on the server!"); } } private async Task NotifyFriendsAndGroupsAsync(Guid userId, string eventName, object payload) { var friendIds = await _friendsService.GetFriendsAsync(userId); var groups = await _groupsRepository.GetByUserIdAsync(userId); var groupIds = groups.Select(g => g.Id).ToList(); await Clients.Group($"user-{userId}") // current user .SendAsync(eventName, payload); foreach (var friendId in friendIds) await Clients.Group($"friends-{friendId}") .SendAsync(eventName, payload); foreach (var groupId in groupIds) await Clients.Group($"group-{groupId}") .SendAsync(eventName, payload); _logger.LogInformation("Sent {EventName} for {UserId} to {Friends} friends and {Groups} groups", eventName, userId, friendIds.Count, groupIds.Count); } }