From 25c40ea3cff044d21b2fb6db9b8ff0c58b1003be Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 22 Sep 2017 16:40:44 -0400 Subject: [PATCH 1/3] Handle new-style delivery receipts. // FREEBIE --- .../Messages/Interactions/TSOutgoingMessage.h | 1 - .../Messages/Interactions/TSOutgoingMessage.m | 7 -- .../src/Messages/OWSMessageManager.m | 69 +++++++++++++------ .../src/Messages/OWSReadReceiptManager.h | 7 +- .../src/Messages/OWSReadReceiptManager.m | 20 ++---- 5 files changed, 59 insertions(+), 45 deletions(-) diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h index ab1e9c157e..7bc0c4ac36 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h @@ -172,7 +172,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { - (void)updateWithCustomMessage:(NSString *)customMessage transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateWithCustomMessage:(NSString *)customMessage; - (void)updateWithWasDeliveredWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; -- (void)updateWithWasDelivered; - (void)updateWithWasSentFromLinkedDeviceWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateWithSingleGroupRecipient:(NSString *)singleGroupRecipient transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 8b686304a7..bbf7b5e929 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -317,13 +317,6 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec }]; } -- (void)updateWithWasDelivered -{ - [self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self updateWithWasDeliveredWithTransaction:transaction]; - }]; -} - - (void)updateWithWasSentFromLinkedDeviceWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(transaction); diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 90d7539f0b..5669166023 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -186,23 +186,40 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(envelope); OWSAssert(transaction); - NSArray *messages - = (NSArray *)[TSInteraction interactionsWithTimestamp:envelope.timestamp - ofClass:[TSOutgoingMessage class] - withTransaction:transaction]; - if (messages.count < 1) { - // Desktop currently sends delivery receipts for "unpersisted" messages - // like group updates, so these errors are expected to a certain extent. - DDLogInfo(@"%@ Missing message for delivery receipt: %llu", self.tag, envelope.timestamp); - } else { - if (messages.count > 1) { - DDLogInfo(@"%@ More than one message (%zd) for delivery receipt: %llu", - self.tag, - messages.count, - envelope.timestamp); - } - for (TSOutgoingMessage *outgoingMessage in messages) { - [outgoingMessage updateWithWasDeliveredWithTransaction:transaction]; + [self processDeliveryReceipts:envelope.source + sentTimestamps:@[ + @(envelope.timestamp), + ] + transaction:transaction]; +} + +- (void)processDeliveryReceipts:(NSString *)recipientId + sentTimestamps:(NSArray *)sentTimestamps + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(recipientId); + OWSAssert(sentTimestamps); + OWSAssert(transaction); + + for (NSNumber *nsTimestamp in sentTimestamps) { + uint64_t timestamp = [nsTimestamp unsignedLongLongValue]; + + NSArray *messages + = (NSArray *)[TSInteraction interactionsWithTimestamp:timestamp + ofClass:[TSOutgoingMessage class] + withTransaction:transaction]; + if (messages.count < 1) { + // Desktop currently sends delivery receipts for "unpersisted" messages + // like group updates, so these errors are expected to a certain extent. + DDLogInfo(@"%@ Missing message for delivery receipt: %llu", self.tag, timestamp); + } else { + if (messages.count > 1) { + DDLogInfo( + @"%@ More than one message (%zd) for delivery receipt: %llu", self.tag, messages.count, timestamp); + } + for (TSOutgoingMessage *outgoingMessage in messages) { + [outgoingMessage updateWithWasDeliveredWithTransaction:transaction]; + } } } } @@ -243,7 +260,7 @@ NS_ASSUME_NONNULL_BEGIN } else if (content.hasNullMessage) { DDLogInfo(@"%@ Received null message.", self.tag); } else if (content.hasReceiptMessage) { - [self handleIncomingEnvelope:envelope withReceiptMessage:content.receiptMessage]; + [self handleIncomingEnvelope:envelope withReceiptMessage:content.receiptMessage transaction:transaction]; } else { DDLogWarn(@"%@ Ignoring envelope. Content with no known payload", self.tag); } @@ -340,17 +357,29 @@ NS_ASSUME_NONNULL_BEGIN - (void)handleIncomingEnvelope:(OWSSignalServiceProtosEnvelope *)envelope withReceiptMessage:(OWSSignalServiceProtosReceiptMessage *)receiptMessage + transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(envelope); OWSAssert(receiptMessage); + OWSAssert(transaction); + + PBArray *messageTimestamps = receiptMessage.timestamp; + NSMutableArray *sentTimestamps = [NSMutableArray new]; + for (int i = 0; i < messageTimestamps.count; i++) { + UInt64 timestamp = [messageTimestamps uint64AtIndex:i]; + [sentTimestamps addObject:@(timestamp)]; + } switch (receiptMessage.type) { case OWSSignalServiceProtosReceiptMessageTypeDelivery: - DDLogInfo(@"%@ Ignoring receipt message with delivery receipt.", self.tag); + DDLogVerbose(@"%@ Processing receipt message with delivery receipts.", self.tag); + [self processDeliveryReceipts:envelope.source sentTimestamps:sentTimestamps transaction:transaction]; return; case OWSSignalServiceProtosReceiptMessageTypeRead: DDLogVerbose(@"%@ Processing receipt message with read receipts.", self.tag); - [OWSReadReceiptManager.sharedManager processReadReceiptsFromRecipient:receiptMessage envelope:envelope]; + [OWSReadReceiptManager.sharedManager processReadReceiptsFromRecipientId:envelope.source + sentTimestamps:sentTimestamps + readTimestamp:envelope.timestamp]; break; default: DDLogInfo(@"%@ Ignoring receipt message of unknown type: %d.", self.tag, (int)receiptMessage.type); diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.h b/SignalServiceKit/src/Messages/OWSReadReceiptManager.h index ad925c6f15..45bc80291b 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.h +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.h @@ -4,8 +4,6 @@ NS_ASSUME_NONNULL_BEGIN -@class OWSSignalServiceProtosEnvelope; -@class OWSSignalServiceProtosReceiptMessage; @class OWSSignalServiceProtosSyncMessageRead; @class TSIncomingMessage; @class TSOutgoingMessage; @@ -41,8 +39,9 @@ extern NSString *const kIncomingMessageMarkedAsReadNotification; // from a user to whom we have sent a message. // // This method can be called from any thread. -- (void)processReadReceiptsFromRecipient:(OWSSignalServiceProtosReceiptMessage *)receiptMessage - envelope:(OWSSignalServiceProtosEnvelope *)envelope; +- (void)processReadReceiptsFromRecipientId:(NSString *)recipientId + sentTimestamps:(NSArray *)sentTimestamps + readTimestamp:(uint64_t)readTimestamp; - (void)applyEarlyReadReceiptsForOutgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m index bdabd2eacf..f25576b46e 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m @@ -340,28 +340,22 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE #pragma mark - Read Receipts From Recipient -- (void)processReadReceiptsFromRecipient:(OWSSignalServiceProtosReceiptMessage *)receiptMessage - envelope:(OWSSignalServiceProtosEnvelope *)envelope +- (void)processReadReceiptsFromRecipientId:(NSString *)recipientId + sentTimestamps:(NSArray *)sentTimestamps + readTimestamp:(uint64_t)readTimestamp { - OWSAssert(receiptMessage); - OWSAssert(envelope); - OWSAssert(receiptMessage.type == OWSSignalServiceProtosReceiptMessageTypeRead); + OWSAssert(recipientId.length > 0); + OWSAssert(sentTimestamps); if (![self areReadReceiptsEnabled]) { DDLogInfo(@"%@ Ignoring incoming receipt message as read receipts are disabled.", self.tag); return; } - NSString *recipientId = envelope.source; - OWSAssert(recipientId.length > 0); - - PBArray *sentTimestamps = receiptMessage.timestamp; - UInt64 readTimestamp = envelope.timestamp; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (int i = 0; i < sentTimestamps.count; i++) { - UInt64 sentTimestamp = [sentTimestamps uint64AtIndex:i]; + for (NSNumber *nsSentTimestamp in sentTimestamps) { + UInt64 sentTimestamp = [nsSentTimestamp unsignedLongLongValue]; NSArray *messages = (NSArray *)[TSInteraction interactionsWithTimestamp:sentTimestamp From aa7329013d3abbb280905f6bda423491e988ad95 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 22 Sep 2017 17:23:09 -0400 Subject: [PATCH 2/3] Handle new-style delivery receipts. // FREEBIE --- .../MessageMetadataViewController.swift | 11 +++++++++-- .../translations/en.lproj/Localizable.strings | 3 +++ .../Messages/Interactions/TSOutgoingMessage.h | 8 +++++++- .../Messages/Interactions/TSOutgoingMessage.m | 17 ++++++++++++++++- .../src/Messages/OWSMessageManager.m | 13 +++++++++++-- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Signal/src/ViewControllers/MessageMetadataViewController.swift b/Signal/src/ViewControllers/MessageMetadataViewController.swift index cd1c4844d1..326ca2004f 100644 --- a/Signal/src/ViewControllers/MessageMetadataViewController.swift +++ b/Signal/src/ViewControllers/MessageMetadataViewController.swift @@ -293,8 +293,15 @@ class MessageMetadataViewController: OWSViewController { MessageMetadataViewController.dateFormatter.string(from:readDate)) } - // TODO: We don't currently track delivery state on a per-recipient basis. - // We should. NOTE: This work is in PR. + let recipientDeliveryMap = message.recipientDeliveryMap + if let deliveryTimestamp = recipientDeliveryMap[recipientId] { + assert(message.messageState == .sentToService) + let deliveryDate = NSDate.ows_date(withMillisecondsSince1970:deliveryTimestamp.uint64Value) + return String(format:NSLocalizedString("MESSAGE_STATUS_DELIVERED_WITH_TIMESTAMP_FORMAT", + comment: "message status for messages delivered to the recipient. Embeds: {{the date and time the message was delivered}}."), + dateFormatter.string(from:deliveryDate)) + } + if message.wasDelivered { return NSLocalizedString("MESSAGE_STATUS_DELIVERED", comment:"message status for message delivered to their recipient.") diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 349079db77..d9043c9c10 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -833,6 +833,9 @@ message status for message delivered to their recipient. */ "MESSAGE_STATUS_DELIVERED" = "Delivered"; +/* message status for messages delivered to the recipient. Embeds: {{the date and time the message was delivered}}. */ +"MESSAGE_STATUS_DELIVERED_WITH_TIMESTAMP_FORMAT" = "Delivered %@"; + /* message footer for failed messages */ "MESSAGE_STATUS_FAILED" = "Sending failed. Tap for info."; diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h index 7bc0c4ac36..e39dd5131e 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h @@ -104,6 +104,9 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { // This property won't be accurate for legacy messages. @property (atomic, readonly) BOOL isFromLinkedDevice; +// Map of "recipient id"-to-"delivery time" of the recipients who have received the message. +@property (atomic, readonly) NSDictionary *recipientDeliveryMap; + // Map of "recipient id"-to-"read time" of the recipients who have read the message. @property (atomic, readonly) NSDictionary *recipientReadMap; @@ -171,7 +174,10 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { - (void)updateWithHasSyncedTranscript:(BOOL)hasSyncedTranscript; - (void)updateWithCustomMessage:(NSString *)customMessage transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateWithCustomMessage:(NSString *)customMessage; -- (void)updateWithWasDeliveredWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; +// deliveryTimestamp is an optional parameter. +- (void)updateWithDeliveredToRecipientId:(NSString *)recipientId + deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp + transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateWithWasSentFromLinkedDeviceWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateWithSingleGroupRecipient:(NSString *)singleGroupRecipient transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index bbf7b5e929..86ff9d82f1 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -38,6 +38,8 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec @property (atomic) TSGroupMetaMessage groupMetaMessage; +@property (atomic) NSDictionary *recipientDeliveryMap; + @property (atomic) NSDictionary *recipientReadMap; @end @@ -307,12 +309,25 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec }]; } -- (void)updateWithWasDeliveredWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +- (void)updateWithDeliveredToRecipientId:(NSString *)recipientId + deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp + transaction:(YapDatabaseReadWriteTransaction *)transaction { + OWSAssert(recipientId.length > 0); OWSAssert(transaction); [self applyChangeToSelfAndLatestOutgoingMessage:transaction changeBlock:^(TSOutgoingMessage *message) { + + if (deliveryTimestamp) { + NSMutableDictionary *recipientDeliveryMap + = (message.recipientDeliveryMap + ? [message.recipientDeliveryMap mutableCopy] + : [NSMutableDictionary new]); + recipientDeliveryMap[recipientId] = deliveryTimestamp; + message.recipientDeliveryMap = recipientDeliveryMap; + } + [message setWasDelivered:YES]; }]; } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 5669166023..a2e64fe6c8 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -186,15 +186,19 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(envelope); OWSAssert(transaction); + // Old-style delivery notices don't include a "delivery timestamp". [self processDeliveryReceipts:envelope.source sentTimestamps:@[ @(envelope.timestamp), ] + deliveryTimestamp:nil transaction:transaction]; } +// deliveryTimestamp is an optional parameter. - (void)processDeliveryReceipts:(NSString *)recipientId sentTimestamps:(NSArray *)sentTimestamps + deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(recipientId); @@ -218,7 +222,9 @@ NS_ASSUME_NONNULL_BEGIN @"%@ More than one message (%zd) for delivery receipt: %llu", self.tag, messages.count, timestamp); } for (TSOutgoingMessage *outgoingMessage in messages) { - [outgoingMessage updateWithWasDeliveredWithTransaction:transaction]; + [outgoingMessage updateWithDeliveredToRecipientId:recipientId + deliveryTimestamp:deliveryTimestamp + transaction:transaction]; } } } @@ -373,7 +379,10 @@ NS_ASSUME_NONNULL_BEGIN switch (receiptMessage.type) { case OWSSignalServiceProtosReceiptMessageTypeDelivery: DDLogVerbose(@"%@ Processing receipt message with delivery receipts.", self.tag); - [self processDeliveryReceipts:envelope.source sentTimestamps:sentTimestamps transaction:transaction]; + [self processDeliveryReceipts:envelope.source + sentTimestamps:sentTimestamps + deliveryTimestamp:@(envelope.timestamp) + transaction:transaction]; return; case OWSSignalServiceProtosReceiptMessageTypeRead: DDLogVerbose(@"%@ Processing receipt message with read receipts.", self.tag); From a4d285f50deb38ebb849f8d9e6ed7b298259854e Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 27 Sep 2017 14:19:26 -0400 Subject: [PATCH 3/3] Respond to CR. // FREEBIE --- .../MessageMetadataViewController.swift | 2 +- .../Messages/Interactions/TSOutgoingMessage.h | 5 ++- .../Messages/Interactions/TSOutgoingMessage.m | 4 +- .../src/Messages/OWSMessageManager.m | 37 +++++++++++-------- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Signal/src/ViewControllers/MessageMetadataViewController.swift b/Signal/src/ViewControllers/MessageMetadataViewController.swift index 326ca2004f..bb0abeb70b 100644 --- a/Signal/src/ViewControllers/MessageMetadataViewController.swift +++ b/Signal/src/ViewControllers/MessageMetadataViewController.swift @@ -299,7 +299,7 @@ class MessageMetadataViewController: OWSViewController { let deliveryDate = NSDate.ows_date(withMillisecondsSince1970:deliveryTimestamp.uint64Value) return String(format:NSLocalizedString("MESSAGE_STATUS_DELIVERED_WITH_TIMESTAMP_FORMAT", comment: "message status for messages delivered to the recipient. Embeds: {{the date and time the message was delivered}}."), - dateFormatter.string(from:deliveryDate)) + MessageMetadataViewController.dateFormatter.string(from:deliveryDate)) } if message.wasDelivered { diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h index e39dd5131e..a1835a5e57 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h @@ -174,7 +174,10 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { - (void)updateWithHasSyncedTranscript:(BOOL)hasSyncedTranscript; - (void)updateWithCustomMessage:(NSString *)customMessage transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateWithCustomMessage:(NSString *)customMessage; -// deliveryTimestamp is an optional parameter. +// deliveryTimestamp is an optional parameter, since legacy +// delivery receipts don't have a "delivery timestamp". Those +// messages repurpose the "timestamp" field to indicate when the +// corresponding message was originally sent. - (void)updateWithDeliveredToRecipientId:(NSString *)recipientId deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 86ff9d82f1..bfcdf9d90b 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -325,7 +325,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec ? [message.recipientDeliveryMap mutableCopy] : [NSMutableDictionary new]); recipientDeliveryMap[recipientId] = deliveryTimestamp; - message.recipientDeliveryMap = recipientDeliveryMap; + message.recipientDeliveryMap = [recipientDeliveryMap copy]; } [message setWasDelivered:YES]; @@ -431,7 +431,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec = (message.recipientReadMap ? [message.recipientReadMap mutableCopy] : [NSMutableDictionary new]); recipientReadMap[recipientId] = @(readTimestamp); - message.recipientReadMap = recipientReadMap; + message.recipientReadMap = [recipientReadMap copy]; }]; } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index a2e64fe6c8..d1d32d5fa2 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -187,19 +187,22 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(transaction); // Old-style delivery notices don't include a "delivery timestamp". - [self processDeliveryReceipts:envelope.source - sentTimestamps:@[ - @(envelope.timestamp), - ] - deliveryTimestamp:nil - transaction:transaction]; + [self processDeliveryReceiptsFromRecipientId:envelope.source + sentTimestamps:@[ + @(envelope.timestamp), + ] + deliveryTimestamp:nil + transaction:transaction]; } -// deliveryTimestamp is an optional parameter. -- (void)processDeliveryReceipts:(NSString *)recipientId - sentTimestamps:(NSArray *)sentTimestamps - deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp - transaction:(YapDatabaseReadWriteTransaction *)transaction +// deliveryTimestamp is an optional parameter, since legacy +// delivery receipts don't have a "delivery timestamp". Those +// messages repurpose the "timestamp" field to indicate when the +// corresponding message was originally sent. +- (void)processDeliveryReceiptsFromRecipientId:(NSString *)recipientId + sentTimestamps:(NSArray *)sentTimestamps + deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp + transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(recipientId); OWSAssert(sentTimestamps); @@ -213,8 +216,10 @@ NS_ASSUME_NONNULL_BEGIN ofClass:[TSOutgoingMessage class] withTransaction:transaction]; if (messages.count < 1) { - // Desktop currently sends delivery receipts for "unpersisted" messages + // The service sends delivery receipts for "unpersisted" messages // like group updates, so these errors are expected to a certain extent. + // + // TODO: persist "early" delivery receipts. DDLogInfo(@"%@ Missing message for delivery receipt: %llu", self.tag, timestamp); } else { if (messages.count > 1) { @@ -379,10 +384,10 @@ NS_ASSUME_NONNULL_BEGIN switch (receiptMessage.type) { case OWSSignalServiceProtosReceiptMessageTypeDelivery: DDLogVerbose(@"%@ Processing receipt message with delivery receipts.", self.tag); - [self processDeliveryReceipts:envelope.source - sentTimestamps:sentTimestamps - deliveryTimestamp:@(envelope.timestamp) - transaction:transaction]; + [self processDeliveryReceiptsFromRecipientId:envelope.source + sentTimestamps:sentTimestamps + deliveryTimestamp:@(envelope.timestamp) + transaction:transaction]; return; case OWSSignalServiceProtosReceiptMessageTypeRead: DDLogVerbose(@"%@ Processing receipt message with read receipts.", self.tag);