mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 00:08:04 +01:00
Return destination client presence when inserting messages
This commit is contained in:
committed by
Jon Chambers
parent
1fa31b3974
commit
eeeb565313
@@ -145,7 +145,7 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
|
||||
}
|
||||
|
||||
final UUID connectionId = UUID.randomUUID();
|
||||
final byte[] clientPresenceKey = getClientPresenceKey(accountIdentifier, deviceId);
|
||||
final byte[] clientPresenceKey = getClientEventChannel(accountIdentifier, deviceId);
|
||||
final AtomicReference<ClientEventListener> displacedListener = new AtomicReference<>();
|
||||
final AtomicReference<CompletionStage<Void>> subscribeFuture = new AtomicReference<>();
|
||||
|
||||
@@ -216,7 +216,7 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
|
||||
listenersByAccountAndDeviceIdentifier.compute(new AccountAndDeviceIdentifier(accountIdentifier, deviceId),
|
||||
(ignored, existingListener) -> {
|
||||
unsubscribeFuture.set(pubSubConnection.withPubSubConnection(connection ->
|
||||
connection.async().sunsubscribe(getClientPresenceKey(accountIdentifier, deviceId)))
|
||||
connection.async().sunsubscribe(getClientEventChannel(accountIdentifier, deviceId)))
|
||||
.thenRun(Util.NOOP));
|
||||
|
||||
return null;
|
||||
@@ -245,7 +245,7 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
|
||||
}
|
||||
|
||||
return pubSubConnection.withPubSubConnection(connection ->
|
||||
connection.async().spublish(getClientPresenceKey(accountIdentifier, deviceId), NEW_MESSAGE_EVENT_BYTES))
|
||||
connection.async().spublish(getClientEventChannel(accountIdentifier, deviceId), NEW_MESSAGE_EVENT_BYTES))
|
||||
.thenApply(listeners -> listeners > 0);
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
|
||||
}
|
||||
|
||||
return pubSubConnection.withPubSubConnection(connection ->
|
||||
connection.async().spublish(getClientPresenceKey(accountIdentifier, deviceId), MESSAGES_PERSISTED_EVENT_BYTES))
|
||||
connection.async().spublish(getClientEventChannel(accountIdentifier, deviceId), MESSAGES_PERSISTED_EVENT_BYTES))
|
||||
.thenRun(Util.NOOP);
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
|
||||
public CompletableFuture<Void> requestDisconnection(final UUID accountIdentifier, final Collection<Byte> deviceIds) {
|
||||
return CompletableFuture.allOf(deviceIds.stream()
|
||||
.map(deviceId -> {
|
||||
final byte[] clientPresenceKey = getClientPresenceKey(accountIdentifier, deviceId);
|
||||
final byte[] clientPresenceKey = getClientEventChannel(accountIdentifier, deviceId);
|
||||
|
||||
return clusterClient.withBinaryCluster(connection -> connection.async()
|
||||
.spublish(clientPresenceKey, DISCONNECT_REQUESTED_EVENT_BYTES))
|
||||
@@ -323,12 +323,12 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
|
||||
// Organize subscriptions by slot so we can issue a smaller number of larger resubscription commands
|
||||
listenersByAccountAndDeviceIdentifier.keySet()
|
||||
.stream()
|
||||
.map(accountAndDeviceIdentifier -> getClientPresenceKey(accountAndDeviceIdentifier.accountIdentifier(), accountAndDeviceIdentifier.deviceId()))
|
||||
.forEach(clientPresenceKey -> {
|
||||
final int slot = SlotHash.getSlot(clientPresenceKey);
|
||||
.map(accountAndDeviceIdentifier -> getClientEventChannel(accountAndDeviceIdentifier.accountIdentifier(), accountAndDeviceIdentifier.deviceId()))
|
||||
.forEach(clientEventChannel -> {
|
||||
final int slot = SlotHash.getSlot(clientEventChannel);
|
||||
|
||||
if (changedSlots[slot]) {
|
||||
clientPresenceKeysBySlot.computeIfAbsent(slot, ignored -> new ArrayList<>()).add(clientPresenceKey);
|
||||
clientPresenceKeysBySlot.computeIfAbsent(slot, ignored -> new ArrayList<>()).add(clientEventChannel);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -380,8 +380,7 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static byte[] getClientPresenceKey(final UUID accountIdentifier, final byte deviceId) {
|
||||
public static byte[] getClientEventChannel(final UUID accountIdentifier, final byte deviceId) {
|
||||
return ("client_presence::{" + accountIdentifier + "::" + deviceId + "}").getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,36 +13,55 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.push.ClientEvent;
|
||||
import org.whispersystems.textsecuregcm.push.NewMessageAvailableEvent;
|
||||
import org.whispersystems.textsecuregcm.push.PubSubClientEventManager;
|
||||
import org.whispersystems.textsecuregcm.redis.ClusterLuaScript;
|
||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisClusterClient;
|
||||
|
||||
/**
|
||||
* Inserts an envelope into the message queue for a destination device.
|
||||
* Inserts an envelope into the message queue for a destination device and publishes a "new message available" event.
|
||||
*/
|
||||
class MessagesCacheInsertScript {
|
||||
|
||||
private final ClusterLuaScript insertScript;
|
||||
|
||||
private static final byte[] NEW_MESSAGE_EVENT_BYTES = ClientEvent.newBuilder()
|
||||
.setNewMessageAvailable(NewMessageAvailableEvent.getDefaultInstance())
|
||||
.build()
|
||||
.toByteArray();
|
||||
|
||||
MessagesCacheInsertScript(FaultTolerantRedisClusterClient redisCluster) throws IOException {
|
||||
this.insertScript = ClusterLuaScript.fromResource(redisCluster, "lua/insert_item.lua", ScriptOutputType.INTEGER);
|
||||
this.insertScript = ClusterLuaScript.fromResource(redisCluster, "lua/insert_item.lua", ScriptOutputType.BOOLEAN);
|
||||
}
|
||||
|
||||
void execute(final UUID destinationUuid, final byte destinationDevice, final MessageProtos.Envelope envelope) {
|
||||
/**
|
||||
* Inserts a message into the given device's message queue and publishes a "new message available" event.
|
||||
*
|
||||
* @param destinationUuid the account identifier for the receiving account
|
||||
* @param destinationDevice the ID of the receiving device within the given account
|
||||
* @param envelope the message to insert
|
||||
* @return {@code true} if the destination device had a registered "presence"/event subscriber or {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
boolean execute(final UUID destinationUuid, final byte destinationDevice, final MessageProtos.Envelope envelope) {
|
||||
assert envelope.hasServerGuid();
|
||||
assert envelope.hasServerTimestamp();
|
||||
|
||||
final List<byte[]> keys = List.of(
|
||||
MessagesCache.getMessageQueueKey(destinationUuid, destinationDevice), // queueKey
|
||||
MessagesCache.getMessageQueueMetadataKey(destinationUuid, destinationDevice), // queueMetadataKey
|
||||
MessagesCache.getQueueIndexKey(destinationUuid, destinationDevice) // queueTotalIndexKey
|
||||
MessagesCache.getQueueIndexKey(destinationUuid, destinationDevice), // queueTotalIndexKey
|
||||
PubSubClientEventManager.getClientEventChannel(destinationUuid, destinationDevice) // eventChannelKey
|
||||
);
|
||||
|
||||
final List<byte[]> args = new ArrayList<>(Arrays.asList(
|
||||
envelope.toByteArray(), // message
|
||||
String.valueOf(envelope.getServerTimestamp()).getBytes(StandardCharsets.UTF_8), // currentTime
|
||||
envelope.getServerGuid().getBytes(StandardCharsets.UTF_8) // guid
|
||||
envelope.getServerGuid().getBytes(StandardCharsets.UTF_8), // guid
|
||||
NEW_MESSAGE_EVENT_BYTES // eventPayload
|
||||
));
|
||||
|
||||
insertScript.executeBinary(keys, args);
|
||||
return (boolean) insertScript.executeBinary(keys, args);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user