diff --git a/src/Messages/TSBlockingManager.h b/src/Messages/TSBlockingManager.h index ddbfe59bd..3a537884a 100644 --- a/src/Messages/TSBlockingManager.h +++ b/src/Messages/TSBlockingManager.h @@ -22,7 +22,7 @@ extern NSString * const kNSNotificationName_BlockedPhoneNumbersDidChange; // When updating the block list from a sync message, we don't // want to fire a sync message. -- (void)setBlockedPhoneNumbers:(NSArray *)blockedPhoneNumbers skipSyncMessage:(BOOL)skipSyncMessage; +- (void)setBlockedPhoneNumbers:(NSArray *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage; - (NSArray *)blockedPhoneNumbers; diff --git a/src/Messages/TSBlockingManager.m b/src/Messages/TSBlockingManager.m index cbe79becc..032c3dc96 100644 --- a/src/Messages/TSBlockingManager.m +++ b/src/Messages/TSBlockingManager.m @@ -33,7 +33,8 @@ NSString *const kTSStorageManager_SyncedBlockedPhoneNumbersKey = @"kTSStorageMan @implementation TSBlockingManager -+ (instancetype)sharedManager { ++ (instancetype)sharedManager +{ static TSBlockingManager *sharedMyManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -65,26 +66,26 @@ NSString *const kTSStorageManager_SyncedBlockedPhoneNumbersKey = @"kTSStorageMan _storageManager = storageManager; _messageSender = messageSender; - [self loadBlockedPhoneNumbers]; - return self; } - - (void)addBlockedPhoneNumber:(NSString *)phoneNumber { OWSAssert(phoneNumber.length > 0); DDLogInfo(@"%@ addBlockedPhoneNumber: %@", self.tag, phoneNumber); @synchronized (self) { + [self lazyLoadBlockedPhoneNumbersIfNecessary]; + if ([_blockedPhoneNumberSet containsObject:phoneNumber]) { + // Ignore redundant changes. return; } [_blockedPhoneNumberSet addObject:phoneNumber]; } - [self handleUpdate:NO]; + [self handleUpdate]; } - (void)removeBlockedPhoneNumber:(NSString *)phoneNumber { @@ -93,23 +94,28 @@ NSString *const kTSStorageManager_SyncedBlockedPhoneNumbersKey = @"kTSStorageMan DDLogInfo(@"%@ removeBlockedPhoneNumber: %@", self.tag, phoneNumber); @synchronized (self) { + [self lazyLoadBlockedPhoneNumbersIfNecessary]; + if (![_blockedPhoneNumberSet containsObject:phoneNumber]) { + // Ignore redundant changes. return; } [_blockedPhoneNumberSet removeObject:phoneNumber]; } - [self handleUpdate:NO]; + [self handleUpdate]; } -- (void)setBlockedPhoneNumbers:(NSArray *)blockedPhoneNumbers skipSyncMessage:(BOOL)skipSyncMessage +- (void)setBlockedPhoneNumbers:(NSArray *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage { OWSAssert(blockedPhoneNumbers != nil); DDLogInfo(@"%@ setBlockedPhoneNumbers: %d", self.tag, (int)blockedPhoneNumbers.count); @synchronized (self) { + [self lazyLoadBlockedPhoneNumbersIfNecessary]; + NSSet *newSet = [NSSet setWithArray:blockedPhoneNumbers]; if ([_blockedPhoneNumberSet isEqualToSet:newSet]) { return; @@ -118,24 +124,35 @@ NSString *const kTSStorageManager_SyncedBlockedPhoneNumbersKey = @"kTSStorageMan _blockedPhoneNumberSet = [newSet mutableCopy]; } - [self handleUpdate:skipSyncMessage]; + [self handleUpdate:sendSyncMessage]; } - (NSArray *)blockedPhoneNumbers { @synchronized (self) { + [self lazyLoadBlockedPhoneNumbersIfNecessary]; + return [_blockedPhoneNumberSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; } } // This should be called every time the block list changes. -- (void)handleUpdate:(BOOL)skipSyncMessage + +- (void)handleUpdate +{ + // By default, always send a sync message when the block list changes. + [self handleUpdate:YES]; +} + +- (void)handleUpdate:(BOOL)sendSyncMessage { NSArray *blockedPhoneNumbers = [self blockedPhoneNumbers]; - - [self saveBlockedPhoneNumbers:blockedPhoneNumbers]; + + [_storageManager setObject:blockedPhoneNumbers + forKey:kTSStorageManager_BlockedPhoneNumbersKey + inCollection:kTSStorageManager_BlockedPhoneNumbersCollection]; dispatch_async(dispatch_get_main_queue(), ^{ - if (!skipSyncMessage) { + if (sendSyncMessage) { [self sendBlockedPhoneNumbersMessage:blockedPhoneNumbers]; } else { // If this update came from an incoming blocklist sync message, @@ -159,20 +176,14 @@ NSString *const kTSStorageManager_SyncedBlockedPhoneNumbersKey = @"kTSStorageMan }); } -- (void)saveBlockedPhoneNumbers:(NSArray *)blockedPhoneNumbers +// This method should only be called from within a synchronized block. +- (void)lazyLoadBlockedPhoneNumbersIfNecessary { - OWSAssert(blockedPhoneNumbers); - - DDLogInfo(@"%@ saveBlockedPhoneNumbers", self.tag); - - [_storageManager setObject:blockedPhoneNumbers - forKey:kTSStorageManager_BlockedPhoneNumbersKey - inCollection:kTSStorageManager_BlockedPhoneNumbersCollection]; -} + if (_blockedPhoneNumberSet) { + // _blockedPhoneNumberSet has already been loaded, abort. + return; + } -// We don't need to synchronize this method since it should only be called by the constructor. -- (void)loadBlockedPhoneNumbers -{ NSArray *blockedPhoneNumbers = [_storageManager objectForKey:kTSStorageManager_BlockedPhoneNumbersKey inCollection:kTSStorageManager_BlockedPhoneNumbersCollection]; _blockedPhoneNumberSet = [[NSMutableSet alloc] initWithArray:(blockedPhoneNumbers ?: [NSArray new])]; diff --git a/src/Messages/TSMessagesManager.m b/src/Messages/TSMessagesManager.m index 097c1f6bf..2f660901e 100644 --- a/src/Messages/TSMessagesManager.m +++ b/src/Messages/TSMessagesManager.m @@ -542,7 +542,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ Received `blocked` syncMessage.", self.tag); NSArray *blockedPhoneNumbers = [syncMessage.blocked.numbers copy]; - [_blockingManager setBlockedPhoneNumbers:blockedPhoneNumbers skipSyncMessage:YES]; + [_blockingManager setBlockedPhoneNumbers:blockedPhoneNumbers sendSyncMessage:NO]; } else if (syncMessage.read.count > 0) { DDLogInfo(@"%@ Received %ld read receipt(s)", self.tag, (u_long)syncMessage.read.count);