diff --git a/backend/src/Contracts/Messaging/Application/Abstractions/IMessageRepository.cs b/backend/src/Contracts/Messaging/Application/Abstractions/IMessageRepository.cs index d032fba..f6f94fb 100644 --- a/backend/src/Contracts/Messaging/Application/Abstractions/IMessageRepository.cs +++ b/backend/src/Contracts/Messaging/Application/Abstractions/IMessageRepository.cs @@ -13,6 +13,7 @@ public interface IMessageRepository Task> GetChatMessagesCursorAsync(Guid chatId, DateTime? cursor, long? sequenceId, int limit, CancellationToken cancellationToken); Task> GetChatMessagesAroundAsync(Guid chatId, long sequenceId, int limit, CancellationToken cancellationToken); + Task> GetChatMessagesAfterAsync(Guid chatId, long sequenceId, int limit, CancellationToken cancellationToken); Task GetLastStoryMessageAsync(Guid chatId, Guid storyId, CancellationToken cancellationToken); Task UpdateAsync(Message message, CancellationToken cancellationToken); diff --git a/backend/src/Modules/Conversations/Application/Messages/GetMessages/GetMessagesQuery.cs b/backend/src/Modules/Conversations/Application/Messages/GetMessages/GetMessagesQuery.cs index 3e77abd..4fa6e9a 100644 --- a/backend/src/Modules/Conversations/Application/Messages/GetMessages/GetMessagesQuery.cs +++ b/backend/src/Modules/Conversations/Application/Messages/GetMessages/GetMessagesQuery.cs @@ -13,7 +13,7 @@ using MediatR; namespace Knot.Modules.Conversations.Application.Messages.GetMessages; -public record GetMessagesQuery(Guid UserId, Guid ChatId, string? Cursor, long? Pivot = null, int? Limit = null) : IQuery>; +public record GetMessagesQuery(Guid UserId, Guid ChatId, string? Cursor, long? Pivot = null, long? AfterSequenceId = null, int? Limit = null) : IQuery>; internal sealed class GetMessagesQueryHandler : IQueryHandler> { @@ -41,7 +41,12 @@ internal sealed class GetMessagesQueryHandler : IQueryHandler messages; int queryLimit = request.Limit ?? ChatConstants.DefaultMessageQueryLimit; - if (request.Pivot.HasValue) + if (request.AfterSequenceId.HasValue) + { + // Получаем только сообщения ПОСЛЕ указанного sequenceId (для синхронизации) + messages = await _messageRepository.GetChatMessagesAfterAsync(request.ChatId, request.AfterSequenceId.Value, queryLimit, cancellationToken); + } + else if (request.Pivot.HasValue) { messages = await _messageRepository.GetChatMessagesAroundAsync(request.ChatId, request.Pivot.Value, queryLimit, cancellationToken); } diff --git a/backend/src/Modules/Conversations/Presentation/Endpoints/MessagesEndpoints.cs b/backend/src/Modules/Conversations/Presentation/Endpoints/MessagesEndpoints.cs index 6e89b10..2196e66 100644 --- a/backend/src/Modules/Conversations/Presentation/Endpoints/MessagesEndpoints.cs +++ b/backend/src/Modules/Conversations/Presentation/Endpoints/MessagesEndpoints.cs @@ -19,9 +19,17 @@ public static class MessagesEndpoints { var group = app.MapGroup("api/messages").RequireAuthorization(); - group.MapGet("chat/{chatId:guid}", async ([FromRoute] Guid chatId, [FromQuery] string? cursor, ISender sender, IUserContext userContext, CancellationToken ct) => + group.MapGet("chat/{chatId:guid}", async ( + [FromRoute] Guid chatId, + [FromQuery] string? cursor, + [FromQuery] long? afterSequenceId, + [FromQuery] long? pivot, + [FromQuery] int? limit, + ISender sender, + IUserContext userContext, + CancellationToken ct) => { - var result = await sender.Send(new GetMessagesQuery(userContext.UserId, chatId, cursor), ct); + var result = await sender.Send(new GetMessagesQuery(userContext.UserId, chatId, cursor, pivot, afterSequenceId, limit), ct); return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error.Description); }); diff --git a/backend/src/Modules/Messaging/Infrastructure/Persistence/MessageRepository.cs b/backend/src/Modules/Messaging/Infrastructure/Persistence/MessageRepository.cs index 1ca31c7..396d7ec 100644 --- a/backend/src/Modules/Messaging/Infrastructure/Persistence/MessageRepository.cs +++ b/backend/src/Modules/Messaging/Infrastructure/Persistence/MessageRepository.cs @@ -95,14 +95,28 @@ public sealed class MessageRepository : IMessageRepository .ToListAsync(cancellationToken); } + public async Task> GetChatMessagesAfterAsync(Guid chatId, long sequenceId, int limit, CancellationToken cancellationToken) + { + var builder = Builders.Filter; + var filter = builder.And( + builder.Eq(m => m.ChatId, chatId), + builder.Gt(m => m.SequenceId, sequenceId) + ); + + return await _messages.Find(filter) + .SortBy(m => m.SequenceId) + .Limit(limit) + .ToListAsync(cancellationToken); + } + public async Task> GetChatMessagesAroundAsync(Guid chatId, long sequenceId, int limit, CancellationToken cancellationToken) { var builder = Builders.Filter; - + // Target message var targetFilter = builder.And(builder.Eq(m => m.ChatId, chatId), builder.Eq(m => m.SequenceId, sequenceId)); var targetMsg = await _messages.Find(targetFilter).FirstOrDefaultAsync(cancellationToken); - + // Older messages var olderFilter = builder.And(builder.Eq(m => m.ChatId, chatId), builder.Lt(m => m.SequenceId, sequenceId)); var older = await _messages.Find(olderFilter)