Use UUIDs instead of phone numbers as account identifiers in clustered message cache

This commit is contained in:
Jon Chambers 2020-07-20 12:18:10 -04:00
parent 6fc1b4c6c0
commit f9f93c77e2
16 changed files with 148 additions and 115 deletions

View File

@ -314,7 +314,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
MessagesCache messagesCache = new MessagesCache(messagesClient, messages, accountsManager, config.getMessageCacheConfiguration().getPersistDelayMinutes(), clusterMessagesCache); MessagesCache messagesCache = new MessagesCache(messagesClient, messages, accountsManager, config.getMessageCacheConfiguration().getPersistDelayMinutes(), clusterMessagesCache);
MessagesManager messagesManager = new MessagesManager(messages, messagesCache); MessagesManager messagesManager = new MessagesManager(messages, messagesCache);
RemoteConfigsManager remoteConfigsManager = new RemoteConfigsManager(remoteConfigs); RemoteConfigsManager remoteConfigsManager = new RemoteConfigsManager(remoteConfigs);
DeadLetterHandler deadLetterHandler = new DeadLetterHandler(messagesManager); DeadLetterHandler deadLetterHandler = new DeadLetterHandler(accountsManager, messagesManager);
DispatchManager dispatchManager = new DispatchManager(pubSubClientFactory, Optional.of(deadLetterHandler)); DispatchManager dispatchManager = new DispatchManager(pubSubClientFactory, Optional.of(deadLetterHandler));
PubSubManager pubSubManager = new PubSubManager(pubsubClient, dispatchManager); PubSubManager pubSubManager = new PubSubManager(pubsubClient, dispatchManager);
APNSender apnSender = new APNSender(accountsManager, config.getApnConfiguration()); APNSender apnSender = new APNSender(accountsManager, config.getApnConfiguration());

View File

