Create disappearing message update info messages before messages they affect

Since we're no longer sorting by timestamp we have to ensure we save the update
info message before we save any affected message, e.g. in the case of implicit
updates.
pull/1/head
Michael Kirk 7 years ago
parent eef1368ad3
commit 550e7ba63b

@ -129,12 +129,13 @@ NS_ASSUME_NONNULL_BEGIN
} }
} }
if (transcript.isExpirationTimerUpdate) { [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:outgoingMessage.expiresInSeconds
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage thread:transcript.thread
contactsManager:self.contactsManager createdByRemoteRecipientId:nil
transaction:transaction]; createdInExistingGroup:NO
transaction:transaction];
if (transcript.isExpirationTimerUpdate) {
// early return to avoid saving an empty incoming message. // early return to avoid saving an empty incoming message.
OWSAssertDebug(transcript.body.length == 0); OWSAssertDebug(transcript.body.length == 0);
OWSAssertDebug(outgoingMessage.attachmentIds.count == 0); OWSAssertDebug(outgoingMessage.attachmentIds.count == 0);
@ -149,9 +150,6 @@ NS_ASSUME_NONNULL_BEGIN
[outgoingMessage saveWithTransaction:transaction]; [outgoingMessage saveWithTransaction:transaction];
[outgoingMessage updateWithWasSentFromLinkedDeviceWithTransaction:transaction]; [outgoingMessage updateWithWasSentFromLinkedDeviceWithTransaction:transaction];
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage
contactsManager:self.contactsManager
transaction:transaction];
[[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:outgoingMessage [[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:outgoingMessage
expirationStartedAt:transcript.expirationStartedAt expirationStartedAt:transcript.expirationStartedAt
transaction:transaction]; transaction:transaction];

@ -76,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN
return [NSString stringWithFormat:infoFormat, self.createdByRemoteName]; return [NSString stringWithFormat:infoFormat, self.createdByRemoteName];
} }
} else { } else {
// Changed by local request // Changed by localNumber on this device or via synced transcript
if (self.configurationIsEnabled && self.configurationDurationSeconds > 0) { if (self.configurationIsEnabled && self.configurationDurationSeconds > 0) {
NSString *infoFormat = NSLocalizedString(@"YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION", NSString *infoFormat = NSLocalizedString(@"YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION",
@"Info message embedding a {{time amount}}, see the *_TIME_AMOUNT strings for context."); @"Info message embedding a {{time amount}}, see the *_TIME_AMOUNT strings for context.");

@ -21,42 +21,23 @@ NS_ASSUME_NONNULL_BEGIN
expirationStartedAt:(uint64_t)expirationStartedAt expirationStartedAt:(uint64_t)expirationStartedAt
transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction; transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction;
/**
* Synchronize our disappearing messages settings with that of the given message. Useful so we can
* become eventually consistent with remote senders.
*
* @param message
* Can be an expiring or non expiring message. We match the expiration timer of the message, including disabling
* expiring messages if the message is not an expiring message.
*
* @param contactsManager
* Provides the contact name responsible for any configuration changes in an info message.
*/
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
contactsManager:(id<ContactsManagerProtocol>)contactsManager
transaction:(YapDatabaseReadWriteTransaction *)transaction;
/** /**
* Synchronize our disappearing messages settings with that of the given message. Useful so we can * Synchronize our disappearing messages settings with that of the given message. Useful so we can
* become eventually consistent with remote senders. * become eventually consistent with remote senders.
* *
* @param duration * @param duration
* Can be 0, indicating a non-expiring message, or greater, indicating an expiring message. We match the expiration * Can be 0, indicating a non-expiring message, or greater, indicating an expiring message. We match the expiration
* timer of the message, including disabling expiring messages if the message is not an expiring message. * timer of the message, including disabling expiring messages if the message is not an expiring message.
* *
* @param timestampForSorting * @param remoteRecipientId
* timestampForSorting of the message before which we want to appear. * nil for outgoing messages, otherwise the recipientId of the sender
* *
* @param remoteContactName
* nil for outgoing messages, otherwise the name of the sender
* @param createdInExistingGroup * @param createdInExistingGroup
* YES when being added to a group which already has DM enabled, otherwise NO * YES when being added to a group which already has DM enabled, otherwise NO
*/ */
// MJK FIXME - we can't rely on timestampForSorting
- (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration - (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration
thread:(TSThread *)thread thread:(TSThread *)thread
appearBeforeSenderTimestamp:(uint64_t)timestampForSorting createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId
createdByRemoteContactName:(nullable NSString *)remoteContactName
createdInExistingGroup:(BOOL)createdInExistingGroup createdInExistingGroup:(BOOL)createdInExistingGroup
transaction:(YapDatabaseReadWriteTransaction *)transaction; transaction:(YapDatabaseReadWriteTransaction *)transaction;

@ -13,6 +13,7 @@
#import "OWSDisappearingMessagesConfiguration.h" #import "OWSDisappearingMessagesConfiguration.h"
#import "OWSDisappearingMessagesFinder.h" #import "OWSDisappearingMessagesFinder.h"
#import "OWSPrimaryStorage.h" #import "OWSPrimaryStorage.h"
#import "SSKEnvironment.h"
#import "TSIncomingMessage.h" #import "TSIncomingMessage.h"
#import "TSMessage.h" #import "TSMessage.h"
#import "TSThread.h" #import "TSThread.h"
@ -110,6 +111,15 @@ void AssertIsOnDisappearingMessagesQueue()
return queue; return queue;
} }
#pragma mark - Dependencies
- (id<ContactsManagerProtocol>)contactsManager
{
return SSKEnvironment.shared.contactsManager;
}
#pragma mark -
- (NSUInteger)deleteExpiredMessages - (NSUInteger)deleteExpiredMessages
{ {
AssertIsOnDisappearingMessagesQueue(); AssertIsOnDisappearingMessagesQueue();
@ -193,40 +203,25 @@ void AssertIsOnDisappearingMessagesQueue()
}]; }];
} }
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
contactsManager:(id<ContactsManagerProtocol>)contactsManager
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
TSThread *thread = [message threadWithTransaction:transaction];
NSString *remoteContactName = nil;
if ([message isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message;
remoteContactName = [contactsManager displayNameForPhoneIdentifier:incomingMessage.messageAuthorId];
}
// MJK - we can't rely on timestampForSorting #pragma mark - Apply Remote Configuration
[self becomeConsistentWithDisappearingDuration:message.expiresInSeconds
thread:thread
appearBeforeSenderTimestamp:message.timestampForSorting
createdByRemoteContactName:remoteContactName
createdInExistingGroup:NO
transaction:transaction];
}
// MJK - we can't rely on timestampForSorting
- (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration - (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration
thread:(TSThread *)thread thread:(TSThread *)thread
appearBeforeSenderTimestamp:(uint64_t)timestampForSorting createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId
createdByRemoteContactName:(nullable NSString *)remoteContactName
createdInExistingGroup:(BOOL)createdInExistingGroup createdInExistingGroup:(BOOL)createdInExistingGroup
transaction:(YapDatabaseReadWriteTransaction *)transaction transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
OWSAssertDebug(thread); OWSAssertDebug(thread);
OWSAssertDebug(timestampForSorting > 0);
OWSAssertDebug(transaction); OWSAssertDebug(transaction);
OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
NSString *_Nullable remoteContactName = nil;
if (remoteRecipientId) {
remoteContactName = [self.contactsManager displayNameForPhoneIdentifier:remoteRecipientId];
}
// Become eventually consistent in the case that the remote changed their settings at the same time. // Become eventually consistent in the case that the remote changed their settings at the same time.
// Also in case remote doesn't support expiring messages // Also in case remote doesn't support expiring messages
OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration = OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration =
@ -248,10 +243,9 @@ void AssertIsOnDisappearingMessagesQueue()
[disappearingMessagesConfiguration saveWithTransaction:transaction]; [disappearingMessagesConfiguration saveWithTransaction:transaction];
// We want the info message to appear _before_ the message. // MJK TODO - should be safe to remove this senderTimestamp
// MJK FIXME - we have to affect ordering by creation sequence, not sender timestamp
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage = OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithSenderTimestamp:timestampForSorting - 1 [[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithSenderTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread thread:thread
configuration:disappearingMessagesConfiguration configuration:disappearingMessagesConfiguration
createdByRemoteName:remoteContactName createdByRemoteName:remoteContactName
@ -262,6 +256,8 @@ void AssertIsOnDisappearingMessagesQueue()
backgroundTask = nil; backgroundTask = nil;
} }
#pragma mark -
- (void)startIfNecessary - (void)startIfNecessary
{ {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{

@ -1146,8 +1146,6 @@ NS_ASSUME_NONNULL_BEGIN
TSGroupThread *newGroupThread = TSGroupThread *newGroupThread =
[TSGroupThread getOrCreateThreadWithGroupId:groupId transaction:transaction]; [TSGroupThread getOrCreateThreadWithGroupId:groupId transaction:transaction];
uint64_t now = [NSDate ows_millisecondTimeStamp];
TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name
memberIds:newMemberIds.allObjects memberIds:newMemberIds.allObjects
image:oldGroupThread.groupModel.groupImage image:oldGroupThread.groupModel.groupImage
@ -1157,23 +1155,19 @@ NS_ASSUME_NONNULL_BEGIN
newGroupThread.groupModel = newGroupModel; newGroupThread.groupModel = newGroupModel;
[newGroupThread saveWithTransaction:transaction]; [newGroupThread saveWithTransaction:transaction];
// MJK FIXME - seems like we're relying on senderTimestamp [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
TSInfoMessage *infoMessage = [[TSInfoMessage alloc] initWithSenderTimestamp:now thread:newGroupThread
inThread:newGroupThread createdByRemoteRecipientId:nil
messageType:TSInfoMessageTypeGroupUpdate createdInExistingGroup:NO
customMessage:updateGroupInfo]; transaction:transaction];
[infoMessage saveWithTransaction:transaction];
if (dataMessage.hasExpireTimer && dataMessage.expireTimer > 0) { // MJK TODO - should be safe to remove senderTimestamp
// MJK - we can't rely on senderTimestamp TSInfoMessage *infoMessage =
[[OWSDisappearingMessagesJob sharedJob] [[TSInfoMessage alloc] initWithSenderTimestamp:[NSDate ows_millisecondTimeStamp]
becomeConsistentWithDisappearingDuration:dataMessage.expireTimer inThread:newGroupThread
thread:newGroupThread messageType:TSInfoMessageTypeGroupUpdate
appearBeforeSenderTimestamp:now customMessage:updateGroupInfo];
createdByRemoteContactName:nil [infoMessage saveWithTransaction:transaction];
createdInExistingGroup:YES
transaction:transaction];
}
return nil; return nil;
} }
@ -1210,6 +1204,12 @@ NS_ASSUME_NONNULL_BEGIN
return nil; return nil;
} }
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
thread:oldGroupThread
createdByRemoteRecipientId:envelope.source
createdInExistingGroup:YES
transaction:transaction];
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
thread:oldGroupThread thread:oldGroupThread
transaction:transaction]; transaction:transaction];
@ -1255,6 +1255,12 @@ NS_ASSUME_NONNULL_BEGIN
TSContactThread *thread = TSContactThread *thread =
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction]; [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
thread:thread
createdByRemoteRecipientId:envelope.source
createdInExistingGroup:NO
transaction:transaction];
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
thread:thread thread:thread
transaction:transaction]; transaction:transaction];
@ -1369,10 +1375,6 @@ NS_ASSUME_NONNULL_BEGIN
[OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage [OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage
transaction:transaction]; transaction:transaction];
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:incomingMessage
contactsManager:self.contactsManager
transaction:transaction];
// Update thread preview in inbox // Update thread preview in inbox
[thread touchWithTransaction:transaction]; [thread touchWithTransaction:transaction];

Loading…
Cancel
Save