Files
Govor/Govor.API/Hubs/ChatsHub.cs
T
Artemy 565d3249e5 Add online pinging and friendship verification features
Introduces OnlinePingingController and related integration/unit tests for user online status updates. Adds PingHandlerService with memory cache throttling, IPingHandlerService interface, and service registration. Implements VerifyFriendship service and interface for friendship validation, with exception handling. Refactors CurrentUserService for improved user ID extraction and testability. Updates ChatsHub to verify friendship before messaging. Cleans up MediaController and optimizes UsersRepository queries by removing unnecessary includes.
2025-07-02 19:16:49 +07:00

107 lines
3.7 KiB
C#

using System.Security.Claims;
using Govor.Application.Interfaces;
using Govor.Contracts.Requests.SignalR;
using Govor.Core.Models;
using Govor.Core.Repositories.Users;
using Govor.Data.Repositories.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace Govor.API.Hubs;
[Authorize]
public class ChatsHub : Hub
{
private readonly IUsersRepository _usersRepository;
private readonly IVerifyFriendship _verifyFriendship;
private readonly ILogger<ChatsHub> _logger;
public ChatsHub(IUsersRepository usersRepository, ILogger<ChatsHub> logger)
{
_usersRepository = usersRepository;
_logger = logger;
}
public override async Task OnConnectedAsync()
{
var userId = GetUserId();
if (userId != Guid.Empty)
{
// Привязываем ConnectionId к UserId
await Groups.AddToGroupAsync(Context.ConnectionId, userId.ToString());
_logger.LogInformation("User {UserId} connected with ConnectionId {ConnectionId}", userId, Context.ConnectionId);
}
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
var userId = GetUserId();
if (userId != Guid.Empty)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, userId.ToString());
_logger.LogInformation("User {UserId} disconnected", userId);
}
await base.OnDisconnectedAsync(exception);
}
public async Task Edit(string newMessage, Guid messageId)
{
}
public async Task Send(MessageRequest request)
{
// Валидация входных данных
if (string.IsNullOrWhiteSpace(request.EncryptedContent))
{
_logger.LogWarning("Empty message received from user {UserId}", GetUserId());
throw new ArgumentException("Message cannot be empty", nameof(request.EncryptedContent));
}
var senderId = GetUserId();
// Проверка существования получателя и установленной дружбы
try
{
await _usersRepository.FindByIdAsync(request.RecipientId);
await _verifyFriendship.VerifyAsync(senderId, request.RecipientId);
}
catch (NotFoundByKeyException<User> ex)
{
_logger.LogWarning("Recipient user {ToUserId} not found", request.RecipientId);
throw;
}
catch (ArgumentException ex)
{
_logger.LogWarning("Invalid recipient userId received from user {UserId}", GetUserId());
throw;
}
try
{
_logger.LogInformation("Message sent from {SenderId} to {RecipientId} at {UtcNow}", senderId, request.RecipientId, DateTime.UtcNow);
// Отправка сообщения отправителю и получателю
//await Clients.Group(request.RecipientId.ToString()).SendAsync("Receive", message, senderId);
// Clients.Group(senderId.ToString()).SendAsync("Receive", message, senderId);
}
catch (Exception ex)
{
//_logger.LogError(ex, "Error sending message from {SenderId} to {RecipientId}", senderId, toUserId);
throw;
}
}
private Guid GetUserId()
{
var userIdClaim = Context.User?.FindFirst("userID")?.Value;
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
{
_logger.LogError("Could not retrieve sender userId");
throw new UnauthorizedAccessException("userID claim is missing or invalid");
}
return userId;
}
}