diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 5679db64f..a9d084d1c 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -208,6 +208,7 @@ import org.whispersystems.textsecuregcm.s3.S3MonitoringSupplier; import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient; import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecoveryClient; import org.whispersystems.textsecuregcm.spam.ChallengeConstraintChecker; +import org.whispersystems.textsecuregcm.spam.MessageDeliveryListener; import org.whispersystems.textsecuregcm.spam.RegistrationFraudChecker; import org.whispersystems.textsecuregcm.spam.RegistrationRecoveryChecker; import org.whispersystems.textsecuregcm.spam.SpamChecker; @@ -1038,6 +1039,7 @@ public class WhisperServerService extends Application messageDeliveryListeners = new ArrayList<>(); + // Note that these names deliberately reference `MessageController` for metric continuity private static final String REJECT_OVERSIZE_MESSAGE_COUNTER_NAME = name(MessageSender.class, "rejectOversizeMessage"); private static final String OVERSIZE_MESSAGE_WARNING_COUNTER_NAME = name(MessageSender.class, "oversizeMessageWarning"); @@ -80,6 +85,10 @@ public class MessageSender { this.pushNotificationManager = pushNotificationManager; } + public void addMessageDeliveryListener(final MessageDeliveryListener messageDeliveryListener) { + messageDeliveryListeners.add(messageDeliveryListener); + } + /** * Sends messages to devices associated with the given destination account. If a destination device has a valid push * notification token and does not have an active connection to a Signal server, then this method will also send a @@ -136,6 +145,16 @@ public class MessageSender { .and(platformTag); Metrics.counter(SEND_COUNTER_NAME, tags).increment(); + + messageDeliveryListeners.forEach(messageDeliveryListener -> + messageDeliveryListener.handleMessageDelivered(destination, + deviceId, + message.getEphemeral(), + message.getUrgent(), + message.getStory(), + !message.hasSourceServiceId(), + false, + syncMessageSenderDeviceId.isPresent())); }); } @@ -223,6 +242,16 @@ public class MessageSender { .and(platformTag); Metrics.counter(SEND_COUNTER_NAME, tags).increment(); + + messageDeliveryListeners.forEach(messageDeliveryListener -> + messageDeliveryListener.handleMessageDelivered(account, + deviceId, + isEphemeral, + isUrgent, + isStory, + true, + true, + false)); }))) .thenRun(Util.NOOP); } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/push/MessageSenderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/push/MessageSenderTest.java index fefa12981..cf7519214 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/push/MessageSenderTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/push/MessageSenderTest.java @@ -14,6 +14,7 @@ import static org.mockito.ArgumentMatchers.anyByte; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @@ -47,6 +48,7 @@ import org.whispersystems.textsecuregcm.identity.IdentityType; import org.whispersystems.textsecuregcm.identity.PniServiceIdentifier; import org.whispersystems.textsecuregcm.identity.ServiceIdentifier; import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil; +import org.whispersystems.textsecuregcm.spam.MessageDeliveryListener; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.MessagesManager; @@ -58,14 +60,18 @@ class MessageSenderTest { private MessagesManager messagesManager; private PushNotificationManager pushNotificationManager; + private MessageDeliveryListener messageDeliveryListener; + private MessageSender messageSender; @BeforeEach void setUp() { messagesManager = mock(MessagesManager.class); pushNotificationManager = mock(PushNotificationManager.class); + messageDeliveryListener = mock(MessageDeliveryListener.class); messageSender = new MessageSender(messagesManager, pushNotificationManager); + messageSender.addMessageDeliveryListener(messageDeliveryListener); } @@ -124,6 +130,15 @@ class MessageSenderTest { } else { verifyNoInteractions(pushNotificationManager); } + + verify(messageDeliveryListener).handleMessageDelivered(account, + deviceId, + ephemeral, + urgent, + false, + true, + false, + false); } @Test @@ -156,6 +171,15 @@ class MessageSenderTest { assertEquals(new MismatchedDevices(Collections.emptySet(), Collections.emptySet(), Set.of(deviceId)), mismatchedDevicesException.getMismatchedDevices()); + + verify(messageDeliveryListener, never()).handleMessageDelivered(any(), + anyByte(), + anyBoolean(), + anyBoolean(), + anyBoolean(), + anyBoolean(), + anyBoolean(), + anyBoolean()); } @CartesianTest @@ -215,6 +239,15 @@ class MessageSenderTest { } else { verifyNoInteractions(pushNotificationManager); } + + verify(messageDeliveryListener).handleMessageDelivered(account, + deviceId, + ephemeral, + urgent, + false, + true, + true, + false); } @Test @@ -259,6 +292,15 @@ class MessageSenderTest { assertEquals(Map.of(serviceIdentifier, new MismatchedDevices(Collections.emptySet(), Collections.emptySet(), Set.of(deviceId))), mismatchedDevicesException.getMismatchedDevicesByServiceIdentifier()); + + verify(messageDeliveryListener, never()).handleMessageDelivered(any(), + anyByte(), + anyBoolean(), + anyBoolean(), + anyBoolean(), + anyBoolean(), + anyBoolean(), + anyBoolean()); } @ParameterizedTest