Обработка пакета печати

This commit is contained in:
RoyceDa
2026-02-10 00:51:40 +02:00
parent f4d3ca30ce
commit b671262aa2
6 changed files with 143 additions and 2 deletions

View File

@@ -4,6 +4,7 @@ import com.rosetta.im.client.ClientManager;
import com.rosetta.im.client.OnlineManager;
import com.rosetta.im.event.EventManager;
import com.rosetta.im.executors.Executor0Handshake;
import com.rosetta.im.executors.Executor11Typeing;
import com.rosetta.im.executors.Executor1UserInfo;
import com.rosetta.im.executors.Executor24DeviceResolve;
import com.rosetta.im.executors.Executor3Search;
@@ -19,6 +20,7 @@ import com.rosetta.im.logger.Logger;
import com.rosetta.im.logger.enums.Color;
import com.rosetta.im.logger.enums.LogLevel;
import com.rosetta.im.packet.Packet0Handshake;
import com.rosetta.im.packet.Packet11Typeing;
import com.rosetta.im.packet.Packet1UserInfo;
import com.rosetta.im.packet.Packet23DeviceList;
import com.rosetta.im.packet.Packet24DeviceResolve;
@@ -129,6 +131,7 @@ public class Boot {
this.packetManager.registerPacket(7, Packet7Read.class);
this.packetManager.registerPacket(8, Packet8Delivery.class);
this.packetManager.registerPacket(9, Packet9DeviceNew.class);
this.packetManager.registerPacket(11, Packet11Typeing.class);
this.packetManager.registerPacket(23, Packet23DeviceList.class);
this.packetManager.registerPacket(24, Packet24DeviceResolve.class);
@@ -141,6 +144,7 @@ public class Boot {
this.packetManager.registerExecutor(4, new Executor4OnlineState(this.onlineManager, this.clientManager));
this.packetManager.registerExecutor(6, new Executor6Message(this.clientManager, this.packetManager));
this.packetManager.registerExecutor(7, new Executor7Read(this.clientManager, this.packetManager));
this.packetManager.registerExecutor(11, new Executor11Typeing(this.clientManager, this.packetManager));
this.packetManager.registerExecutor(24, new Executor24DeviceResolve(this.clientManager, this.eventManager));
}

View File

@@ -0,0 +1,73 @@
package com.rosetta.im.executors;
import com.rosetta.im.Failures;
import com.rosetta.im.client.ClientManager;
import com.rosetta.im.client.tags.ECIAuthentificate;
import com.rosetta.im.packet.Packet11Typeing;
import com.rosetta.im.service.dispatch.MessageDispatcher;
import io.orprotocol.ProtocolException;
import io.orprotocol.client.Client;
import io.orprotocol.packet.PacketExecutor;
import io.orprotocol.packet.PacketManager;
public class Executor11Typeing extends PacketExecutor<Packet11Typeing> {
private final MessageDispatcher messageDispatcher;
public Executor11Typeing(ClientManager clientManager, PacketManager packetManager) {
this.messageDispatcher = new MessageDispatcher(clientManager, packetManager);
}
@Override
public void onPacketReceived(Packet11Typeing packet, Client client) throws Exception, ProtocolException {
ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class);
String fromPublicKey = packet.getFromPublicKey();
String toPublicKey = packet.getToPublicKey();
if(eciAuthentificate == null || !eciAuthentificate.hasAuthorized()){
/**
* Если пользователь не авторизован он не может отправлять пакет печати
*/
client.disconnect(Failures.HANDSHAKE_NOT_COMPLETED);
return;
}
if(!eciAuthentificate.getPublicKey().equals(fromPublicKey)){
/**
* Если клиент пытается отправить сообщение от отправителя,
* которым он не является
*/
client.disconnect(Failures.DATA_MISSMATCH);
return;
}
if(fromPublicKey.equals(toPublicKey)){
/**
* Отправка пакета печати самому себе, не кикаем пользователя, так как это ни на что не
* влияет, просто ничего не делаем
*/
return;
}
/**
* Удаляем приватный ключ чтобы не показать его оппоненту
*/
packet.setPrivateKey("");
if(toPublicKey.startsWith("#group:")){
/**
* Пакет печати отправляется в группу, отправляем всем участникам
*/
this.messageDispatcher.sendGroup(packet, client, eciAuthentificate);
}else{
/**
* Пакет печати отправляется обычному оппоненту (пользователь),
* отправляем его, при этом выключаем буфферизацию, потому что пакет печати действителен
* только "здесь и сейчас", его не нужно видеть офлайн пользователям
*/
this.messageDispatcher.sendPeer(packet, client, false);
}
}
}

