Respond to CR.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-09-22 15:15:04 -04:00
parent 825503210b
commit b74da07f7e
9 changed files with 121 additions and 73 deletions

View File

@ -3,7 +3,7 @@
//
#import "OWSReadReceiptsForSenderMessage.h"
#import "NSDate+millisecondTimeStamp.h"
#import "NSDate+OWS.h"
#import "OWSReadReceipt.h"
#import "OWSSignalServiceProtos.pb.h"
#import "SignalRecipient.h"
@ -56,8 +56,6 @@ NS_ASSUME_NONNULL_BEGIN
[builder addTimestamp:[messageTimestamp unsignedLongLongValue]];
}
// TODO: addLocalProfileKeyIfNecessary.
return [builder build];
}

View File

@ -104,17 +104,16 @@ NS_ASSUME_NONNULL_BEGIN
}
if (outgoingMessage.body.length < 1 && outgoingMessage.attachmentIds.count < 1) {
// TODO: Is this safe?
DDLogInfo(@"Ignoring message transcript for empty message.");
OWSFail(@"Ignoring message transcript for empty message.");
return;
}
// TODO: Refactor this logic.
// TODO: Refactor this logic. Most of it doesn't belong in `OWSMessageSender`.
[self.messageSender handleMessageSentRemotely:outgoingMessage
sentAt:transcript.expirationStartedAt
transaction:transaction];
[self.readReceiptManager outgoingMessageFromLinkedDevice:outgoingMessage transaction:transaction];
[self.readReceiptManager updateOutgoingMessageFromLinkedDevice:outgoingMessage transaction:transaction];
[attachmentsProcessor
fetchAttachmentsForMessage:outgoingMessage

View File

@ -26,8 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark Utility Method
+ (instancetype)interactionForTimestamp:(uint64_t)timestamp
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
ofClass:(Class)clazz
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;

View File

@ -12,28 +12,6 @@ NS_ASSUME_NONNULL_BEGIN
@implementation TSInteraction
+ (instancetype)interactionForTimestamp:(uint64_t)timestamp
withTransaction:(YapDatabaseReadWriteTransaction *)transaction {
OWSAssert(timestamp > 0);
// Accept any interaction.
NSArray<TSInteraction *> *interactions = [self interactionsWithTimestamp:timestamp
withFilter:^(TSInteraction *interaction) {
return YES;
}
withTransaction:transaction];
if (interactions.count < 1) {
// TODO: OWSFail()?
return nil;
}
if (interactions.count > 1) {
DDLogWarn(@"The database contains %zd colliding timestamps at: %lld.", interactions.count, timestamp);
}
TSInteraction *lastInteraction = interactions.lastObject;
return lastInteraction;
}
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
ofClass:(Class)clazz
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
@ -42,14 +20,14 @@ NS_ASSUME_NONNULL_BEGIN
// Accept any interaction.
return [self interactionsWithTimestamp:timestamp
withFilter:^(TSInteraction *interaction) {
return [interaction isKindOfClass:clazz];
}
filter:^(TSInteraction *interaction) {
return [interaction isKindOfClass:clazz];
}
withTransaction:transaction];
}
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
withFilter:(BOOL (^_Nonnull)(TSInteraction *))filter
filter:(BOOL (^_Nonnull)(TSInteraction *))filter
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(timestamp > 0);

View File

@ -176,7 +176,7 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) {
- (void)updateWithWasSentFromLinkedDeviceWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)updateWithSingleGroupRecipient:(NSString *)singleGroupRecipient
transaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)updateWithReadRecipient:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)updateWithReadRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction;
#pragma mark - Sent Recipients

View File

@ -411,7 +411,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
}];
}
- (void)updateWithReadRecipient:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction
- (void)updateWithReadRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(recipientId.length > 0);
OWSAssert(transaction);

View File

