Обработка пакета 16 с пуш токенами

This commit is contained in:
RoyceDa
2026-02-11 11:48:36 +02:00
parent 867137a5fa
commit 0981cd3d4b
9 changed files with 196 additions and 1 deletions

View File

@@ -9,6 +9,7 @@ import com.rosetta.im.executors.Executor0Handshake;
import com.rosetta.im.executors.Executor10RequestUpdate;
import com.rosetta.im.executors.Executor11Typeing;
import com.rosetta.im.executors.Executor15RequestTransport;
import com.rosetta.im.executors.Executor16PushNotification;
import com.rosetta.im.executors.Executor1UserInfo;
import com.rosetta.im.executors.Executor24DeviceResolve;
import com.rosetta.im.executors.Executor3Search;
@@ -27,6 +28,7 @@ import com.rosetta.im.packet.Packet0Handshake;
import com.rosetta.im.packet.Packet10RequestUpdate;
import com.rosetta.im.packet.Packet11Typeing;
import com.rosetta.im.packet.Packet15RequestTransport;
import com.rosetta.im.packet.Packet16PushNotification;
import com.rosetta.im.packet.Packet1UserInfo;
import com.rosetta.im.packet.Packet23DeviceList;
import com.rosetta.im.packet.Packet24DeviceResolve;
@@ -62,6 +64,17 @@ public class Boot {
private Configuration configuration;
private ServerConfiguration serverConfiguration;
/**
* Конструктор по умолчанию, использует порт 3000 для сервера
*/
public Boot() {
this(3000);
}
/**
* Инициализатор приложения
* @param port Порт, на котором будет работать сервер. Если не указан, то будет использован порт 3000
*/
public Boot(int port) {
this.packetManager = new PacketManager();
this.eventManager = new EventManager();
@@ -149,7 +162,11 @@ public class Boot {
this.packetManager.registerPacket(9, Packet9DeviceNew.class);
this.packetManager.registerPacket(10, Packet10RequestUpdate.class);
this.packetManager.registerPacket(11, Packet11Typeing.class);
//RESERVED 12 PACKET AVATAR (unused)
//RESERVED 13 PACKET KERNEL UPDATE (unused)
//RESERVED 14 PACKET APP UPDATE (unused)
this.packetManager.registerPacket(15, Packet15RequestTransport.class);
this.packetManager.registerPacket(16, Packet16PushNotification.class);
this.packetManager.registerPacket(23, Packet23DeviceList.class);
this.packetManager.registerPacket(24, Packet24DeviceResolve.class);
@@ -165,6 +182,7 @@ public class Boot {
this.packetManager.registerExecutor(10, new Executor10RequestUpdate(this.serverConfiguration));
this.packetManager.registerExecutor(11, new Executor11Typeing(this.clientManager, this.packetManager));
this.packetManager.registerExecutor(15, new Executor15RequestTransport(this.serverConfiguration));
this.packetManager.registerExecutor(16, new Executor16PushNotification());
this.packetManager.registerExecutor(24, new Executor24DeviceResolve(this.clientManager, this.eventManager));
}

View File

@@ -32,7 +32,7 @@ public class Main {
}
// Значение по умолчанию.
return 8080;
return 3000;
}
}

View File

@@ -236,6 +236,7 @@ public abstract class Repository<T> {
* @param noResultType если true, то не указывать тип результата в запросе, используется для запросов типа UPDATE и DELETE
* @return список сущностей
*/
@SuppressWarnings("deprecation")
public QuerySession<T> buildQuery(String queryString, HashMap<String, Object> parameters, boolean noResultType) {
Session session = HibernateUtil.openSession();
try {

View File

@@ -0,0 +1,47 @@
package com.rosetta.im.executors;
import com.rosetta.im.Failures;
import com.rosetta.im.client.tags.ECIAuthentificate;
import com.rosetta.im.database.entity.User;
import com.rosetta.im.database.repository.UserRepository;
import com.rosetta.im.packet.Packet16PushNotification;
import com.rosetta.im.service.services.UserService;
import io.orprotocol.ProtocolException;
import io.orprotocol.client.Client;
import io.orprotocol.packet.PacketExecutor;
public class Executor16PushNotification extends PacketExecutor<Packet16PushNotification> {
private final UserRepository userRepository = new UserRepository();
private final UserService userService = new UserService(userRepository);
@Override
public void onPacketReceived(Packet16PushNotification packet, Client client) throws Exception, ProtocolException {
ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class);
if(eciAuthentificate == null || !eciAuthentificate.hasAuthorized()){
/**
* Клиент не авторизован, нельзя подписывать его на уведомления
*/
client.disconnect(Failures.HANDSHAKE_NOT_COMPLETED);
return;
}
String notificationToken = packet.getNotificationToken();
if(notificationToken.isEmpty()){
/**
* Клиент прислал пустой токен, отписывать его от уведомлений не нужно, а подписывать бессмысленно, просто игнорируем этот пакет
*/
return;
}
User user = userService.fromClient(client);
switch (packet.getAction()) {
case SUBSCRIBE:
userService.subscribeToPushNotifications(user, notificationToken);
break;
case UNSUBSCRIBE:
userService.unsubscribeFromPushNotifications(user, notificationToken);
break;
}
}
}

View File

@@ -0,0 +1,63 @@
package com.rosetta.im.packet;
import com.rosetta.im.packet.runtime.NetworkNotificationAction;
import io.orprotocol.Stream;
import io.orprotocol.packet.Packet;
/**
* Packet16PushNotification бросается клиентом для подписки на пуш уведомления
*/
public class Packet16PushNotification extends Packet {
private String notificationToken;
private NetworkNotificationAction action;
@Override
public void read(Stream stream) {
this.notificationToken = stream.readString();
this.action = NetworkNotificationAction.fromCode(stream.readInt8());
}
@Override
public Stream write() {
Stream stream = new Stream();
stream.writeInt16(this.packetId);
stream.writeString(notificationToken);
stream.writeInt8(action.getCode());
return stream;
}
/**
* Получить токен пуш уведомлений, который нужно подписать или отписать в зависимости от action
* @return токен пуш уведомлений
*/
public String getNotificationToken() {
return notificationToken;
}
/**
* Получить действие, которое нужно выполнить с токеном пуш уведомлений. SUBSCRIBE - подписать этот токен на пуш уведомления, UNSUBSCRIBE - отписать этот токен от пуш уведомлений
* @return действие, которое нужно выполнить с токеном пуш уведомлений
*/
public NetworkNotificationAction getAction() {
return action;
}
/**
* Устанавливает токен пуш уведомлений, который нужно подписать или отписать в зависимости от action
* @param notificationToken токен пуш уведомлений
*/
public void setNotificationToken(String notificationToken) {
this.notificationToken = notificationToken;
}
/**
* Устанавливает действие, которое нужно выполнить с токеном пуш уведомлений. SUBSCRIBE - подписать этот токен на пуш уведомления, UNSUBSCRIBE - отписать этот токен от пуш уведомлений
* @param action действие, которое нужно выполнить с токеном пуш уведомлений
*/
public void setAction(NetworkNotificationAction action) {
this.action = action;
}
}

View File

@@ -0,0 +1,34 @@
package com.rosetta.im.packet.runtime;
/**
* Используется в Packet16PushNotification для указания действия, которое нужно выполнить с токеном пуш уведомлений.
*/
public enum NetworkNotificationAction {
/**
* Подписать этот токен на пуш уведомления. Если токен уже был подписан, то ничего не произойдет.
*/
SUBSCRIBE(0),
/**
* Отписать этот токен от пуш уведомлений. Если токен не был подписан, то ничего не произойдет.
*/
UNSUBSCRIBE(1);
private final int code;
NetworkNotificationAction(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static NetworkNotificationAction fromCode(int code) {
for (NetworkNotificationAction action : values()) {
if (action.code == code) {
return action;
}
}
throw new IllegalArgumentException("Unknown NetworkNotificationAction code: " + code);
}
}

View File

@@ -60,4 +60,34 @@ public class UserService extends Service<UserRepository> {
return user != null;
}
/**
* Подписывает пользователя на пуш уведомления, добавляя токен в его список токенов. Если токен уже был добавлен, то ничего не произойдет.
* @param user пользователь, которого нужно подписать на пуш уведомления
* @param notificationToken токен пуш уведомлений, который нужно добавить пользователю. Если токен уже был добавлен, то ничего не произойдет
*/
public void subscribeToPushNotifications(User user, String notificationToken) {
List<String> tokens = user.getNotificationsTokens();
if(tokens.contains(notificationToken)){
return;
}
tokens.add(notificationToken);
user.setNotificationsTokens(tokens);
this.getRepository().update(user);
}
/**
* Отписывает пользователя от пуш уведомлений, удаляя токен из его списка токенов. Если токена не было, то ничего не произойдет.
* @param user пользователь, которого нужно отписать от пуш уведомлений
* @param notificationToken токен пуш уведомлений, который нужно удалить у пользователя. Если токена не было, то ничего не произойдет
*/
public void unsubscribeFromPushNotifications(User user, String notificationToken) {
List<String> tokens = user.getNotificationsTokens();
if(!tokens.contains(notificationToken)){
return;
}
tokens.remove(notificationToken);
user.setNotificationsTokens(tokens);
this.getRepository().update(user);
}
}