View File

@@ -95,7 +95,8 @@ public class Executor6Message extends PacketExecutor<Packet6Message> {
return;
}
/**
* Обновляем системную метку времени в соотвествии с сервером, так как у клиентов могут быть например неправильно настроены часы
* Обновляем системную метку времени в соотвествии с сервером,
* так как у клиентов могут быть например неправильно настроены часы
* или разные часовые пояса
*/
packet.setTimestamp(System.currentTimeMillis());

View File

@@ -0,0 +1,29 @@
package com.rosetta.im.packet;
import com.rosetta.im.packet.base.PacketBaseDialog;
import io.orprotocol.Stream;
/**
* Пакет отвечающий за индикацию печати в диалогах
*/
public class Packet11Typeing extends PacketBaseDialog {
@Override
public void read(Stream stream) {
this.privateKey = stream.readString();
this.fromPublicKey = stream.readString();
this.toPublicKey = stream.readString();
}
@Override
public Stream write() {
Stream stream = new Stream();
stream.writeInt16(this.packetId);
stream.writeString(this.privateKey);
stream.writeString(this.fromPublicKey);
stream.writeString(this.toPublicKey);
return stream;
}
}

View File

@@ -5,6 +5,14 @@ import io.orprotocol.packet.Packet;
/**
* Базовый пакет для диалогов между пользователями
*
* ВОПРОС: Почему мы должны отправлять fromPublicKey с клиента, если сервер
* может получить fromPublicKey из хэндшейка?
* ОТВЕТ: Клиенты (оппоненты) должны понимать, от кого им приходит например пакет сообщения
* или печати с сервера (from), чтобы производить с отправителем какие-либо действия (например показать
* имя печатающего или отрендерить аватарку отправтеля сообщения), если бы поле fromPublicKey заполнял
* сервер - это бы выглядело не логично. Это не влияет на безопасность, так как каждый Exectuor
* верифицирует поле fromPublicKey сравнивая его с публичным ключом фактического отправителя.
*/
public class PacketBaseDialog extends Packet {

View File

@@ -75,15 +75,41 @@ public class MessageDispatcher {
/**
* Отправляет личное сообщение получателю
* @param packet пакет с личным сообщением
* @param client клиент отправляющий пакет
* @param bufferizationNeed флаг указывающий на то, что сообщение нужно буфферизировать,
* чтобы доставить пользователям если они не онлайн, если указать false то этот пакет получит
* только пользователь который были в сети
*/
public void sendPeer(PacketBaseDialog packet, Client client) throws ProtocolException {
public void sendPeer(PacketBaseDialog packet, Client client, boolean bufferizationNeed) throws ProtocolException {
String fromPublicKey = packet.getFromPublicKey();
String toPublicKey = packet.getToPublicKey();
this.clientManager.sendPacketToAuthorizedPK(toPublicKey, packet);
if(!bufferizationNeed){
/**
* Указан флаг, что буферизация не нужна, сообщения с этим флагом не будут доставлены если
* оппонент оффлайн
*/
return;
}
/**
* Сохраняем сообщение в буфер на случай если получатель офлайн, или нам нужна будет синхронизация сообщений для получателя
*/
this.bufferService.pushPacketToBuffer(fromPublicKey, toPublicKey, packet);
}
/**
* Отправляет личное сообщение получателю с буферизацией
* @param packet пакет сообщения
* @param client клиент отправляющий пакет
* @throws ProtocolException
*/
public void sendPeer(PacketBaseDialog packet, Client client) throws ProtocolException {
/**
* По умолчанию буферизация включена, чтобы не терять сообщения
*/
this.sendPeer(packet, client, true);
}
}