Полная реализация синхронизации
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package im.rosetta.service.dispatch;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import im.rosetta.Failures;
|
||||
@@ -96,6 +97,11 @@ public class MessageDispatcher {
|
||||
* Сохраняем сообщение в буфер на случай если получатель офлайн, или нам нужна будет синхронизация сообщений для получателя
|
||||
*/
|
||||
this.bufferService.pushPacketToBuffer(fromPublicKey, toPublicKey, packet);
|
||||
|
||||
/**
|
||||
* Ретранслируем сообщение всем авторизованным сессиям отправителя, чтобы синхронизировать отправленные сообщения
|
||||
*/
|
||||
this.retranslate(packet, client);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,5 +117,34 @@ 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<Client> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import im.rosetta.database.entity.Buffer;
|
||||
import im.rosetta.database.repository.BufferRepository;
|
||||
import im.rosetta.exception.UnauthorizedExeception;
|
||||
import im.rosetta.service.Service;
|
||||
|
||||
import im.rosetta.service.services.runtime.PacketBuffer;
|
||||
import io.orprotocol.ProtocolException;
|
||||
import io.orprotocol.client.Client;
|
||||
import io.orprotocol.packet.Packet;
|
||||
@@ -32,7 +32,7 @@ public class BufferService extends Service<BufferRepository> {
|
||||
* @return
|
||||
* @throws ProtocolException
|
||||
*/
|
||||
public List<Packet> getPacketsFromTime(Client client, long fromTimestampMs) throws ProtocolException, UnauthorizedExeception {
|
||||
public PacketBuffer getPacketsFromTime(Client client, long fromTimestampMs, int take) throws ProtocolException, UnauthorizedExeception {
|
||||
ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class);
|
||||
if(eciAuthentificate == null || !eciAuthentificate.hasAuthorized()){
|
||||
/**
|
||||
@@ -41,20 +41,25 @@ public class BufferService extends Service<BufferRepository> {
|
||||
throw new UnauthorizedExeception("Unauthorized client cannot get packets from buffer");
|
||||
}
|
||||
String toPublicKey = eciAuthentificate.getPublicKey();
|
||||
String hql = "FROM Buffer WHERE to = :to AND timestamp > :timestamp ORDER BY timestamp ASC";
|
||||
String hql = "FROM Buffer WHERE (to = :to OR from = :from) AND timestamp > :timestamp ORDER BY timestamp ASC";
|
||||
HashMap<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("to", toPublicKey);
|
||||
parameters.put("from", toPublicKey);
|
||||
parameters.put("timestamp", fromTimestampMs);
|
||||
List<Packet> packets = new ArrayList<>();
|
||||
long lastTimestamp = fromTimestampMs;
|
||||
try(QuerySession<Buffer> querySession = this.getRepository().buildQuery(hql, parameters)){
|
||||
List<Buffer> buffers = querySession.getQuery().list();
|
||||
List<Buffer> buffers = querySession.getQuery().setMaxResults(take).list();
|
||||
for(Buffer buffer : buffers) {
|
||||
byte[] packetBytes = buffer.getPacket();
|
||||
Packet packet = this.packetManager.createPacket(packetBytes);
|
||||
packets.add(packet);
|
||||
}
|
||||
if(!buffers.isEmpty()){
|
||||
lastTimestamp = buffers.get(buffers.size() - 1).getTimestamp();
|
||||
}
|
||||
}
|
||||
return packets;
|
||||
return new PacketBuffer(packets, lastTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,10 +2,13 @@ package im.rosetta.service.services;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import im.rosetta.client.tags.ECIAuthentificate;
|
||||
import im.rosetta.client.tags.ECIDevice;
|
||||
import im.rosetta.database.entity.Device;
|
||||
import im.rosetta.database.entity.User;
|
||||
import im.rosetta.database.repository.DeviceRepository;
|
||||
import im.rosetta.service.Service;
|
||||
import io.orprotocol.client.Client;
|
||||
|
||||
public class DeviceService extends Service<DeviceRepository> {
|
||||
|
||||
@@ -45,4 +48,38 @@ public class DeviceService extends Service<DeviceRepository> {
|
||||
return this.getRepository().findAllByField("publicKey", publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает время последней синхронизации устройства, для корректной работы синхронизации сообщений
|
||||
* @param client клиент для которого нужно получить время последней синхронизации устройства
|
||||
* @return время последней синхронизации устройства, или 0 если устройство не найдено,
|
||||
* или клиент не авторизован, таким образом вызывающий код синхронизирует все сообщения
|
||||
*/
|
||||
public long getLastSyncTime(Client client){
|
||||
ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class);
|
||||
if(eciAuthentificate == null || !eciAuthentificate.hasAuthorized()){
|
||||
/**
|
||||
* Если клиент не авторизован, возвращаем 0, такого быть не должно
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
ECIDevice eciDevice = client.getTag(ECIDevice.class);
|
||||
if(eciDevice == null){
|
||||
/**
|
||||
* Если у клиента нет тега устройства, возвращаем 0, такого быть не должно, но на всякий случай
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
Device device = this.getRepository().findByField(new java.util.HashMap<String, Object>(){{
|
||||
put("deviceId", eciDevice.getDeviceId());
|
||||
put("publicKey", eciAuthentificate.getPublicKey());
|
||||
}});
|
||||
if(device == null){
|
||||
/**
|
||||
* Если устройство не найдено, возвращаем 0, значит это устройство новое
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
return device.getSyncTime();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package im.rosetta.service.services.runtime;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.orprotocol.packet.Packet;
|
||||
|
||||
/**
|
||||
* Класс для хранения пакетов для синхронизации и времени последнего пакета для корректной работы синхронизации сообщений
|
||||
* Когда клиент запрашивает синхронизацию сообщений, мы возвращаем ему список пакетов для
|
||||
* синхронизации и время последнего пакета, чтобы клиент мог корректно обновить время последней
|
||||
* синхронизации и не запрашивать одни и те же пакеты при следующей синхронизации
|
||||
*/
|
||||
public class PacketBuffer {
|
||||
|
||||
private List<Packet> packets;
|
||||
private long lastPacketTimestamp;
|
||||
|
||||
public PacketBuffer(List<Packet> packets, long lastPacketTimestamp) {
|
||||
this.packets = packets;
|
||||
this.lastPacketTimestamp = lastPacketTimestamp;
|
||||
}
|
||||
|
||||
public List<Packet> getPackets() {
|
||||
return packets;
|
||||
}
|
||||
|
||||
public long getLastPacketTimestamp() {
|
||||
return lastPacketTimestamp;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user