diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReceiptSender.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReceiptSender.kt new file mode 100644 index 0000000000..971213ea6e --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReceiptSender.kt @@ -0,0 +1,45 @@ +package org.thoughtcrime.securesms.jobs + +import org.signal.core.util.logging.Log +import org.thoughtcrime.securesms.dependencies.AppDependencies +import org.thoughtcrime.securesms.recipients.RecipientId +import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException +import org.whispersystems.signalservice.api.messages.SendMessageResult +import java.io.IOException + +/** + * Shared send logic for the receipt jobs ([SendReadReceiptJob], [SendDeliveryReceiptJob], [SendViewedReceiptJob]) that + * will repair on first failure and then try again. + */ +object ReceiptSender { + + private val TAG = Log.tag(ReceiptSender::class.java) + + /** + * @return the result of the send, or `null` if the receipt was dropped because the session could not be repaired. + */ + @JvmStatic + @Throws(IOException::class, UntrustedIdentityException::class) + fun sendWithSessionRepair(recipientId: RecipientId, operation: ReceiptSendOperation): SendMessageResult? { + return try { + operation.send() + } catch (e: IllegalStateException) { + Log.w(TAG, "Failed to send receipt, likely due to a missing or corrupt session. Archiving sessions and retrying.", e) + + AppDependencies.protocolStore.aci().sessions().archiveSessions(recipientId) + AppDependencies.protocolStore.pni().sessions().archiveSessions(recipientId) + + try { + operation.send() + } catch (retryError: IllegalStateException) { + Log.w(TAG, "Failed to send receipt even after archiving sessions. Dropping.", retryError) + null + } + } + } + + fun interface ReceiptSendOperation { + @Throws(IOException::class, UntrustedIdentityException::class) + fun send(): SendMessageResult + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/SendDeliveryReceiptJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/SendDeliveryReceiptJob.java index dafad79e04..32521be90d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/SendDeliveryReceiptJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/SendDeliveryReceiptJob.java @@ -125,12 +125,12 @@ public class SendDeliveryReceiptJob extends BaseJob { Collections.singletonList(messageSentTimestamp), timestamp); - SendMessageResult result = messageSender.sendReceipt(remoteAddress, - SealedSenderAccessUtil.getSealedSenderAccessFor(recipient, this::getGroupSendFullToken), - receiptMessage, - recipient.getNeedsPniSignature()); + SendMessageResult result = ReceiptSender.sendWithSessionRepair(recipientId, () -> messageSender.sendReceipt(remoteAddress, + SealedSenderAccessUtil.getSealedSenderAccessFor(recipient, this::getGroupSendFullToken), + receiptMessage, + recipient.getNeedsPniSignature())); - if (messageId != null) { + if (result != null && messageId != null) { SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageId, false); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java index e2c541eeff..2869b97fef 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java @@ -191,13 +191,13 @@ public class SendReadReceiptJob extends BaseJob { SignalServiceAddress remoteAddress = RecipientUtil.toSignalServiceAddress(context, recipient); SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ, messageSentTimestamps, timestamp); - SendMessageResult result = messageSender.sendReceipt(remoteAddress, - SealedSenderAccessUtil.getSealedSenderAccessFor(recipient, - () -> SignalDatabase.groups().getGroupSendFullToken(threadId, recipientId)), - receiptMessage, - recipient.getNeedsPniSignature()); + SendMessageResult result = ReceiptSender.sendWithSessionRepair(recipientId, () -> messageSender.sendReceipt(remoteAddress, + SealedSenderAccessUtil.getSealedSenderAccessFor(recipient, + () -> SignalDatabase.groups().getGroupSendFullToken(threadId, recipientId)), + receiptMessage, + recipient.getNeedsPniSignature())); - if (Util.hasItems(messageIds)) { + if (result != null && Util.hasItems(messageIds)) { SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageIds, false); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/SendViewedReceiptJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/SendViewedReceiptJob.java index 431a77b606..f84f3652d9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/SendViewedReceiptJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/SendViewedReceiptJob.java @@ -209,13 +209,13 @@ public class SendViewedReceiptJob extends BaseJob { messageSentTimestamps, timestamp); - SendMessageResult result = messageSender.sendReceipt(remoteAddress, - SealedSenderAccessUtil.getSealedSenderAccessFor(recipient, - () -> SignalDatabase.groups().getGroupSendFullToken(threadId, recipientId)), - receiptMessage, - recipient.getNeedsPniSignature()); + SendMessageResult result = ReceiptSender.sendWithSessionRepair(recipientId, () -> messageSender.sendReceipt(remoteAddress, + SealedSenderAccessUtil.getSealedSenderAccessFor(recipient, + () -> SignalDatabase.groups().getGroupSendFullToken(threadId, recipientId)), + receiptMessage, + recipient.getNeedsPniSignature())); - if (Util.hasItems(foundMessageIds)) { + if (result != null && Util.hasItems(foundMessageIds)) { SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, foundMessageIds, false); } }