@ -612,6 +612,8 @@ public class AccountController {
} }
private Account createAccount(String number, String password, String userAgent, AccountAttributes accountAttributes) { private Account createAccount(String number, String password, String userAgent, AccountAttributes accountAttributes) {
Optional<Account> maybeExistingAccount = accounts.get(number);
Device device = new Device(); Device device = new Device();
device.setId(Device.MASTER_ID); device.setId(Device.MASTER_ID);
device.setAuthenticationCredentials(new AuthenticationCredentials(password)); device.setAuthenticationCredentials(new AuthenticationCredentials(password));
@ -643,7 +645,7 @@ public class AccountController {
directoryQueue.deleteRegisteredUser(account.getUuid(), number); directoryQueue.deleteRegisteredUser(account.getUuid(), number);
} }
messagesManager.clear(number); messagesManager.clear(number, maybeExistingAccount.map(Account::getUuid).orElse(null));
pendingAccounts.remove(number); pendingAccounts.remove(number);
return account; return account;

View File

@ -117,7 +117,7 @@ public class DeviceController {
directoryQueue.deleteRegisteredUser(account.getUuid(), account.getNumber()); directoryQueue.deleteRegisteredUser(account.getUuid(), account.getNumber());
} }
messages.clear(account.getNumber(), deviceId); messages.clear(account.getNumber(), account.getUuid(), deviceId);
} }
@Timed @Timed
@ -205,7 +205,7 @@ public class DeviceController {
device.setCreated(System.currentTimeMillis()); device.setCreated(System.currentTimeMillis());
account.get().addDevice(device); account.get().addDevice(device);
messages.clear(account.get().getNumber(), device.getId()); messages.clear(account.get().getNumber(), account.get().getUuid(), device.getId());
accounts.update(account.get()); accounts.update(account.get());
pendingDevices.remove(number); pendingDevices.remove(number);

View File

@ -189,6 +189,7 @@ public class MessageController {
} }
return messagesManager.getMessagesForDevice(account.getNumber(), return messagesManager.getMessagesForDevice(account.getNumber(),
account.getUuid(),
account.getAuthenticatedDevice().get().getId()); account.getAuthenticatedDevice().get().getId());
} }
@ -203,6 +204,7 @@ public class MessageController {
WebSocketConnection.messageTime.update(System.currentTimeMillis() - timestamp); WebSocketConnection.messageTime.update(System.currentTimeMillis() - timestamp);
Optional<OutgoingMessageEntity> message = messagesManager.delete(account.getNumber(), Optional<OutgoingMessageEntity> message = messagesManager.delete(account.getNumber(),
account.getUuid(),
account.getAuthenticatedDevice().get().getId(), account.getAuthenticatedDevice().get().getId(),
source, timestamp); source, timestamp);
@ -222,6 +224,7 @@ public class MessageController {
public void removePendingMessage(@Auth Account account, @PathParam("uuid") UUID uuid) { public void removePendingMessage(@Auth Account account, @PathParam("uuid") UUID uuid) {
try { try {
Optional<OutgoingMessageEntity> message = messagesManager.delete(account.getNumber(), Optional<OutgoingMessageEntity> message = messagesManager.delete(account.getNumber(),
account.getUuid(),
account.getAuthenticatedDevice().get().getId(), account.getAuthenticatedDevice().get().getId(),
uuid); uuid);

View File

@ -96,7 +96,7 @@ public class WebsocketSender {
WebsocketAddress address = new WebsocketAddress(account.getNumber(), device.getId()); WebsocketAddress address = new WebsocketAddress(account.getNumber(), device.getId());
messagesManager.insert(account.getNumber(), device.getId(), message); messagesManager.insert(account.getNumber(), account.getUuid(), device.getId(), message);
pubSubManager.publish(address, PubSubMessage.newBuilder() pubSubManager.publish(address, PubSubMessage.newBuilder()
.setType(PubSubMessage.Type.QUERY_DB) .setType(PubSubMessage.Type.QUERY_DB)
.build()); .build());

View File

@ -89,14 +89,14 @@ public class MessagesCache implements Managed, UserMessagesCache {
} }
@Override @Override
public long insert(UUID guid, String destination, long destinationDevice, Envelope message) { public long insert(UUID guid, String destination, final UUID destinationUuid, long destinationDevice, Envelope message) {
final Envelope messageWithGuid = message.toBuilder().setServerGuid(guid.toString()).build(); final Envelope messageWithGuid = message.toBuilder().setServerGuid(guid.toString()).build();
Timer.Context timer = insertTimer.time(); Timer.Context timer = insertTimer.time();
try { try {
final long messageId = insertOperation.insert(guid, destination, destinationDevice, System.currentTimeMillis(), messageWithGuid); final long messageId = insertOperation.insert(guid, destination, destinationDevice, System.currentTimeMillis(), messageWithGuid);
insertExperiment.compareSupplierResultAsync(messageId, () -> clusterMessagesCache.insert(guid, destination, destinationDevice, message, messageId), experimentExecutor); insertExperiment.compareSupplierResultAsync(messageId, () -> clusterMessagesCache.insert(guid, destination, destinationUuid, destinationDevice, message, messageId), experimentExecutor);
return messageId; return messageId;
} finally { } finally {
@ -105,7 +105,7 @@ public class MessagesCache implements Managed, UserMessagesCache {
} }
@Override @Override
public Optional<OutgoingMessageEntity> remove(String destination, long destinationDevice, long id) { public Optional<OutgoingMessageEntity> remove(String destination, final UUID destinationUuid, long destinationDevice, long id) {
OutgoingMessageEntity removedMessageEntity = null; OutgoingMessageEntity removedMessageEntity = null;
try (Jedis jedis = jedisPool.getWriteResource(); try (Jedis jedis = jedisPool.getWriteResource();
@ -122,13 +122,13 @@ public class MessagesCache implements Managed, UserMessagesCache {
final Optional<OutgoingMessageEntity> maybeRemovedMessage = Optional.ofNullable(removedMessageEntity); final Optional<OutgoingMessageEntity> maybeRemovedMessage = Optional.ofNullable(removedMessageEntity);
removeByIdExperiment.compareSupplierResultAsync(maybeRemovedMessage, () -> clusterMessagesCache.remove(destination, destinationDevice, id), experimentExecutor); removeByIdExperiment.compareSupplierResultAsync(maybeRemovedMessage, () -> clusterMessagesCache.remove(destination, destinationUuid, destinationDevice, id), experimentExecutor);
return maybeRemovedMessage; return maybeRemovedMessage;
} }
@Override @Override
public Optional<OutgoingMessageEntity> remove(String destination, long destinationDevice, String sender, long timestamp) { public Optional<OutgoingMessageEntity> remove(String destination, final UUID destinationUuid, long destinationDevice, String sender, long timestamp) {
OutgoingMessageEntity removedMessageEntity = null; OutgoingMessageEntity removedMessageEntity = null;
Timer.Context timer = removeByNameTimer.time(); Timer.Context timer = removeByNameTimer.time();
@ -146,13 +146,13 @@ public class MessagesCache implements Managed, UserMessagesCache {
final Optional<OutgoingMessageEntity> maybeRemovedMessage = Optional.ofNullable(removedMessageEntity); final Optional<OutgoingMessageEntity> maybeRemovedMessage = Optional.ofNullable(removedMessageEntity);
removeBySenderExperiment.compareSupplierResultAsync(maybeRemovedMessage, () -> clusterMessagesCache.remove(destination, destinationDevice, sender, timestamp), experimentExecutor); removeBySenderExperiment.compareSupplierResultAsync(maybeRemovedMessage, () -> clusterMessagesCache.remove(destination, destinationUuid, destinationDevice, sender, timestamp), experimentExecutor);
return maybeRemovedMessage; return maybeRemovedMessage;
} }
@Override @Override
public Optional<OutgoingMessageEntity> remove(String destination, long destinationDevice, UUID guid) { public Optional<OutgoingMessageEntity> remove(String destination, final UUID destinationUuid, long destinationDevice, UUID guid) {
OutgoingMessageEntity removedMessageEntity = null; OutgoingMessageEntity removedMessageEntity = null;
Timer.Context timer = removeByGuidTimer.time(); Timer.Context timer = removeByGuidTimer.time();
@ -170,13 +170,13 @@ public class MessagesCache implements Managed, UserMessagesCache {
final Optional<OutgoingMessageEntity> maybeRemovedMessage = Optional.ofNullable(removedMessageEntity); final Optional<OutgoingMessageEntity> maybeRemovedMessage = Optional.ofNullable(removedMessageEntity);
removeByUuidExperiment.compareSupplierResultAsync(maybeRemovedMessage, () -> clusterMessagesCache.remove(destination, destinationDevice, guid), experimentExecutor); removeByUuidExperiment.compareSupplierResultAsync(maybeRemovedMessage, () -> clusterMessagesCache.remove(destination, destinationUuid, destinationDevice, guid), experimentExecutor);
return maybeRemovedMessage; return maybeRemovedMessage;
} }
@Override @Override
public List<OutgoingMessageEntity> get(String destination, long destinationDevice, int limit) { public List<OutgoingMessageEntity> get(String destination, final UUID destinationUuid, long destinationDevice, int limit) {
Timer.Context timer = getTimer.time(); Timer.Context timer = getTimer.time();
try { try {
@ -194,7 +194,7 @@ public class MessagesCache implements Managed, UserMessagesCache {
} }
} }
getMessagesExperiment.compareSupplierResultAsync(results, () -> clusterMessagesCache.get(destination, destinationDevice, limit), experimentExecutor); getMessagesExperiment.compareSupplierResultAsync(results, () -> clusterMessagesCache.get(destination, destinationUuid, destinationDevice, limit), experimentExecutor);
return results; return results;
} finally { } finally {
@ -203,12 +203,12 @@ public class MessagesCache implements Managed, UserMessagesCache {
} }
@Override @Override
public void clear(String destination) { public void clear(String destination, final UUID destinationUuid) {
Timer.Context timer = clearAccountTimer.time(); Timer.Context timer = clearAccountTimer.time();
try { try {
for (int i = 1; i < 255; i++) { for (int i = 1; i < 255; i++) {
clear(destination, i); clear(destination, destinationUuid, i);
} }
} finally { } finally {
timer.stop(); timer.stop();
@ -216,7 +216,7 @@ public class MessagesCache implements Managed, UserMessagesCache {
} }
@Override @Override
public void clear(String destination, long deviceId) { public void clear(String destination, final UUID destinationUuid, long deviceId) {
Timer.Context timer = clearDeviceTimer.time(); Timer.Context timer = clearDeviceTimer.time();
try { try {

View File

@ -34,34 +34,34 @@ public class MessagesManager {
this.messagesCache = messagesCache; this.messagesCache = messagesCache;
} }
public void insert(String destination, long destinationDevice, Envelope message) { public void insert(String destination, UUID destinationUuid, long destinationDevice, Envelope message) {
UUID guid = UUID.randomUUID(); UUID guid = UUID.randomUUID();
messagesCache.insert(guid, destination, destinationDevice, message); messagesCache.insert(guid, destination, destinationUuid, destinationDevice, message);
} }
public OutgoingMessageEntityList getMessagesForDevice(String destination, long destinationDevice) { public OutgoingMessageEntityList getMessagesForDevice(String destination, UUID destinationUuid, long destinationDevice) {
List<OutgoingMessageEntity> messages = this.messages.load(destination, destinationDevice); List<OutgoingMessageEntity> messages = this.messages.load(destination, destinationDevice);
if (messages.size() <= Messages.RESULT_SET_CHUNK_SIZE) { if (messages.size() <= Messages.RESULT_SET_CHUNK_SIZE) {
messages.addAll(this.messagesCache.get(destination, destinationDevice, Messages.RESULT_SET_CHUNK_SIZE - messages.size())); messages.addAll(this.messagesCache.get(destination, destinationUuid, destinationDevice, Messages.RESULT_SET_CHUNK_SIZE - messages.size()));
} }
return new OutgoingMessageEntityList(messages, messages.size() >= Messages.RESULT_SET_CHUNK_SIZE); return new OutgoingMessageEntityList(messages, messages.size() >= Messages.RESULT_SET_CHUNK_SIZE);
} }
public void clear(String destination) { public void clear(String destination, UUID destinationUuid) {
this.messagesCache.clear(destination); this.messagesCache.clear(destination, destinationUuid);
this.messages.clear(destination); this.messages.clear(destination);
} }
public void clear(String destination, long deviceId) { public void clear(String destination, UUID destinationUuid, long deviceId) {
this.messagesCache.clear(destination, deviceId); this.messagesCache.clear(destination, destinationUuid, deviceId);
this.messages.clear(destination, deviceId); this.messages.clear(destination, deviceId);
} }
public Optional<OutgoingMessageEntity> delete(String destination, long destinationDevice, String source, long timestamp) public Optional<OutgoingMessageEntity> delete(String destination, UUID destinationUuid, long destinationDevice, String source, long timestamp)
{ {
Optional<OutgoingMessageEntity> removed = this.messagesCache.remove(destination, destinationDevice, source, timestamp); Optional<OutgoingMessageEntity> removed = this.messagesCache.remove(destination, destinationUuid, destinationDevice, source, timestamp);
if (!removed.isPresent()) { if (!removed.isPresent()) {
removed = this.messages.remove(destination, destinationDevice, source, timestamp); removed = this.messages.remove(destination, destinationDevice, source, timestamp);
@ -73,8 +73,8 @@ public class MessagesManager {
return removed; return removed;
} }
public Optional<OutgoingMessageEntity> delete(String destination, long deviceId, UUID guid) { public Optional<OutgoingMessageEntity> delete(String destination, UUID destinationUuid, long deviceId, UUID guid) {
Optional<OutgoingMessageEntity> removed = this.messagesCache.remove(destination, deviceId, guid); Optional<OutgoingMessageEntity> removed = this.messagesCache.remove(destination, destinationUuid, deviceId, guid);
if (!removed.isPresent()) { if (!removed.isPresent()) {
removed = this.messages.remove(destination, guid); removed = this.messages.remove(destination, guid);
@ -86,9 +86,9 @@ public class MessagesManager {
return removed; return removed;
} }
public void delete(String destination, long deviceId, long id, boolean cached) { public void delete(String destination, UUID destinationUuid, long deviceId, long id, boolean cached) {
if (cached) { if (cached) {
this.messagesCache.remove(destination, deviceId, id); this.messagesCache.remove(destination, destinationUuid, deviceId, id);
cacheHitByIdMeter.mark(); cacheHitByIdMeter.mark();
} else { } else {
this.messages.remove(destination, id); this.messages.remove(destination, id);

View File

@ -53,28 +53,28 @@ public class RedisClusterMessagesCache implements UserMessagesCache {
} }
@Override @Override
public long insert(final UUID guid, final String destination, final long destinationDevice, final MessageProtos.Envelope message) { public long insert(final UUID guid, final String destination, final UUID destinationUuid, final long destinationDevice, final MessageProtos.Envelope message) {
final MessageProtos.Envelope messageWithGuid = message.toBuilder().setServerGuid(guid.toString()).build(); final MessageProtos.Envelope messageWithGuid = message.toBuilder().setServerGuid(guid.toString()).build();
final String sender = message.hasSource() ? (message.getSource() + "::" + message.getTimestamp()) : "nil"; final String sender = message.hasSource() ? (message.getSource() + "::" + message.getTimestamp()) : "nil";
return (long)Metrics.timer(INSERT_TIMER_NAME).record(() -> return (long)Metrics.timer(INSERT_TIMER_NAME).record(() ->
insertScript.executeBinary(List.of(getMessageQueueKey(destination, destinationDevice), insertScript.executeBinary(List.of(getMessageQueueKey(destinationUuid, destinationDevice),
getMessageQueueMetadataKey(destination, destinationDevice), getMessageQueueMetadataKey(destinationUuid, destinationDevice),
getQueueIndexKey(destination, destinationDevice)), getQueueIndexKey(destinationUuid, destinationDevice)),
List.of(messageWithGuid.toByteArray(), List.of(messageWithGuid.toByteArray(),
String.valueOf(message.getTimestamp()).getBytes(StandardCharsets.UTF_8), String.valueOf(message.getTimestamp()).getBytes(StandardCharsets.UTF_8),
sender.getBytes(StandardCharsets.UTF_8), sender.getBytes(StandardCharsets.UTF_8),
guid.toString().getBytes(StandardCharsets.UTF_8)))); guid.toString().getBytes(StandardCharsets.UTF_8))));
} }
public long insert(final UUID guid, final String destination, final long destinationDevice, final MessageProtos.Envelope message, final long messageId) { public long insert(final UUID guid, final String destination, final UUID destinationUuid, final long destinationDevice, final MessageProtos.Envelope message, final long messageId) {
final MessageProtos.Envelope messageWithGuid = message.toBuilder().setServerGuid(guid.toString()).build(); final MessageProtos.Envelope messageWithGuid = message.toBuilder().setServerGuid(guid.toString()).build();
final String sender = message.hasSource() ? (message.getSource() + "::" + message.getTimestamp()) : "nil"; final String sender = message.hasSource() ? (message.getSource() + "::" + message.getTimestamp()) : "nil";
return (long)Metrics.timer(INSERT_TIMER_NAME).record(() -> return (long)Metrics.timer(INSERT_TIMER_NAME).record(() ->
insertScript.executeBinary(List.of(getMessageQueueKey(destination, destinationDevice), insertScript.executeBinary(List.of(getMessageQueueKey(destinationUuid, destinationDevice),
getMessageQueueMetadataKey(destination, destinationDevice), getMessageQueueMetadataKey(destinationUuid, destinationDevice),
getQueueIndexKey(destination, destinationDevice)), getQueueIndexKey(destinationUuid, destinationDevice)),
List.of(messageWithGuid.toByteArray(), List.of(messageWithGuid.toByteArray(),
String.valueOf(message.getTimestamp()).getBytes(StandardCharsets.UTF_8), String.valueOf(message.getTimestamp()).getBytes(StandardCharsets.UTF_8),
sender.getBytes(StandardCharsets.UTF_8), sender.getBytes(StandardCharsets.UTF_8),
@ -83,12 +83,12 @@ public class RedisClusterMessagesCache implements UserMessagesCache {
} }
@Override @Override
public Optional<OutgoingMessageEntity> remove(final String destination, final long destinationDevice, final long id) { public Optional<OutgoingMessageEntity> remove(final String destination, final UUID destinationUuid, final long destinationDevice, final long id) {
try { try {
final byte[] serialized = (byte[])Metrics.timer(REMOVE_TIMER_NAME, REMOVE_METHOD_TAG, REMOVE_METHOD_ID).record(() -> final byte[] serialized = (byte[])Metrics.timer(REMOVE_TIMER_NAME, REMOVE_METHOD_TAG, REMOVE_METHOD_ID).record(() ->
removeByIdScript.executeBinary(List.of(getMessageQueueKey(destination, destinationDevice), removeByIdScript.executeBinary(List.of(getMessageQueueKey(destinationUuid, destinationDevice),
getMessageQueueMetadataKey(destination, destinationDevice), getMessageQueueMetadataKey(destinationUuid, destinationDevice),
getQueueIndexKey(destination, destinationDevice)), getQueueIndexKey(destinationUuid, destinationDevice)),
List.of(String.valueOf(id).getBytes(StandardCharsets.UTF_8)))); List.of(String.valueOf(id).getBytes(StandardCharsets.UTF_8))));
@ -103,12 +103,12 @@ public class RedisClusterMessagesCache implements UserMessagesCache {
} }
@Override @Override
public Optional<OutgoingMessageEntity> remove(final String destination, final long destinationDevice, final String sender, final long timestamp) { public Optional<OutgoingMessageEntity> remove(final String destination, final UUID destinationUuid, final long destinationDevice, final String sender, final long timestamp) {
try { try {
final byte[] serialized = (byte[])Metrics.timer(REMOVE_TIMER_NAME, REMOVE_METHOD_TAG, REMOVE_METHOD_SENDER).record(() -> final byte[] serialized = (byte[])Metrics.timer(REMOVE_TIMER_NAME, REMOVE_METHOD_TAG, REMOVE_METHOD_SENDER).record(() ->
removeBySenderScript.executeBinary(List.of(getMessageQueueKey(destination, destinationDevice), removeBySenderScript.executeBinary(List.of(getMessageQueueKey(destinationUuid, destinationDevice),
getMessageQueueMetadataKey(destination, destinationDevice), getMessageQueueMetadataKey(destinationUuid, destinationDevice),
getQueueIndexKey(destination, destinationDevice)), getQueueIndexKey(destinationUuid, destinationDevice)),
List.of((sender + "::" + timestamp).getBytes(StandardCharsets.UTF_8)))); List.of((sender + "::" + timestamp).getBytes(StandardCharsets.UTF_8))));
if (serialized != null) { if (serialized != null) {
@ -122,12 +122,12 @@ public class RedisClusterMessagesCache implements UserMessagesCache {
} }
@Override @Override
public Optional<OutgoingMessageEntity> remove(final String destination, final long destinationDevice, final UUID guid) { public Optional<OutgoingMessageEntity> remove(final String destination, final UUID destinationUuid, final long destinationDevice, final UUID guid) {
try { try {
final byte[] serialized = (byte[])Metrics.timer(REMOVE_TIMER_NAME, REMOVE_METHOD_TAG, REMOVE_METHOD_UUID).record(() -> final byte[] serialized = (byte[])Metrics.timer(REMOVE_TIMER_NAME, REMOVE_METHOD_TAG, REMOVE_METHOD_UUID).record(() ->
removeByGuidScript.executeBinary(List.of(getMessageQueueKey(destination, destinationDevice), removeByGuidScript.executeBinary(List.of(getMessageQueueKey(destinationUuid, destinationDevice),
getMessageQueueMetadataKey(destination, destinationDevice), getMessageQueueMetadataKey(destinationUuid, destinationDevice),
getQueueIndexKey(destination, destinationDevice)), getQueueIndexKey(destinationUuid, destinationDevice)),
List.of(guid.toString().getBytes(StandardCharsets.UTF_8)))); List.of(guid.toString().getBytes(StandardCharsets.UTF_8))));
if (serialized != null) { if (serialized != null) {
@ -142,10 +142,10 @@ public class RedisClusterMessagesCache implements UserMessagesCache {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<OutgoingMessageEntity> get(String destination, long destinationDevice, int limit) { public List<OutgoingMessageEntity> get(String destination, final UUID destinationUuid, long destinationDevice, int limit) {
return Metrics.timer(GET_TIMER_NAME).record(() -> { return Metrics.timer(GET_TIMER_NAME).record(() -> {
final List<byte[]> queueItems = (List<byte[]>)getItemsScript.executeBinary(List.of(getMessageQueueKey(destination, destinationDevice), final List<byte[]> queueItems = (List<byte[]>)getItemsScript.executeBinary(List.of(getMessageQueueKey(destinationUuid, destinationDevice),
getPersistInProgressKey(destination, destinationDevice)), getPersistInProgressKey(destinationUuid, destinationDevice)),
List.of(String.valueOf(limit).getBytes())); List.of(String.valueOf(limit).getBytes()));
final List<OutgoingMessageEntity> messageEntities; final List<OutgoingMessageEntity> messageEntities;
@ -173,34 +173,37 @@ public class RedisClusterMessagesCache implements UserMessagesCache {
} }
@Override @Override
public void clear(final String destination) { public void clear(final String destination, final UUID destinationUuid) {
// TODO Remove null check in a fully UUID-based world
if (destinationUuid != null) {
for (int i = 1; i < 256; i++) { for (int i = 1; i < 256; i++) {
clear(destination, i); clear(destination, destinationUuid, i);
}
} }
} }
@Override @Override
public void clear(final String destination, final long deviceId) { public void clear(final String destination, final UUID destinationUuid, final long deviceId) {
Metrics.timer(CLEAR_TIMER_NAME).record(() -> Metrics.timer(CLEAR_TIMER_NAME).record(() ->
removeQueueScript.executeBinary(List.of(getMessageQueueKey(destination, deviceId), removeQueueScript.executeBinary(List.of(getMessageQueueKey(destinationUuid, deviceId),
getMessageQueueMetadataKey(destination, deviceId), getMessageQueueMetadataKey(destinationUuid, deviceId),
getQueueIndexKey(destination, deviceId)), getQueueIndexKey(destinationUuid, deviceId)),
Collections.emptyList())); Collections.emptyList()));
} }
private static byte[] getMessageQueueKey(final String address, final long deviceId) { private static byte[] getMessageQueueKey(final UUID accountUuid, final long deviceId) {
return ("user_queue::{" + address + "::" + deviceId + "}").getBytes(StandardCharsets.UTF_8); return ("user_queue::{" + accountUuid.toString() + "::" + deviceId + "}").getBytes(StandardCharsets.UTF_8);
} }
private static byte[] getMessageQueueMetadataKey(final String address, final long deviceId) { private static byte[] getMessageQueueMetadataKey(final UUID accountUuid, final long deviceId) {
return ("user_queue_metadata::{" + address + "::" + deviceId + "}").getBytes(StandardCharsets.UTF_8); return ("user_queue_metadata::{" + accountUuid.toString() + "::" + deviceId + "}").getBytes(StandardCharsets.UTF_8);
} }
private byte[] getQueueIndexKey(final String address, final long deviceId) { private byte[] getQueueIndexKey(final UUID accountUuid, final long deviceId) {
return ("user_queue_index::{" + RedisClusterUtil.getMinimalHashTag(address + "::" + deviceId) + "}").getBytes(StandardCharsets.UTF_8); return ("user_queue_index::{" + RedisClusterUtil.getMinimalHashTag(accountUuid.toString() + "::" + deviceId) + "}").getBytes(StandardCharsets.UTF_8);
} }
private byte[] getPersistInProgressKey(final String address, final long deviceId) { private byte[] getPersistInProgressKey(final UUID accountUuid, final long deviceId) {
return ("user_queue_persisting::{" + address + "::" + deviceId + "}").getBytes(StandardCharsets.UTF_8); return ("user_queue_persisting::{" + accountUuid.toString() + "::" + deviceId + "}").getBytes(StandardCharsets.UTF_8);
} }
} }

View File

@ -3,7 +3,6 @@ package org.whispersystems.textsecuregcm.storage;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.whispersystems.textsecuregcm.entities.MessageProtos; import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.entities.OutgoingMessageEntity; import org.whispersystems.textsecuregcm.entities.OutgoingMessageEntity;
import org.whispersystems.textsecuregcm.push.PushSender;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -25,17 +24,17 @@ public interface UserMessagesCache {
envelope.hasServerTimestamp() ? envelope.getServerTimestamp() : 0); envelope.hasServerTimestamp() ? envelope.getServerTimestamp() : 0);
} }
long insert(UUID guid, String destination, long destinationDevice, MessageProtos.Envelope message); long insert(UUID guid, String destination, UUID destinationUuid, long destinationDevice, MessageProtos.Envelope message);
Optional<OutgoingMessageEntity> remove(String destination, long destinationDevice, long id); Optional<OutgoingMessageEntity> remove(String destination, UUID destinationUuid, long destinationDevice, long id);
Optional<OutgoingMessageEntity> remove(String destination, long destinationDevice, String sender, long timestamp); Optional<OutgoingMessageEntity> remove(String destination, UUID destinationUuid, long destinationDevice, String sender, long timestamp);
Optional<OutgoingMessageEntity> remove(String destination, long destinationDevice, UUID guid); Optional<OutgoingMessageEntity> remove(String destination, UUID destinationUuid, long destinationDevice, UUID guid);
List<OutgoingMessageEntity> get(String destination, long destinationDevice, int limit); List<OutgoingMessageEntity> get(String destination, UUID destinationUuid, long destinationDevice, int limit);
void clear(String destination); void clear(String destination, UUID destinationUuid);
void clear(String destination, long deviceId); void clear(String destination, UUID destinationUuid, long deviceId);
} }

View File

@ -7,20 +7,26 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.dispatch.DispatchChannel; import org.whispersystems.dispatch.DispatchChannel;
import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope; import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.storage.PubSubProtos.PubSubMessage; import org.whispersystems.textsecuregcm.storage.PubSubProtos.PubSubMessage;
import java.util.Optional;
import static com.codahale.metrics.MetricRegistry.name; import static com.codahale.metrics.MetricRegistry.name;
public class DeadLetterHandler implements DispatchChannel { public class DeadLetterHandler implements DispatchChannel {
private final Logger logger = LoggerFactory.getLogger(DeadLetterHandler.class); private final Logger logger = LoggerFactory.getLogger(DeadLetterHandler.class);
private final AccountsManager accountsManager;
private final MessagesManager messagesManager; private final MessagesManager messagesManager;
private final Counter deadLetterCounter = Metrics.counter(name(getClass(), "deadLetterCounter")); private final Counter deadLetterCounter = Metrics.counter(name(getClass(), "deadLetterCounter"));
public DeadLetterHandler(MessagesManager messagesManager) { public DeadLetterHandler(AccountsManager accountsManager, MessagesManager messagesManager) {
this.accountsManager = accountsManager;
this.messagesManager = messagesManager; this.messagesManager = messagesManager;
} }
@ -36,7 +42,14 @@ public class DeadLetterHandler implements DispatchChannel {
switch (pubSubMessage.getType().getNumber()) { switch (pubSubMessage.getType().getNumber()) {
case PubSubMessage.Type.DELIVER_VALUE: case PubSubMessage.Type.DELIVER_VALUE:
Envelope message = Envelope.parseFrom(pubSubMessage.getContent()); Envelope message = Envelope.parseFrom(pubSubMessage.getContent());
messagesManager.insert(address.getNumber(), address.getDeviceId(), message); Optional<Account> maybeAccount = accountsManager.get(address.getNumber());
if (maybeAccount.isPresent()) {
messagesManager.insert(address.getNumber(), maybeAccount.get().getUuid(), address.getDeviceId(), message);
} else {
logger.warn("Dead letter for account that no longer exists: {}", address);
}
break; break;
} }
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {

View File

@ -129,7 +129,7 @@ public class WebSocketConnection implements DispatchChannel {
} }
if (isSuccessResponse(response)) { if (isSuccessResponse(response)) {
if (storedMessageInfo.isPresent()) messagesManager.delete(account.getNumber(), device.getId(), storedMessageInfo.get().id, storedMessageInfo.get().cached); if (storedMessageInfo.isPresent()) messagesManager.delete(account.getNumber(), account.getUuid(), device.getId(), storedMessageInfo.get().id, storedMessageInfo.get().cached);
if (!isReceipt) sendDeliveryReceiptFor(message); if (!isReceipt) sendDeliveryReceiptFor(message);
if (requery) processStoredMessages(); if (requery) processStoredMessages();
} else if (!isSuccessResponse(response) && !storedMessageInfo.isPresent()) { } else if (!isSuccessResponse(response) && !storedMessageInfo.isPresent()) {
@ -172,7 +172,7 @@ public class WebSocketConnection implements DispatchChannel {
} }
private void processStoredMessages() { private void processStoredMessages() {
OutgoingMessageEntityList messages = messagesManager.getMessagesForDevice(account.getNumber(), device.getId()); OutgoingMessageEntityList messages = messagesManager.getMessagesForDevice(account.getNumber(), account.getUuid(), device.getId());
Iterator<OutgoingMessageEntity> iterator = messages.getMessages().iterator(); Iterator<OutgoingMessageEntity> iterator = messages.getMessages().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {

View File

@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest { public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest {
private static final String DESTINATION_ACCOUNT = "+18005551234"; private static final String DESTINATION_ACCOUNT = "+18005551234";
private static final UUID DESTINATION_UUID = UUID.randomUUID();
private static final int DESTINATION_DEVICE_ID = 7; private static final int DESTINATION_DEVICE_ID = 7;
private final Random random = new Random(); private final Random random = new Random();
@ -35,7 +36,7 @@ public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest
@Parameters({"true", "false"}) @Parameters({"true", "false"})
public void testInsert(final boolean sealedSender) { public void testInsert(final boolean sealedSender) {
final UUID messageGuid = UUID.randomUUID(); final UUID messageGuid = UUID.randomUUID();
assertTrue(getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, generateRandomMessage(messageGuid, sealedSender)) > 0); assertTrue(getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, generateRandomMessage(messageGuid, sealedSender)) > 0);
} }
@Test @Test
@ -44,12 +45,12 @@ public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest
final UUID messageGuid = UUID.randomUUID(); final UUID messageGuid = UUID.randomUUID();
final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender); final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender);
final long messageId = getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, message); final long messageId = getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, message);
final Optional<OutgoingMessageEntity> maybeRemovedMessage = getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, messageId); final Optional<OutgoingMessageEntity> maybeRemovedMessage = getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, messageId);
assertTrue(maybeRemovedMessage.isPresent()); assertTrue(maybeRemovedMessage.isPresent());
assertEquals(UserMessagesCache.constructEntityFromEnvelope(messageId, message), maybeRemovedMessage.get()); assertEquals(UserMessagesCache.constructEntityFromEnvelope(messageId, message), maybeRemovedMessage.get());
assertEquals(Optional.empty(), getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, messageId)); assertEquals(Optional.empty(), getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, messageId));
} }
@Test @Test
@ -57,12 +58,12 @@ public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest
final UUID messageGuid = UUID.randomUUID(); final UUID messageGuid = UUID.randomUUID();
final MessageProtos.Envelope message = generateRandomMessage(messageGuid, false); final MessageProtos.Envelope message = generateRandomMessage(messageGuid, false);
getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, message); getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, message);
final Optional<OutgoingMessageEntity> maybeRemovedMessage = getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, message.getSource(), message.getTimestamp()); final Optional<OutgoingMessageEntity> maybeRemovedMessage = getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, message.getSource(), message.getTimestamp());
assertTrue(maybeRemovedMessage.isPresent()); assertTrue(maybeRemovedMessage.isPresent());
assertEquals(UserMessagesCache.constructEntityFromEnvelope(0, message), maybeRemovedMessage.get()); assertEquals(UserMessagesCache.constructEntityFromEnvelope(0, message), maybeRemovedMessage.get());
assertEquals(Optional.empty(), getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, message.getSource(), message.getTimestamp())); assertEquals(Optional.empty(), getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, message.getSource(), message.getTimestamp()));
} }
@Test @Test
@ -70,12 +71,12 @@ public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest
public void testRemoveByUUID(final boolean sealedSender) { public void testRemoveByUUID(final boolean sealedSender) {
final UUID messageGuid = UUID.randomUUID(); final UUID messageGuid = UUID.randomUUID();
assertEquals(Optional.empty(), getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, messageGuid)); assertEquals(Optional.empty(), getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, messageGuid));
final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender); final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender);
getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, message); getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, message);
final Optional<OutgoingMessageEntity> maybeRemovedMessage = getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, messageGuid); final Optional<OutgoingMessageEntity> maybeRemovedMessage = getMessagesCache().remove(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, messageGuid);
assertTrue(maybeRemovedMessage.isPresent()); assertTrue(maybeRemovedMessage.isPresent());
assertEquals(UserMessagesCache.constructEntityFromEnvelope(0, message), maybeRemovedMessage.get()); assertEquals(UserMessagesCache.constructEntityFromEnvelope(0, message), maybeRemovedMessage.get());
@ -91,12 +92,12 @@ public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest
for (int i = 0; i < messageCount; i++) { for (int i = 0; i < messageCount; i++) {
final UUID messageGuid = UUID.randomUUID(); final UUID messageGuid = UUID.randomUUID();
final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender); final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender);
final long messageId = getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, message); final long messageId = getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, message);
expectedMessages.add(UserMessagesCache.constructEntityFromEnvelope(messageId, message)); expectedMessages.add(UserMessagesCache.constructEntityFromEnvelope(messageId, message));
} }
assertEquals(expectedMessages, getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, messageCount)); assertEquals(expectedMessages, getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, messageCount));
} }
@Test @Test
@ -109,14 +110,14 @@ public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest
final UUID messageGuid = UUID.randomUUID(); final UUID messageGuid = UUID.randomUUID();
final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender); final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender);
getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, deviceId, message); getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, deviceId, message);
} }
} }
getMessagesCache().clear(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID); getMessagesCache().clear(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID);
assertEquals(Collections.emptyList(), getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, messageCount)); assertEquals(Collections.emptyList(), getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, messageCount));
assertEquals(messageCount, getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID + 1, messageCount).size()); assertEquals(messageCount, getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID + 1, messageCount).size());
} }
@Test @Test
@ -129,14 +130,14 @@ public abstract class AbstractMessagesCacheTest extends AbstractRedisClusterTest
final UUID messageGuid = UUID.randomUUID(); final UUID messageGuid = UUID.randomUUID();
final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender); final MessageProtos.Envelope message = generateRandomMessage(messageGuid, sealedSender);
getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, deviceId, message); getMessagesCache().insert(messageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, deviceId, message);
} }
} }
getMessagesCache().clear(DESTINATION_ACCOUNT); getMessagesCache().clear(DESTINATION_ACCOUNT, DESTINATION_UUID);
assertEquals(Collections.emptyList(), getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, messageCount)); assertEquals(Collections.emptyList(), getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, messageCount));
assertEquals(Collections.emptyList(), getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID + 1, messageCount)); assertEquals(Collections.emptyList(), getMessagesCache().get(DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID + 1, messageCount));
} }
protected MessageProtos.Envelope generateRandomMessage(final UUID messageGuid, final boolean sealedSender) { protected MessageProtos.Envelope generateRandomMessage(final UUID messageGuid, final boolean sealedSender) {

View File

@ -12,6 +12,7 @@ import static org.junit.Assert.assertEquals;
public class RedisClusterMessagesCacheTest extends AbstractMessagesCacheTest { public class RedisClusterMessagesCacheTest extends AbstractMessagesCacheTest {
private static final String DESTINATION_ACCOUNT = "+18005551234"; private static final String DESTINATION_ACCOUNT = "+18005551234";
private static final UUID DESTINATION_UUID = UUID.randomUUID();
private static final int DESTINATION_DEVICE_ID = 7; private static final int DESTINATION_DEVICE_ID = 7;
private RedisClusterMessagesCache messagesCache; private RedisClusterMessagesCache messagesCache;
@ -42,7 +43,13 @@ public class RedisClusterMessagesCacheTest extends AbstractMessagesCacheTest {
final UUID secondMessageGuid = UUID.randomUUID(); final UUID secondMessageGuid = UUID.randomUUID();
final long messageId = 74; final long messageId = 74;
assertEquals(messageId, messagesCache.insert(firstMessageGuid, DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, generateRandomMessage(firstMessageGuid, sealedSender), messageId)); assertEquals(messageId, messagesCache.insert(firstMessageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, generateRandomMessage(firstMessageGuid, sealedSender), messageId));
assertEquals(messageId + 1, messagesCache.insert(secondMessageGuid, DESTINATION_ACCOUNT, DESTINATION_DEVICE_ID, generateRandomMessage(secondMessageGuid, sealedSender))); assertEquals(messageId + 1, messagesCache.insert(secondMessageGuid, DESTINATION_ACCOUNT, DESTINATION_UUID, DESTINATION_DEVICE_ID, generateRandomMessage(secondMessageGuid, sealedSender)));
}
@Test
public void testClearNullUuid() {
// We're happy as long as this doesn't throw an exception
messagesCache.clear(DESTINATION_ACCOUNT, null);
} }
} }

View File

@ -113,6 +113,7 @@ public class DeviceControllerTest {
when(account.getNextDeviceId()).thenReturn(42L); when(account.getNextDeviceId()).thenReturn(42L);
when(account.getNumber()).thenReturn(AuthHelper.VALID_NUMBER); when(account.getNumber()).thenReturn(AuthHelper.VALID_NUMBER);
when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
// when(maxedAccount.getActiveDeviceCount()).thenReturn(6); // when(maxedAccount.getActiveDeviceCount()).thenReturn(6);
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(masterDevice)); when(account.getAuthenticatedDevice()).thenReturn(Optional.of(masterDevice));
when(account.isEnabled()).thenReturn(false); when(account.isEnabled()).thenReturn(false);
@ -144,7 +145,7 @@ public class DeviceControllerTest {
assertThat(response.getDeviceId()).isEqualTo(42L); assertThat(response.getDeviceId()).isEqualTo(42L);
verify(pendingDevicesManager).remove(AuthHelper.VALID_NUMBER); verify(pendingDevicesManager).remove(AuthHelper.VALID_NUMBER);
verify(messagesManager).clear(eq(AuthHelper.VALID_NUMBER), eq(42L)); verify(messagesManager).clear(eq(AuthHelper.VALID_NUMBER), eq(AuthHelper.VALID_UUID), eq(42L));
} }
@Test @Test

