Files
rosetta-wss/src/main/java/im/rosetta/service/dispatch/MessageDispatcher.java
2026-03-20 20:23:54 +02:00

184 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package im.rosetta.service.dispatch;
import java.util.List;
import im.rosetta.client.ClientManager;
import im.rosetta.client.tags.ECIAuthentificate;
import im.rosetta.database.entity.User;
import im.rosetta.database.repository.BufferRepository;
import im.rosetta.database.repository.GroupRepository;
import im.rosetta.database.repository.UserRepository;
import im.rosetta.packet.Packet11Typeing;
import im.rosetta.packet.Packet7Read;
import im.rosetta.packet.base.PacketBaseDialog;
import im.rosetta.service.services.BufferService;
import im.rosetta.service.services.UserService;
import io.orprotocol.ProtocolException;
import io.orprotocol.client.Client;
import io.orprotocol.packet.PacketManager;
/**
* Диспетчер сообщений, который отвечает за отправку сообщений получателям, а так же за сохранение сообщений в буфер для офлайн получателей и для синхронизации
* Такой диспетчер нужен для того, чтобы не загромождать логику обработчиков сообщений, а так же для того, чтобы
* централизовать логику отправки сообщений и сохранения их в буфер
* Например, при отправке группового сообщения, диспетчер сам достает участников группы и
* отправляет сообщение каждому участнику
*/
public class MessageDispatcher {
private final GroupRepository groupRepository = new GroupRepository();
private final ClientManager clientManager;
private final BufferRepository bufferRepository = new BufferRepository();
private final BufferService bufferService;
private final FirebaseDispatcher firebaseDispatcher = new FirebaseDispatcher();
private final UserRepository userRepository = new UserRepository();
private final UserService userService = new UserService(userRepository);
public MessageDispatcher(ClientManager clientManager, PacketManager packetManager) {
this.clientManager = clientManager;
this.bufferService = new BufferService(bufferRepository, packetManager);
}
/**
* Отправляет групповое сообщение всем участникам группы, кроме отправителя
* @param packet пакет с групповым сообщением
*/
public void sendGroup(PacketBaseDialog packet, Client client, ECIAuthentificate eciAuthentificate) throws ProtocolException {
String fromPublicKey = packet.getFromPublicKey();
String toPublicKey = packet.getToPublicKey();
List<String> groupMembersPublicKeys = this.groupRepository.findGroupMembers(toPublicKey.replace("#group:", ""));
if(groupMembersPublicKeys.isEmpty()){
/**
* Если группа не найдена или в группе нет участников, то в такую отправить
* сообщение нельзя, ничего не делаем
*/
return;
}
if(!groupMembersPublicKeys.contains(eciAuthentificate.getPublicKey())){
/**
* Если отправитель не является участником группы, то он не может отправлять
* сообщения в эту группу
*/
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()){
/**
* Если отправитель был единственным участником группы, то отправлять сообщение некуда,
* не кикаем пользователя
*/
return;
}
/**
* Отправляем сообщение всем, кто в беседе
*/
this.clientManager.sendPacketToAuthorizedPK(groupMembersPublicKeys, packet);
if(packet instanceof Packet11Typeing){
/**
* Если это пакет печати, то не отправляем пуш уведомление, так как это может привести к спаму пушами при наборе текста
*/
return;
}
if(packet instanceof Packet7Read){
/**
* Если это пакет прочтения, то не отправляем пуш уведомление, так как это может привести к спаму пушами при чтении сообщений
*/
return;
}
/**
* Отправляем PUSH уведомление
*/
this.firebaseDispatcher.sendPushNotification(groupMembersPublicKeys, "Rosetta", "New message in group", toPublicKey.replace("#group:", ""));
}
/**
* Отправляет личное сообщение получателю
* @param packet пакет с личным сообщением
* @param client клиент отправляющий пакет
* @param bufferizationNeed флаг указывающий на то, что сообщение нужно буфферизировать,
* чтобы доставить пользователям если они не онлайн, если указать false то этот пакет получит
* только пользователь который были в сети
*/
public void sendPeer(PacketBaseDialog packet, Client client, boolean bufferizationNeed) throws ProtocolException {
String fromPublicKey = packet.getFromPublicKey();
String toPublicKey = packet.getToPublicKey();
User user = this.userService.fromClient(client);
if(user == null){
/**
* Если пользователь не найден, то не отправляем сообщение, так как у нас нет информации о том, кто отправляет сообщение
*/
return;
}
/**
* Ретранслируем сообщение ВСЕМ авторизованным сессиям отправителя КРОМЕ текущей,
* чтобы синхронизировать отправленные сообщения
*/
this.clientManager.retranslate(client, packet);
/**
* Отправляем сообщение получателю
*/
this.clientManager.sendPacketToAuthorizedPK(toPublicKey, packet);
if(!bufferizationNeed){
/**
* Указан флаг, что буферизация не нужна, сообщения с этим флагом не будут доставлены если
* оппонент оффлайн
*/
return;
}
/**
* Сохраняем сообщение в буфер на случай если получатель офлайн, или нам нужна будет синхронизация сообщений для получателя
*/
this.bufferService.pushPacketToBuffer(fromPublicKey, toPublicKey, packet);
if(packet instanceof Packet11Typeing){
/**
* Если это пакет печати, то не отправляем пуш уведомление,
* так как это может привести к спаму пушами при наборе текста
*/
return;
}
if(packet instanceof Packet7Read){
/**
* Если это пакет прочтения, то не отправляем пуш уведомление,
* так как это может привести к спаму пушами при чтении сообщений
*/
return;
}
/**
* Отправляем PUSH уведомление получателю
*/
this.firebaseDispatcher.sendPushNotification(toPublicKey, user.getTitle(), "New message", fromPublicKey);
}
/**
* Отправляет личное сообщение получателю с буферизацией
* @param packet пакет сообщения
* @param client клиент отправляющий пакет
* @throws ProtocolException
*/
public void sendPeer(PacketBaseDialog packet, Client client) throws ProtocolException {
/**
* По умолчанию буферизация включена, чтобы не терять сообщения
*/
this.sendPeer(packet, client, true);
}
}