diff --git a/src/main/java/im/rosetta/Boot.java b/src/main/java/im/rosetta/Boot.java index 4cbdfcc..2e339e5 100644 --- a/src/main/java/im/rosetta/Boot.java +++ b/src/main/java/im/rosetta/Boot.java @@ -200,7 +200,7 @@ public class Boot { this.packetManager.registerExecutor(17, new Executor17GroupCreate()); this.packetManager.registerExecutor(18, new Executor18GroupInfo()); this.packetManager.registerExecutor(19, new Executor19GroupInviteInfo()); - this.packetManager.registerExecutor(20, new Executor20GroupJoin()); + this.packetManager.registerExecutor(20, new Executor20GroupJoin(this.packetManager)); this.packetManager.registerExecutor(21, new Executor21GroupLeave()); this.packetManager.registerExecutor(22, new Executor22GroupBan()); this.packetManager.registerExecutor(24, new Executor24DeviceResolve(this.clientManager, this.eventManager, this.packetManager)); diff --git a/src/main/java/im/rosetta/client/ClientManager.java b/src/main/java/im/rosetta/client/ClientManager.java index b4c8112..0ec7650 100644 --- a/src/main/java/im/rosetta/client/ClientManager.java +++ b/src/main/java/im/rosetta/client/ClientManager.java @@ -53,7 +53,7 @@ public class ClientManager { } /** - * Отправить пакет всем АВТОРИЗОВАННЫМ клиентам с публичным ключом publicKey + * Отправить пакет ВСЕМ АВТОРИЗОВАННЫМ клиентам с публичным ключом publicKey * @param publicKey публичный ключ получателя * @param packet пакет для отправки * @throws ProtocolException если произошла ошибка при отправке пакета клиенту @@ -83,6 +83,34 @@ public class ClientManager { } } + /** + * Отправить пакет всем клиентам с публичными ключом как у client, кроме клиента client, который является отправителем и не должен получать этот пакет + * @param client клиент + * @param packet пакет для отправки + * @throws ProtocolException + */ + public void retranslate(Client client, Packet packet) throws ProtocolException{ + ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class); + HashSet clients = this.clientIndexer + .getClients(ECIAuthentificate.class, "publicKey", eciAuthentificate.getPublicKey()); + if(clients == null){ + /** + * Нет авторизованных сессий с таким публичным ключом + */ + return; + } + for(Client c : clients){ + /** + * Проходим по всем устройствам с таким публичным ключом и ретранслируем им пакет, кроме того устройства что + * отправило пакет + */ + if(c.equals(client)){ + continue; + } + c.send(packet); + } + } + /** * Отправить пакет всем клиентам с публичными ключами из списка publicKeys * @param publicKeys список публичных ключей получателей diff --git a/src/main/java/im/rosetta/database/entity/Group.java b/src/main/java/im/rosetta/database/entity/Group.java index 5117702..6486638 100644 --- a/src/main/java/im/rosetta/database/entity/Group.java +++ b/src/main/java/im/rosetta/database/entity/Group.java @@ -3,15 +3,20 @@ package im.rosetta.database.entity; import java.util.ArrayList; import java.util.List; -import im.rosetta.database.CreateUpdateEntity; -import im.rosetta.database.converters.StringListConverter; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; +import im.rosetta.database.CreateUpdateEntity; +import jakarta.persistence.CollectionTable; import jakarta.persistence.Column; -import jakarta.persistence.Convert; +import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OrderColumn; import jakarta.persistence.Table; /** @@ -28,13 +33,20 @@ public class Group extends CreateUpdateEntity { @Column(name = "groupId") private String groupId; - @Convert(converter = StringListConverter.class) - @Column(name = "membersPublicKeys", nullable = false, columnDefinition = "TEXT") - private List membersPublicKeys = new ArrayList<>(); - @Convert(converter = StringListConverter.class) - @Column(name = "bannedPublicKeys", nullable = false, columnDefinition = "TEXT") - private List bannedPublicKeys = new ArrayList<>(); + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "group_members", joinColumns = @JoinColumn(name = "group_id")) + @Column(name = "public_key", nullable = false, columnDefinition = "TEXT") + @OrderColumn(name = "order_index") + @Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN }) + private List membersPublicKeys = new ArrayList<>(); + + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "group_banned", joinColumns = @JoinColumn(name = "group_id")) + @Column(name = "public_key", nullable = false, columnDefinition = "TEXT") + @OrderColumn(name = "order_index") + @Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN }) + private List bannedPublicKeys = new ArrayList<>(); public Long getId() { return id; diff --git a/src/main/java/im/rosetta/database/repository/GroupRepository.java b/src/main/java/im/rosetta/database/repository/GroupRepository.java index 130d469..2173234 100644 --- a/src/main/java/im/rosetta/database/repository/GroupRepository.java +++ b/src/main/java/im/rosetta/database/repository/GroupRepository.java @@ -1,8 +1,12 @@ package im.rosetta.database.repository; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import org.hibernate.Hibernate; + +import im.rosetta.database.QuerySession; import im.rosetta.database.Repository; import im.rosetta.database.entity.Group; @@ -18,11 +22,16 @@ public class GroupRepository extends Repository { * @return список публичных ключей участников группы */ public List findGroupMembers(String groupId) { - Group group = this.findByField("groupId", groupId); - if(group == null) { + try(QuerySession querySession = this.buildQuery("FROM Group g WHERE g.groupId = :groupId", new HashMap(){{ + put("groupId", groupId); + }})){ + Group group = querySession.getQuery().uniqueResult(); + if(group != null) { + Hibernate.initialize(group.getMembersPublicKeys()); + return group.getMembersPublicKeys(); + } return new ArrayList<>(); } - return group.getMembersPublicKeys(); } /** @@ -30,12 +39,9 @@ public class GroupRepository extends Repository { * @param groupId ID группы * @param creatorPublicKey публичный ключ создателя группы, который будет единственным участником группы при создании */ - public void createGroup(String groupId, String creatorPublicKey) { + public void createGroup(String groupId) { Group group = new Group(); group.setGroupId(groupId); - List membersPublicKeys = new ArrayList<>(); - membersPublicKeys.add(creatorPublicKey); - group.setMembersPublicKeys(membersPublicKeys); this.save(group); } @@ -45,7 +51,18 @@ public class GroupRepository extends Repository { * @return группа с заданным id, или null, если группа не найдена */ public Group getGroup(String groupId) { - return this.findByField("groupId", groupId); + String hql = "FROM Group g WHERE g.groupId = :groupId"; + HashMap params = new HashMap<>(); + params.put("groupId", groupId); + + try (QuerySession qs = this.buildQuery(hql, params)) { + Group group = qs.getQuery().uniqueResult(); + if (group != null) { + Hibernate.initialize(group.getMembersPublicKeys()); + Hibernate.initialize(group.getBannedPublicKeys()); + } + return group; + } } /** @@ -65,13 +82,18 @@ public class GroupRepository extends Repository { * @param memberPublicKey публичный ключ участника, которого нужно добавить в группу */ public void addMemberToGroup(String groupId, String memberPublicKey) { - Group group = this.findByField("groupId", groupId); - if(group != null) { - List membersPublicKeys = group.getMembersPublicKeys(); - if(!membersPublicKeys.contains(memberPublicKey)) { - membersPublicKeys.add(memberPublicKey); - group.setMembersPublicKeys(membersPublicKeys); - this.update(group); + try(QuerySession querySession = this.buildQuery("FROM Group g WHERE g.groupId = :groupId", new HashMap(){{ + put("groupId", groupId); + }})){ + Group group = querySession.getQuery().uniqueResult(); + if(group != null) { + Hibernate.initialize(group.getMembersPublicKeys()); + List membersPublicKeys = group.getMembersPublicKeys(); + if(!membersPublicKeys.contains(memberPublicKey)) { + membersPublicKeys.add(memberPublicKey); + group.setMembersPublicKeys(membersPublicKeys); + this.update(group); + } } } } @@ -82,13 +104,18 @@ public class GroupRepository extends Repository { * @param memberPublicKey публичный ключ участника, которого нужно удалить из группы */ public void removeMemberFromGroup(String groupId, String memberPublicKey) { - Group group = this.findByField("groupId", groupId); - if(group != null) { - List membersPublicKeys = group.getMembersPublicKeys(); - if(membersPublicKeys.contains(memberPublicKey)) { - membersPublicKeys.remove(memberPublicKey); - group.setMembersPublicKeys(membersPublicKeys); - this.update(group); + try(QuerySession querySession = this.buildQuery("FROM Group g WHERE g.groupId = :groupId", new HashMap(){{ + put("groupId", groupId); + }})){ + Group group = querySession.getQuery().uniqueResult(); + if(group != null) { + Hibernate.initialize(group.getMembersPublicKeys()); + List membersPublicKeys = group.getMembersPublicKeys(); + if(membersPublicKeys.contains(memberPublicKey)) { + membersPublicKeys.remove(memberPublicKey); + group.setMembersPublicKeys(membersPublicKeys); + this.update(group); + } } } } @@ -99,20 +126,39 @@ public class GroupRepository extends Repository { * @param memberPublicKey публичный ключ участника, которого нужно забанить в группе */ public void banMemberInGroup(String groupId, String memberPublicKey) { - Group group = this.findByField("groupId", groupId); - if(group != null) { - List bannedPublicKeys = group.getBannedPublicKeys(); - List membersPublicKeys = group.getMembersPublicKeys(); - if(membersPublicKeys.contains(memberPublicKey)) { - membersPublicKeys.remove(memberPublicKey); - group.setMembersPublicKeys(membersPublicKeys); + try(QuerySession querySession = this.buildQuery("FROM Group g WHERE g.groupId = :groupId", new HashMap(){{ + put("groupId", groupId); + }})){ + Group group = querySession.getQuery().uniqueResult(); + if(group != null) { + Hibernate.initialize(group.getBannedPublicKeys()); + List bannedPublicKeys = group.getBannedPublicKeys(); + if(!bannedPublicKeys.contains(memberPublicKey)) { + bannedPublicKeys.add(memberPublicKey); + group.setBannedPublicKeys(bannedPublicKeys); + this.update(group); + } } - if(!bannedPublicKeys.contains(memberPublicKey)) { - bannedPublicKeys.add(memberPublicKey); - group.setBannedPublicKeys(bannedPublicKeys); - } - this.update(group); } } + /** + * Получает все группы в которых состоит пользователь с заданным публичным ключом + * @param memberPublicKey публичный ключ пользователя, для которого нужно найти группы + * @return список ID групп, в которых состоит пользователь с заданным публичным ключом, или пустой список, если таких групп нет + */ + public List findGroupsByMember(String memberPublicKey) { + String hql = "FROM Group g WHERE :memberPublicKey MEMBER OF g.membersPublicKeys"; + List groupIds = new ArrayList<>(); + HashMap parameters = new HashMap<>(); + parameters.put("memberPublicKey", memberPublicKey); + try(QuerySession querySession = this.buildQuery(hql, parameters)){ + List groups = querySession.getQuery().list(); + for(Group group : groups){ + groupIds.add(group.getGroupId()); + } + } + return groupIds; + } + } diff --git a/src/main/java/im/rosetta/executors/Executor0Handshake.java b/src/main/java/im/rosetta/executors/Executor0Handshake.java index 9c3e27d..727cffd 100644 --- a/src/main/java/im/rosetta/executors/Executor0Handshake.java +++ b/src/main/java/im/rosetta/executors/Executor0Handshake.java @@ -184,7 +184,7 @@ public class Executor0Handshake extends PacketExecutor { newDevicePacket.setDeviceId(deviceId); newDevicePacket.setDeviceName(deviceName); newDevicePacket.setDeviceOs(deviceOs); - newDevicePacket.setIpAddress(client.getSocket().getRemoteSocketAddress().getAddress().getHostAddress()); + newDevicePacket.setIpAddress(client.getIpAddress()); clientManager.sendPacketToAuthorizedPK(publicKey, newDevicePacket); /** * Сбрасываем клиенту все старые подтверждения устройств, чтобы исключить спам запросами diff --git a/src/main/java/im/rosetta/executors/Executor17GroupCreate.java b/src/main/java/im/rosetta/executors/Executor17GroupCreate.java index e85dfae..23de798 100644 --- a/src/main/java/im/rosetta/executors/Executor17GroupCreate.java +++ b/src/main/java/im/rosetta/executors/Executor17GroupCreate.java @@ -25,7 +25,7 @@ public class Executor17GroupCreate extends PacketExecutor { return; } String groupId = RandomUtil.randomString(16); - this.groupRepository.createGroup(groupId, eciAuthentificate.getPublicKey()); + this.groupRepository.createGroup(groupId); /** * Отправляем клиенту ид созданной группы */ diff --git a/src/main/java/im/rosetta/executors/Executor20GroupJoin.java b/src/main/java/im/rosetta/executors/Executor20GroupJoin.java index 6f89877..b258bda 100644 --- a/src/main/java/im/rosetta/executors/Executor20GroupJoin.java +++ b/src/main/java/im/rosetta/executors/Executor20GroupJoin.java @@ -3,17 +3,25 @@ package im.rosetta.executors; import im.rosetta.Failures; import im.rosetta.client.tags.ECIAuthentificate; import im.rosetta.database.entity.Group; +import im.rosetta.database.repository.BufferRepository; import im.rosetta.database.repository.GroupRepository; import im.rosetta.packet.Packet20GroupJoin; import im.rosetta.packet.runtime.NetworkGroupStatus; - +import im.rosetta.service.services.BufferService; import io.orprotocol.ProtocolException; import io.orprotocol.client.Client; import io.orprotocol.packet.PacketExecutor; +import io.orprotocol.packet.PacketManager; public class Executor20GroupJoin extends PacketExecutor { private final GroupRepository groupRepository = new GroupRepository(); + private final BufferRepository bufferRepository = new BufferRepository(); + private final BufferService bufferService; + + public Executor20GroupJoin(PacketManager packetManager) { + this.bufferService = new BufferService(bufferRepository, packetManager); + } @Override public void onPacketReceived(Packet20GroupJoin packet, Client client) throws Exception, ProtocolException { @@ -53,12 +61,21 @@ public class Executor20GroupJoin extends PacketExecutor { client.send(packet); return; } - + /** + * Все проверки пройдены, клиент может вступить в группу + */ + packet.setStatus(NetworkGroupStatus.JOINED); + /** + * Кладем пакет в буфер для будущей синхронизации + */ + this.bufferService.pushPacketToBuffer("server", eciAuthentificate.getPublicKey(), packet); /** * Добавляем клиента в группу и возвращаем клиенту статус JOINED */ this.groupRepository.addMemberToGroup(groupId, eciAuthentificate.getPublicKey()); - packet.setStatus(NetworkGroupStatus.JOINED); + /** + * Возвращаем клиенту ответный пакет с статусом JOINED + */ client.send(packet); } diff --git a/src/main/java/im/rosetta/executors/Executor7Read.java b/src/main/java/im/rosetta/executors/Executor7Read.java index 8383e21..56aa2e1 100644 --- a/src/main/java/im/rosetta/executors/Executor7Read.java +++ b/src/main/java/im/rosetta/executors/Executor7Read.java @@ -38,6 +38,14 @@ public class Executor7Read extends PacketExecutor { client.disconnect(Failures.HANDSHAKE_NOT_COMPLETED); return; } + if(!eciAuthentificate.getPublicKey().equals(fromPublicKey)){ + /** + * Клиент пытается прочитать сообщения от имени того, кем не является + */ + client.disconnect(Failures.DATA_MISSMATCH); + return; + } + packet.setPrivateKey(""); if(toPublicKey.startsWith("#group:")){ diff --git a/src/main/java/im/rosetta/packet/Packet20GroupJoin.java b/src/main/java/im/rosetta/packet/Packet20GroupJoin.java index 1abbcc1..599070d 100644 --- a/src/main/java/im/rosetta/packet/Packet20GroupJoin.java +++ b/src/main/java/im/rosetta/packet/Packet20GroupJoin.java @@ -14,11 +14,20 @@ public class Packet20GroupJoin extends Packet { private String groupId; private NetworkGroupStatus status; + /** + * Строка группы, которая содержит информацию о группе, такую как ее название, описание и ключ + * Строка зашифрована обратимым шифрованием, где ключом выступает - реальный приватный ключ + * входящего в группу клиента. Нужно это для будущей синхронзации, так как клиенту на его другом + * устройстве нужно получить ключ группы и ее информацию. Сервер расшифровать эту строку не может. Эту + * строку может расшифровать только клиент, так как она зашифрована его приватным ключом + */ + private String groupString; @Override public void read(Stream stream) { this.groupId = stream.readString(); this.status = NetworkGroupStatus.fromCode(stream.readInt8()); + this.groupString = stream.readString(); } @Override @@ -27,6 +36,7 @@ public class Packet20GroupJoin extends Packet { stream.writeInt16(this.packetId); stream.writeString(this.groupId); stream.writeInt8(this.status.getCode()); + stream.writeString(this.groupString); return stream; } @@ -62,4 +72,20 @@ public class Packet20GroupJoin extends Packet { this.status = status; } + /** + * Получить строку группы, которая содержит информацию о группе, такую как ее название, описание и ключ + * @return строка группы + */ + public String getGroupString() { + return groupString; + } + + /** + * Установить строку группы, которая содержит информацию о группе, такую как ее название, описание и ключ + * @param groupString строка группы + */ + public void setGroupString(String groupString) { + this.groupString = groupString; + } + } diff --git a/src/main/java/im/rosetta/service/dispatch/MessageDispatcher.java b/src/main/java/im/rosetta/service/dispatch/MessageDispatcher.java index 3636ad7..2141f9e 100644 --- a/src/main/java/im/rosetta/service/dispatch/MessageDispatcher.java +++ b/src/main/java/im/rosetta/service/dispatch/MessageDispatcher.java @@ -1,12 +1,12 @@ package im.rosetta.service.dispatch; -import java.util.HashSet; import java.util.List; import im.rosetta.client.ClientManager; import im.rosetta.client.tags.ECIAuthentificate; import im.rosetta.database.repository.BufferRepository; import im.rosetta.database.repository.GroupRepository; +import im.rosetta.packet.Packet11Typeing; import im.rosetta.packet.base.PacketBaseDialog; import im.rosetta.service.services.BufferService; @@ -19,7 +19,7 @@ import io.orprotocol.packet.PacketManager; * Такой диспетчер нужен для того, чтобы не загромождать логику обработчиков сообщений, а так же для того, чтобы * централизовать логику отправки сообщений и сохранения их в буфер * Например, при отправке группового сообщения, диспетчер сам достает участников группы и - * отправляет сообщение каждому участнику, а так же сохраняет сообщение в буфер для каждого участника, который офлайн + * отправляет сообщение каждому участнику */ public class MessageDispatcher { @@ -38,6 +38,7 @@ public class MessageDispatcher { * @param packet пакет с групповым сообщением */ public void sendGroup(PacketBaseDialog packet, Client client, ECIAuthentificate eciAuthentificate) throws ProtocolException { + String fromPublicKey = packet.getFromPublicKey(); String toPublicKey = packet.getToPublicKey(); List groupMembersPublicKeys = this.groupRepository.findGroupMembers(toPublicKey.replace("#group:", "")); if(groupMembersPublicKeys.isEmpty()){ @@ -55,7 +56,21 @@ public class MessageDispatcher { return; } /** - * Отправляем всем участникам группы, кроме отправителя этот пакет, попутно не забывая проверить, а не один ли он в группе + * Ретранслируем сообщение ВСЕМ авторизованным сессиям отправителя КРОМЕ текущей, + * чтобы синхронизировать отправленные сообщения + */ + if(!(packet instanceof Packet11Typeing)){ + /** + * Если это пакет печати его не обязательно кэшировать, так как он нужен только + * для отображения статуса печати в реальном времени + * Кладем пакет в буфер для будущей синхронизации и на случай если кто-то из участников оффлайн, + * в toPublicKey при отправке в группу у нас находится #group:groupId + */ + this.bufferService.pushPacketToBuffer(fromPublicKey, toPublicKey.replace("#group:", ""), packet); + this.clientManager.retranslate(client, packet); + } + /** + * Отправляем всем участникам группы, кроме отправителя, попутно проверяем, а не один ли он в группе */ groupMembersPublicKeys.remove(eciAuthentificate.getPublicKey()); if(groupMembersPublicKeys.isEmpty()){ @@ -65,9 +80,10 @@ public class MessageDispatcher { */ return; } + /** + * Отправляем сообщение всем, кто в беседе + */ this.clientManager.sendPacketToAuthorizedPK(groupMembersPublicKeys, packet); - - //TODO: Сохранить сообщение в буфер для группы, чтобы группы тоже синхронизировались } /** @@ -81,6 +97,12 @@ public class MessageDispatcher { public void sendPeer(PacketBaseDialog packet, Client client, boolean bufferizationNeed) throws ProtocolException { String fromPublicKey = packet.getFromPublicKey(); String toPublicKey = packet.getToPublicKey(); + + /** + * Ретранслируем сообщение ВСЕМ авторизованным сессиям отправителя КРОМЕ текущей, + * чтобы синхронизировать отправленные сообщения + */ + this.clientManager.retranslate(client, packet); this.clientManager.sendPacketToAuthorizedPK(toPublicKey, packet); if(!bufferizationNeed){ @@ -94,11 +116,6 @@ public class MessageDispatcher { * Сохраняем сообщение в буфер на случай если получатель офлайн, или нам нужна будет синхронизация сообщений для получателя */ this.bufferService.pushPacketToBuffer(fromPublicKey, toPublicKey, packet); - - /** - * Ретранслируем сообщение всем авторизованным сессиям отправителя, чтобы синхронизировать отправленные сообщения - */ - this.retranslate(packet, client); } /** @@ -114,34 +131,4 @@ public class MessageDispatcher { this.sendPeer(packet, client, true); } - /** - * Сообщает всем авторизованным сессиям отправителя о том, что он отправил сообщения, - * для того чтобы синхронизировать отправленные сообщения на всех устройствах отправителя - * @param packet пакет сообщения - * @param client клиент отправляющий пакет - * @throws ProtocolException - */ - public void retranslate(PacketBaseDialog packet, Client client) throws ProtocolException { - ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class); - HashSet clients = this.clientManager.getClientIndexer() - .getClients(ECIAuthentificate.class, "publicKey", eciAuthentificate.getPublicKey()); - if(clients == null){ - /** - * Нет авторизованных сессий с таким публичным ключом - */ - return; - } - for(Client c : clients){ - /** - * Проходим по всем устройствам с таким публичным ключом и ретранслируем им пакет, кроме того устройства что - * отправило пакет - */ - if(c.equals(client)){ - continue; - } - c.send(packet); - } - } - - } diff --git a/src/main/java/im/rosetta/service/services/BufferService.java b/src/main/java/im/rosetta/service/services/BufferService.java index a179dd4..2d04fca 100644 --- a/src/main/java/im/rosetta/service/services/BufferService.java +++ b/src/main/java/im/rosetta/service/services/BufferService.java @@ -8,6 +8,7 @@ import im.rosetta.client.tags.ECIAuthentificate; import im.rosetta.database.QuerySession; import im.rosetta.database.entity.Buffer; import im.rosetta.database.repository.BufferRepository; +import im.rosetta.database.repository.GroupRepository; import im.rosetta.exception.UnauthorizedExeception; import im.rosetta.packet.Packet7Read; import im.rosetta.service.Service; @@ -20,6 +21,7 @@ import io.orprotocol.packet.PacketManager; public class BufferService extends Service { private PacketManager packetManager; + private GroupRepository groupRepository = new GroupRepository(); public BufferService(BufferRepository repository, PacketManager packetManager) { super(repository); @@ -41,10 +43,24 @@ public class BufferService extends Service { */ throw new UnauthorizedExeception("Unauthorized client cannot get packets from buffer"); } + /** + * Получаем группы клиента, и исходя из этого формируем список каких пакетов нам нужно взять из базы + */ + List clientGroups = this.groupRepository.findGroupsByMember(eciAuthentificate.getPublicKey()); + List toValue = new ArrayList<>(); + /** + * Добавляем публичный ключ клиента, так как ему нужны пакеты, которые были отправлены ему напрямую, а не в группу + */ + toValue.add(eciAuthentificate.getPublicKey()); + /** + * Добавляем группы клиента, так как ему нужны пакеты, которые были отправлены в эти группы + */ + toValue.addAll(clientGroups); + String toPublicKey = eciAuthentificate.getPublicKey(); - String hql = "FROM Buffer WHERE (to = :to OR from = :from) AND timestamp > :timestamp ORDER BY timestamp ASC"; + String hql = "FROM Buffer WHERE (to IN (:to) OR from = :from) AND timestamp > :timestamp ORDER BY timestamp ASC"; HashMap parameters = new HashMap<>(); - parameters.put("to", toPublicKey); + parameters.put("to", toValue); parameters.put("from", toPublicKey); parameters.put("timestamp", fromTimestampMs); List packets = new ArrayList<>();