View File

@ -257,7 +257,7 @@ public class MessageControllerTest {
OutgoingMessageEntityList messagesList = new OutgoingMessageEntityList(messages, false); OutgoingMessageEntityList messagesList = new OutgoingMessageEntityList(messages, false);
when(messagesManager.getMessagesForDevice(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(messagesList); when(messagesManager.getMessagesForDevice(eq(AuthHelper.VALID_NUMBER), eq(AuthHelper.VALID_UUID), eq(1L))).thenReturn(messagesList);
OutgoingMessageEntityList response = OutgoingMessageEntityList response =
resources.getJerseyTest().target("/v1/messages/") resources.getJerseyTest().target("/v1/messages/")
@ -294,7 +294,7 @@ public class MessageControllerTest {
OutgoingMessageEntityList messagesList = new OutgoingMessageEntityList(messages, false); OutgoingMessageEntityList messagesList = new OutgoingMessageEntityList(messages, false);
when(messagesManager.getMessagesForDevice(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(messagesList); when(messagesManager.getMessagesForDevice(eq(AuthHelper.VALID_NUMBER), eq(AuthHelper.VALID_UUID), eq(1L))).thenReturn(messagesList);
Response response = Response response =
resources.getJerseyTest().target("/v1/messages/") resources.getJerseyTest().target("/v1/messages/")
@ -312,20 +312,20 @@ public class MessageControllerTest {
UUID sourceUuid = UUID.randomUUID(); UUID sourceUuid = UUID.randomUUID();
when(messagesManager.delete(AuthHelper.VALID_NUMBER, 1, "+14152222222", 31337)) when(messagesManager.delete(AuthHelper.VALID_NUMBER, AuthHelper.VALID_UUID, 1, "+14152222222", 31337))
.thenReturn(Optional.of(new OutgoingMessageEntity(31337L, true, null, .thenReturn(Optional.of(new OutgoingMessageEntity(31337L, true, null,
Envelope.Type.CIPHERTEXT_VALUE, Envelope.Type.CIPHERTEXT_VALUE,
null, timestamp, null, timestamp,
"+14152222222", sourceUuid, 1, "hi".getBytes(), null, 0))); "+14152222222", sourceUuid, 1, "hi".getBytes(), null, 0)));
when(messagesManager.delete(AuthHelper.VALID_NUMBER, 1, "+14152222222", 31338)) when(messagesManager.delete(AuthHelper.VALID_NUMBER, AuthHelper.VALID_UUID, 1, "+14152222222", 31338))
.thenReturn(Optional.of(new OutgoingMessageEntity(31337L, true, null, .thenReturn(Optional.of(new OutgoingMessageEntity(31337L, true, null,
Envelope.Type.RECEIPT_VALUE, Envelope.Type.RECEIPT_VALUE,
null, System.currentTimeMillis(), null, System.currentTimeMillis(),
"+14152222222", sourceUuid, 1, null, null, 0))); "+14152222222", sourceUuid, 1, null, null, 0)));
when(messagesManager.delete(AuthHelper.VALID_NUMBER, 1, "+14152222222", 31339)) when(messagesManager.delete(AuthHelper.VALID_NUMBER, AuthHelper.VALID_UUID, 1, "+14152222222", 31339))
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
Response response = resources.getJerseyTest() Response response = resources.getJerseyTest()

View File

@ -105,6 +105,7 @@ public class WebSocketConnectionTest {
public void testOpen() throws Exception { public void testOpen() throws Exception {
MessagesManager storedMessages = mock(MessagesManager.class); MessagesManager storedMessages = mock(MessagesManager.class);
UUID accountUuid = UUID.randomUUID();
UUID senderOneUuid = UUID.randomUUID(); UUID senderOneUuid = UUID.randomUUID();
UUID senderTwoUuid = UUID.randomUUID(); UUID senderTwoUuid = UUID.randomUUID();
@ -121,6 +122,7 @@ public class WebSocketConnectionTest {
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device)); when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));
when(account.getNumber()).thenReturn("+14152222222"); when(account.getNumber()).thenReturn("+14152222222");
when(account.getUuid()).thenReturn(accountUuid);
final Device sender1device = mock(Device.class); final Device sender1device = mock(Device.class);
@ -134,7 +136,7 @@ public class WebSocketConnectionTest {
when(accountsManager.get("sender1")).thenReturn(Optional.of(sender1)); when(accountsManager.get("sender1")).thenReturn(Optional.of(sender1));
when(accountsManager.get("sender2")).thenReturn(Optional.empty()); when(accountsManager.get("sender2")).thenReturn(Optional.empty());
when(storedMessages.getMessagesForDevice(account.getNumber(), device.getId())) when(storedMessages.getMessagesForDevice(account.getNumber(), account.getUuid(), device.getId()))
.thenReturn(outgoingMessagesList); .thenReturn(outgoingMessagesList);
final List<CompletableFuture<WebSocketResponseMessage>> futures = new LinkedList<>(); final List<CompletableFuture<WebSocketResponseMessage>> futures = new LinkedList<>();
@ -166,7 +168,7 @@ public class WebSocketConnectionTest {
futures.get(0).completeExceptionally(new IOException()); futures.get(0).completeExceptionally(new IOException());
futures.get(2).completeExceptionally(new IOException()); futures.get(2).completeExceptionally(new IOException());
verify(storedMessages, times(1)).delete(eq(account.getNumber()), eq(2L), eq(2L), eq(false)); verify(storedMessages, times(1)).delete(eq(account.getNumber()), eq(accountUuid), eq(2L), eq(2L), eq(false));
verify(receiptSender, times(1)).sendReceipt(eq(account), eq("sender1"), eq(2222L)); verify(receiptSender, times(1)).sendReceipt(eq(account), eq("sender1"), eq(2222L));
connection.onDispatchUnsubscribed(websocketAddress.serialize()); connection.onDispatchUnsubscribed(websocketAddress.serialize());
@ -204,6 +206,7 @@ public class WebSocketConnectionTest {
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device)); when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));
when(account.getNumber()).thenReturn("+14152222222"); when(account.getNumber()).thenReturn("+14152222222");
when(account.getUuid()).thenReturn(UUID.randomUUID());
final Device sender1device = mock(Device.class); final Device sender1device = mock(Device.class);
@ -217,7 +220,7 @@ public class WebSocketConnectionTest {
when(accountsManager.get("sender1")).thenReturn(Optional.of(sender1)); when(accountsManager.get("sender1")).thenReturn(Optional.of(sender1));
when(accountsManager.get("sender2")).thenReturn(Optional.<Account>empty()); when(accountsManager.get("sender2")).thenReturn(Optional.<Account>empty());
when(storedMessages.getMessagesForDevice(account.getNumber(), device.getId())) when(storedMessages.getMessagesForDevice(account.getNumber(), account.getUuid(), device.getId()))
.thenReturn(pendingMessagesList); .thenReturn(pendingMessagesList);
final List<CompletableFuture<WebSocketResponseMessage>> futures = new LinkedList<>(); final List<CompletableFuture<WebSocketResponseMessage>> futures = new LinkedList<>();
@ -311,6 +314,7 @@ public class WebSocketConnectionTest {
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device)); when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));
when(account.getNumber()).thenReturn("+14152222222"); when(account.getNumber()).thenReturn("+14152222222");
when(account.getUuid()).thenReturn(UUID.randomUUID());
final Device sender1device = mock(Device.class); final Device sender1device = mock(Device.class);
@ -324,7 +328,7 @@ public class WebSocketConnectionTest {
when(accountsManager.get("sender1")).thenReturn(Optional.of(sender1)); when(accountsManager.get("sender1")).thenReturn(Optional.of(sender1));
when(accountsManager.get("sender2")).thenReturn(Optional.<Account>empty()); when(accountsManager.get("sender2")).thenReturn(Optional.<Account>empty());
when(storedMessages.getMessagesForDevice(account.getNumber(), device.getId())) when(storedMessages.getMessagesForDevice(account.getNumber(), account.getUuid(), device.getId()))
.thenReturn(pendingMessagesList); .thenReturn(pendingMessagesList);
final List<CompletableFuture<WebSocketResponseMessage>> futures = new LinkedList<>(); final List<CompletableFuture<WebSocketResponseMessage>> futures = new LinkedList<>();