@ -187,14 +187,24 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(envelope);
OWSAssert(transaction);
TSInteraction *interaction = [TSInteraction interactionForTimestamp:envelope.timestamp withTransaction:transaction];
if ([interaction isKindOfClass:[TSOutgoingMessage class]]) {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)interaction;
[outgoingMessage updateWithWasDeliveredWithTransaction:transaction];
} else {
NSArray<TSOutgoingMessage *> *messages
= (NSArray<TSOutgoingMessage *> *)[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(@"%@ Unexpected message with timestamp: %llu", self.tag, envelope.timestamp);
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];
}
}
}

View File

@ -39,8 +39,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)processReadReceiptsFromRecipient:(OWSSignalServiceProtosReceiptMessage *)receiptMessage
envelope:(OWSSignalServiceProtosEnvelope *)envelope;
- (void)outgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message
transaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)updateOutgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message
transaction:(YapDatabaseReadWriteTransaction *)transaction;
// This method cues this manager:
//

View File

@ -17,9 +17,81 @@
NS_ASSUME_NONNULL_BEGIN
@interface TSRecipientReadReceipt : TSYapDatabaseObject
@property (nonatomic, readonly) uint64_t timestamp;
@property (nonatomic, readonly) NSSet<NSString *> *recipientIds;
@end
#pragma mark -
@implementation TSRecipientReadReceipt
- (instancetype)initWithTimestamp:(uint64_t)timestamp
{
OWSAssert(timestamp > 0);
self = [super initWithUniqueId:[TSRecipientReadReceipt uniqueIdForTimestamp:timestamp]];
if (self) {
_timestamp = timestamp;
_recipientIds = [NSSet set];
}
return self;
}
+ (NSString *)uniqueIdForTimestamp:(uint64_t)timestamp
{
return [NSString stringWithFormat:@"%llu", timestamp];
}
- (void)addRecipientId:(NSString *)recipientId
{
NSMutableSet<NSString *> *recipientIdsCopy = [self.recipientIds mutableCopy];
[recipientIdsCopy addObject:recipientId];
_recipientIds = [recipientIdsCopy copy];
}
+ (void)addRecipientId:(NSString *)recipientId
timestamp:(uint64_t)timestamp
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(transaction);
TSRecipientReadReceipt *_Nullable recipientReadReceipt =
[transaction objectForKey:[self uniqueIdForTimestamp:timestamp] inCollection:[self collection]];
if (!recipientReadReceipt) {
recipientReadReceipt = [[TSRecipientReadReceipt alloc] initWithTimestamp:timestamp];
}
[recipientReadReceipt addRecipientId:recipientId];
[recipientReadReceipt saveWithTransaction:transaction];
}
+ (nullable NSSet<NSString *> *)recipientIdsForTimestamp:(uint64_t)timestamp
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(transaction);
TSRecipientReadReceipt *_Nullable recipientReadReceipt =
[transaction objectForKey:[self uniqueIdForTimestamp:timestamp] inCollection:[self collection]];
return recipientReadReceipt.recipientIds;
}
+ (void)removeRecipientIdsForTimestamp:(uint64_t)timestamp transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(transaction);
[transaction removeObjectForKey:[self uniqueIdForTimestamp:timestamp] inCollection:[self collection]];
}
@end
#pragma mark -
NSString *const OWSReadReceiptManagerCollection = @"OWSReadReceiptManagerCollection";
NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsEnabled";
NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCollection";
@interface OWSReadReceiptManager ()
@ -37,7 +109,7 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol
// we will send to senders.
//
// Should only be accessed while synchronized on the OWSReadReceiptManager.
@property (nonatomic, readonly) NSMutableDictionary<NSString *, NSMutableArray<NSNumber *> *> *toSenderReadReceiptMap;
@property (nonatomic, readonly) NSMutableDictionary<NSString *, NSMutableSet<NSNumber *> *> *toSenderReadReceiptMap;
// Should only be accessed while synchronized on the OWSReadReceiptManager.
@property (nonatomic) BOOL isProcessing;
@ -168,16 +240,17 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol
});
}
NSArray<OWSReadReceipt *> *readReceiptsToSend = [[self.toLinkedDevicesReadReceiptMap allValues] copy];
NSArray<OWSReadReceipt *> *readReceiptsToSend = [self.toLinkedDevicesReadReceiptMap allValues];
[self.toLinkedDevicesReadReceiptMap removeAllObjects];
if (self.toSenderReadReceiptMap.count > 0) {
for (NSString *recipientId in self.toSenderReadReceiptMap) {
NSArray<NSNumber *> *timestamps = self.toSenderReadReceiptMap[recipientId];
NSSet<NSNumber *> *timestamps = self.toSenderReadReceiptMap[recipientId];
OWSAssert(timestamps.count > 0);
TSThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId];
OWSReadReceiptsForSenderMessage *message =
[[OWSReadReceiptsForSenderMessage alloc] initWithThread:thread messageTimestamps:timestamps];
[[OWSReadReceiptsForSenderMessage alloc] initWithThread:thread
messageTimestamps:timestamps.allObjects];
dispatch_async(dispatch_get_main_queue(), ^{
[self.messageSender sendMessage:message
@ -274,9 +347,9 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol
if ([self areReadReceiptsEnabled]) {
DDLogVerbose(@"%@ Enqueuing read receipt for sender.", self.tag);
NSMutableArray<NSNumber *> *_Nullable timestamps = self.toSenderReadReceiptMap[messageAuthorId];
NSMutableSet<NSNumber *> *_Nullable timestamps = self.toSenderReadReceiptMap[messageAuthorId];
if (!timestamps) {
timestamps = [NSMutableArray new];
timestamps = [NSMutableSet new];
self.toSenderReadReceiptMap[messageAuthorId] = timestamps;
}
[timestamps addObject:@(message.timestamp)];
@ -320,42 +393,34 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol
// TODO: We might also need to "mark as read by recipient" any older messages
// from us in that thread. Or maybe this state should hang on the thread?
for (TSOutgoingMessage *message in messages) {
[message updateWithReadRecipient:recipientId transaction:transaction];
[message updateWithReadRecipientId:recipientId transaction:transaction];
}
} else {
// Persist the read receipts so that we can apply them to outgoing messages
// that we learn about later through sync messages.
NSString *storageKey = [NSString stringWithFormat:@"%llu", timestamp];
NSSet<NSString *> *recipientIds =
[transaction objectForKey:storageKey inCollection:OWSRecipientReadReceiptCollection];
NSMutableSet<NSString *> *recipientIdsCopy
= (recipientIds ? [recipientIds mutableCopy] : [NSMutableSet new]);
[recipientIdsCopy addObject:recipientId];
[transaction setObject:recipientIdsCopy
forKey:storageKey
inCollection:OWSRecipientReadReceiptCollection];
[TSRecipientReadReceipt addRecipientId:recipientId timestamp:timestamp transaction:transaction];
}
}
}];
});
}
- (void)outgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message
transaction:(YapDatabaseReadWriteTransaction *)transaction
- (void)updateOutgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(message);
OWSAssert(transaction);
NSString *storageKey = [NSString stringWithFormat:@"%llu", message.timestamp];
NSSet<NSString *> *recipientIds =
[transaction objectForKey:storageKey inCollection:OWSRecipientReadReceiptCollection];
if (recipientIds) {
OWSAssert(recipientIds.count > 0);
for (NSString *recipientId in recipientIds) {
[message updateWithReadRecipient:recipientId transaction:transaction];
}
NSSet<NSString *> *_Nullable recipientIds =
[TSRecipientReadReceipt recipientIdsForTimestamp:message.timestamp transaction:transaction];
if (!recipientIds) {
return;
}
[transaction removeObjectForKey:storageKey inCollection:OWSRecipientReadReceiptCollection];
OWSAssert(recipientIds.count > 0);
for (NSString *recipientId in recipientIds) {
[message updateWithReadRecipientId:recipientId transaction:transaction];
}
[TSRecipientReadReceipt removeRecipientIdsForTimestamp:message.timestamp transaction:transaction];
}
#pragma mark - Settings