Reduce usage of contacts intersection endpoint.

// FREEBIE
pull/1/head
Matthew Chen 9 years ago
parent f38f3d8887
commit 5b4e3a2422

@ -16,12 +16,13 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification =
@interface OWSContactsManager () @interface OWSContactsManager ()
@property id addressBookReference; @property (atomic) id addressBookReference;
@property TOCFuture *futureAddressBook; @property (atomic) TOCFuture *futureAddressBook;
@property ObservableValueController *observableContactsController; @property (atomic) ObservableValueController *observableContactsController;
@property TOCCancelTokenSource *life; @property (atomic) TOCCancelTokenSource *life;
@property (atomic) NSDictionary *latestContactsById; @property (atomic) NSDictionary *latestContactsById;
@property (atomic) NSDictionary<NSString *, Contact *> *contactMap; @property (atomic) NSDictionary<NSString *, Contact *> *contactMap;
@property (nonatomic) BOOL isContactsUpdateInFlight;
@end @end
@ -86,6 +87,7 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification =
- (void)doAfterEnvironmentInitSetup { - (void)doAfterEnvironmentInitSetup {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(9, 0)) { if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(9, 0)) {
OWSAssert(!self.contactStore);
self.contactStore = [[CNContactStore alloc] init]; self.contactStore = [[CNContactStore alloc] init];
[self.contactStore requestAccessForEntityType:CNEntityTypeContacts [self.contactStore requestAccessForEntityType:CNEntityTypeContacts
completionHandler:^(BOOL granted, NSError *_Nullable error) { completionHandler:^(BOOL granted, NSError *_Nullable error) {
@ -96,7 +98,7 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification =
}]; }];
} }
[self setupAddressBook]; [self setupAddressBookIfNecessary];
[self.observableContactsController watchLatestValueOnArbitraryThread:^(NSArray *latestContacts) { [self.observableContactsController watchLatestValueOnArbitraryThread:^(NSArray *latestContacts) {
@synchronized(self) { @synchronized(self) {
@ -107,9 +109,7 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification =
} }
- (void)verifyABPermission { - (void)verifyABPermission {
if (!self.addressBookReference) { [self setupAddressBookIfNecessary];
[self setupAddressBook];
}
} }
#pragma mark - Address Book callbacks #pragma mark - Address Book callbacks
@ -131,34 +131,78 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
#pragma mark - Setup #pragma mark - Setup
- (void)setupAddressBook { - (void)setupAddressBookIfNecessary
{
@synchronized(self)
{
// We only need to set up our address book once;
// after that we only need to respond to onAddressBookChanged.
if (self.addressBookReference) {
return;
}
// De-bounce address book setup.
if (self.isContactsUpdateInFlight) {
return;
}
self.isContactsUpdateInFlight = YES;
}
dispatch_async(ADDRESSBOOK_QUEUE, ^{ dispatch_async(ADDRESSBOOK_QUEUE, ^{
[[OWSContactsManager asyncGetAddressBook] thenDo:^(id addressBook) { TOCFuture *future = [OWSContactsManager asyncGetAddressBook];
[future thenDo:^(id addressBook) {
// Success.
@synchronized(self)
{
OWSAssert(self.isContactsUpdateInFlight);
OWSAssert(!self.addressBookReference);
self.addressBookReference = addressBook; self.addressBookReference = addressBook;
self.isContactsUpdateInFlight = NO;
}
ABAddressBookRef cfAddressBook = (__bridge ABAddressBookRef)addressBook; ABAddressBookRef cfAddressBook = (__bridge ABAddressBookRef)addressBook;
ABAddressBookRegisterExternalChangeCallback(cfAddressBook, onAddressBookChanged, (__bridge void *)self); ABAddressBookRegisterExternalChangeCallback(cfAddressBook, onAddressBookChanged, (__bridge void *)self);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self handleAddressBookChanged]; [self handleAddressBookChanged];
}); });
}]; }];
[future catchDo:^(id failure) {
// Failure.
@synchronized(self)
{
OWSAssert(self.isContactsUpdateInFlight);
OWSAssert(!self.addressBookReference);
self.isContactsUpdateInFlight = NO;
}
}];
}); });
} }
- (void)intersectContacts { - (void)intersectContacts {
[[ContactsUpdater sharedUpdater] updateSignalContactIntersectionWithABContacts:self.allContacts [self intersectContactsWithRetryDelay:60];
success:^{ }
- (void)intersectContactsWithRetryDelay:(CGFloat)retryDelaySeconds
{
void (^success)() = ^{
DDLogInfo(@"%@ Successfully intersected contacts.", self.tag); DDLogInfo(@"%@ Successfully intersected contacts.", self.tag);
[self fireSignalRecipientsDidChange]; [self fireSignalRecipientsDidChange];
} };
failure:^(NSError *error) { void (^failure)(NSError *error) = ^(NSError *error) {
DDLogWarn(@"%@ Failed to intersect contacts with error: %@. Rescheduling", self.tag, error); DDLogWarn(@"%@ Failed to intersect contacts with error: %@. Rescheduling", self.tag, error);
[NSTimer scheduledTimerWithTimeInterval:60 // Retry with exponential backoff.
target:self //
selector:@selector(intersectContacts) // TODO: Abort if another contact
userInfo:nil // intersection succeeds in the meantime.
repeats:NO]; dispatch_after(
}]; dispatch_time(DISPATCH_TIME_NOW, (int64_t)(retryDelaySeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self intersectContactsWithRetryDelay:retryDelaySeconds * 2.f];
});
};
[[ContactsUpdater sharedUpdater] updateSignalContactIntersectionWithABContacts:self.allContacts
success:success
failure:failure];
} }
- (void)fireSignalRecipientsDidChange - (void)fireSignalRecipientsDidChange

Loading…
Cancel
Save