Add TSBlockingManager.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 8b5f82eb6d
commit f5237ef5d1

@ -0,0 +1,15 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSOutgoingSyncMessage.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSBlockedPhoneNumbersMessage : OWSOutgoingSyncMessage
- (instancetype)initWithPhoneNumbers:(NSArray<NSString *> *)phoneNumbers;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,43 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSBlockedPhoneNumbersMessage.h"
#import "OWSSignalServiceProtos.pb.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSBlockedPhoneNumbersMessage ()
@property (nonatomic, readonly) NSArray<NSString *> *phoneNumbers;
@end
@implementation OWSBlockedPhoneNumbersMessage
- (instancetype)initWithPhoneNumbers:(NSArray<NSString *> *)phoneNumbers
{
self = [super init];
if (!self) {
return self;
}
_phoneNumbers = [phoneNumbers copy];
return self;
}
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
{
OWSSignalServiceProtosSyncMessageBlockedBuilder *blockedPhoneNumbersBuilder =
[OWSSignalServiceProtosSyncMessageBlockedBuilder new];
[blockedPhoneNumbersBuilder setNumbersArray:_phoneNumbers];
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
[syncMessageBuilder setBlocked:[blockedPhoneNumbersBuilder build]];
return [syncMessageBuilder build];
}
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,29 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@class TSStorageManager;
@class OWSMessageSender;
extern NSString * const kNSNotificationName_BlockedPhoneNumbersDidChange;
// This class can be safely accessed and used from any thread.
@interface TSBlockingManager : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)sharedManager;
- (void)addBlockedPhoneNumber:(NSString *)phoneNumber;
- (void)removeBlockedPhoneNumber:(NSString *)phoneNumber;
- (void)setBlockedPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers;
- (NSArray<NSString *> *)blockedPhoneNumbers;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,202 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSBlockingManager.h"
#import "OWSBlockedPhoneNumbersMessage.h"
#import "OWSMessageSender.h"
#import "TSStorageManager.h"
#import "TextSecureKitEnv.h"
NS_ASSUME_NONNULL_BEGIN
NSString * const kNSNotificationName_BlockedPhoneNumbersDidChange = @"kNSNotificationName_BlockedPhoneNumbersDidChange";
NSString * const kTSStorageManager_BlockedPhoneNumbersCollection = @"kTSStorageManager_BlockedPhoneNumbersCollection";
// This key is used to persist the current "blocked phone numbers" state.
NSString * const kTSStorageManager_BlockedPhoneNumbersKey = @"kTSStorageManager_BlockedPhoneNumbersKey";
// This key is used to persist the most recently synced "blocked phone numbers" state.
NSString *const kTSStorageManager_SyncedBlockedPhoneNumbersKey = @"kTSStorageManager_SyncedBlockedPhoneNumbersKey";
@interface TSBlockingManager ()
@property (nonatomic, readonly) TSStorageManager *storageManager;
@property (nonatomic, readonly) OWSMessageSender *messageSender;
// We don't store the phone numbers as instances of PhoneNumber to avoid
// consistency issues between clients, but these should all be valid e164
// phone numbers.
@property (nonatomic, readonly) NSMutableSet<NSString *> *blockedPhoneNumberSet;
@end
#pragma mark -
@implementation TSBlockingManager
+ (instancetype)sharedManager {
static TSBlockingManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] initDefault];
});
return sharedMyManager;
}
- (instancetype)initDefault
{
TSStorageManager *storageManager = [TSStorageManager sharedManager];
OWSMessageSender *messageSender = [TextSecureKitEnv sharedEnv].messageSender;
return [self initStorageManager:storageManager
messageSender:messageSender];
}
- (instancetype)initStorageManager:(TSStorageManager *)storageManager messageSender:(OWSMessageSender *)messageSender
{
self = [super init];
if (!self) {
return self;
}
OWSAssert(storageManager);
OWSAssert(messageSender);
_storageManager = storageManager;
_messageSender = messageSender;
[self loadBlockedPhoneNumbers];
return self;
}
- (void)addBlockedPhoneNumber:(NSString *)phoneNumber {
OWSAssert(phoneNumber.length > 0);
@synchronized (self) {
if ([_blockedPhoneNumberSet containsObject:phoneNumber]) {
return;
}
[_blockedPhoneNumberSet addObject:phoneNumber];
}
[self handleUpdate];
}
- (void)removeBlockedPhoneNumber:(NSString *)phoneNumber {
OWSAssert(phoneNumber.length > 0);
@synchronized (self) {
if (![_blockedPhoneNumberSet containsObject:phoneNumber]) {
return;
}
[_blockedPhoneNumberSet removeObject:phoneNumber];
}
[self handleUpdate];
}
- (void)setBlockedPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers {
OWSAssert(blockedPhoneNumbers != nil);
@synchronized (self) {
NSSet *newSet = [NSSet setWithArray:blockedPhoneNumbers];
if ([_blockedPhoneNumberSet isEqualToSet:newSet]) {
return;
}
_blockedPhoneNumberSet = [newSet mutableCopy];
}
[self handleUpdate];
}
- (NSArray<NSString *> *)blockedPhoneNumbers {
@synchronized (self) {
return [_blockedPhoneNumberSet.allObjects sortedArrayUsingSelector:@selector(compare:)];
}
}
// This should be called every time the block list changes.
- (void)handleUpdate {
NSArray<NSString *> *blockedPhoneNumbers = [self blockedPhoneNumbers];
[self saveBlockedPhoneNumbers:blockedPhoneNumbers];
dispatch_async(dispatch_get_main_queue(), ^{
[self sendBlockedPhoneNumbersMessage:blockedPhoneNumbers];
[[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_BlockedPhoneNumbersDidChange
object:nil
userInfo:nil];
});
}
- (void)saveBlockedPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers
{
OWSAssert(blockedPhoneNumbers);
[_storageManager setObject:blockedPhoneNumbers
forKey:kTSStorageManager_BlockedPhoneNumbersKey
inCollection:kTSStorageManager_BlockedPhoneNumbersCollection];
}
// We don't need to synchronize this method since it should only be called by the constructor.
- (void)loadBlockedPhoneNumbers
{
NSArray<NSString *> *blockedPhoneNumbers = [_storageManager objectForKey:kTSStorageManager_BlockedPhoneNumbersKey
inCollection:kTSStorageManager_BlockedPhoneNumbersCollection];
_blockedPhoneNumberSet = [[NSMutableSet alloc] initWithArray:(blockedPhoneNumbers ?: [NSArray new])];
// If we haven't yet successfully synced the current "blocked phone numbers" changes,
// try again to sync now.
NSArray<NSString *> *syncedBlockedPhoneNumbers =
[_storageManager objectForKey:kTSStorageManager_SyncedBlockedPhoneNumbersKey
inCollection:kTSStorageManager_BlockedPhoneNumbersCollection];
NSSet *syncedBlockedPhoneNumberSet = [[NSSet alloc] initWithArray:(syncedBlockedPhoneNumbers ?: [NSArray new])];
if (![_blockedPhoneNumberSet isEqualToSet:syncedBlockedPhoneNumberSet]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self sendBlockedPhoneNumbersMessage:blockedPhoneNumbers];
});
}
}
- (void)sendBlockedPhoneNumbersMessage:(NSArray<NSString *> *)blockedPhoneNumbers
{
OWSAssert(blockedPhoneNumbers);
OWSBlockedPhoneNumbersMessage *message =
[[OWSBlockedPhoneNumbersMessage alloc] initWithPhoneNumbers:blockedPhoneNumbers];
[self.messageSender sendMessage:message
success:^{
DDLogInfo(@"%@ Successfully sent blocked phone numbers", self.tag);
// Record the last set of "blocked phone numbers" which we successfully synced.
[_storageManager setObject:blockedPhoneNumbers
forKey:kTSStorageManager_SyncedBlockedPhoneNumbersKey
inCollection:kTSStorageManager_BlockedPhoneNumbersCollection];
}
failure:^(NSError *error) {
DDLogError(@"%@ Failed to send blocked phone numbers with error: %@", self.tag, error);
}];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

@ -37,6 +37,7 @@
#import "TextSecureKitEnv.h"
#import <AxolotlKit/AxolotlExceptions.h>
#import <AxolotlKit/SessionCipher.h>
#import "TSBlockingManager.h"
NS_ASSUME_NONNULL_BEGIN
@ -48,6 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic, readonly) OWSDisappearingMessagesJob *disappearingMessagesJob;
@property (nonatomic, readonly) OWSIncomingMessageFinder *incomingMessageFinder;
@property (nonatomic, readonly) TSBlockingManager *blockingManager;
@end
@ -102,7 +104,8 @@ NS_ASSUME_NONNULL_BEGIN
_dbConnection = storageManager.newDatabaseConnection;
_disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithStorageManager:storageManager];
_incomingMessageFinder = [[OWSIncomingMessageFinder alloc] initWithDatabase:storageManager.database];
_blockingManager = [TSBlockingManager sharedManager];
return self;
}
@ -504,37 +507,43 @@ NS_ASSUME_NONNULL_BEGIN
} else if (syncMessage.hasRequest) {
if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeContacts) {
DDLogInfo(@"%@ Received request `Contacts` syncMessage.", self.tag);
OWSSyncContactsMessage *syncContactsMessage =
[[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager];
[[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager];
[self.messageSender sendTemporaryAttachmentData:[syncContactsMessage buildPlainTextAttachmentData]
contentType:OWSMimeTypeApplicationOctetStream
inMessage:syncContactsMessage
success:^{
DDLogInfo(@"%@ Successfully sent Contacts response syncMessage.", self.tag);
}
failure:^(NSError *error) {
DDLogError(@"%@ Failed to send Contacts response syncMessage with error: %@", self.tag, error);
}];
contentType:OWSMimeTypeApplicationOctetStream
inMessage:syncContactsMessage
success:^{
DDLogInfo(@"%@ Successfully sent Contacts response syncMessage.", self.tag);
}
failure:^(NSError *error) {
DDLogError(@"%@ Failed to send Contacts response syncMessage with error: %@", self.tag, error);
}];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeGroups) {
DDLogInfo(@"%@ Received request `groups` syncMessage.", self.tag);
OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init];
[self.messageSender sendTemporaryAttachmentData:[syncGroupsMessage buildPlainTextAttachmentData]
contentType:OWSMimeTypeApplicationOctetStream
inMessage:syncGroupsMessage
success:^{
DDLogInfo(@"%@ Successfully sent Groups response syncMessage.", self.tag);
}
failure:^(NSError *error) {
DDLogError(@"%@ Failed to send Groups response syncMessage with error: %@", self.tag, error);
}];
contentType:OWSMimeTypeApplicationOctetStream
inMessage:syncGroupsMessage
success:^{
DDLogInfo(@"%@ Successfully sent Groups response syncMessage.", self.tag);
}
failure:^(NSError *error) {
DDLogError(@"%@ Failed to send Groups response syncMessage with error: %@", self.tag, error);
}];
} else {
DDLogWarn(@"%@ ignoring unsupported sync request message", self.tag);
}
} else if (syncMessage.hasBlocked) {
DDLogInfo(@"%@ Received `blocked` syncMessage.", self.tag);
NSArray<NSString *> *blockedPhoneNumbers = [syncMessage.blocked.numbers copy];
[_blockingManager setBlockedPhoneNumbers:blockedPhoneNumbers];
} else if (syncMessage.read.count > 0) {
DDLogInfo(@"%@ Received %ld read receipt(s)", self.tag, (u_long)syncMessage.read.count);

Loading…
Cancel
Save