diff --git a/SignalMessaging/environment/AppSetup.m b/SignalMessaging/environment/AppSetup.m index 23a04b611..9776d4e83 100644 --- a/SignalMessaging/environment/AppSetup.m +++ b/SignalMessaging/environment/AppSetup.m @@ -14,11 +14,13 @@ #import #import #import +#import #import #import #import #import #import +#import #import #import #import @@ -68,6 +70,10 @@ NS_ASSUME_NONNULL_BEGIN OWSDisappearingMessagesJob *disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithPrimaryStorage:primaryStorage]; ContactDiscoveryService *contactDiscoveryService = [[ContactDiscoveryService alloc] initDefault]; + OWSReadReceiptManager *readReceiptManager = + [[OWSReadReceiptManager alloc] initWithPrimaryStorage:primaryStorage]; + OWSDeliveryReceiptManager *deliveryReceiptManager = + [[OWSDeliveryReceiptManager alloc] initWithPrimaryStorage:primaryStorage]; [Environment setShared:[[Environment alloc] initWithPreferences:preferences]]; @@ -88,7 +94,9 @@ NS_ASSUME_NONNULL_BEGIN tsAccountManager:tsAccountManager ows2FAManager:ows2FAManager disappearingMessagesJob:disappearingMessagesJob - contactDiscoveryService:contactDiscoveryService]]; + contactDiscoveryService:contactDiscoveryService + disappearingMessagesJob:readReceiptManager + contactDiscoveryService:deliveryReceiptManager]]; appSpecificSingletonBlock(); diff --git a/SignalServiceKit/src/Devices/OWSReadReceiptsForSenderMessage.h b/SignalServiceKit/src/Devices/OWSReceiptsForSenderMessage.h similarity index 65% rename from SignalServiceKit/src/Devices/OWSReadReceiptsForSenderMessage.h rename to SignalServiceKit/src/Devices/OWSReceiptsForSenderMessage.h index de15a8fa6..38ac126aa 100644 --- a/SignalServiceKit/src/Devices/OWSReadReceiptsForSenderMessage.h +++ b/SignalServiceKit/src/Devices/OWSReceiptsForSenderMessage.h @@ -6,9 +6,9 @@ NS_ASSUME_NONNULL_BEGIN -@class OWSReadReceipt; +@class OWSDeliveryReceipt; -@interface OWSReadReceiptsForSenderMessage : TSOutgoingMessage +@interface OWSReceiptsForSenderMessage : TSOutgoingMessage - (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp inThread:(nullable TSThread *)thread @@ -21,7 +21,11 @@ NS_ASSUME_NONNULL_BEGIN quotedMessage:(nullable TSQuotedMessage *)quotedMessage contactShare:(nullable OWSContact *)contactShare NS_UNAVAILABLE; -- (instancetype)initWithThread:(nullable TSThread *)thread messageTimestamps:(NSArray *)messageTimestamps; ++ (OWSReceiptsForSenderMessage *)deliveryReceiptsForSenderMessageWithThread:(nullable TSThread *)thread + messageTimestamps:(NSArray *)messageTimestamps; + ++ (OWSReceiptsForSenderMessage *)readReceiptsForSenderMessageWithThread:(nullable TSThread *)thread + messageTimestamps:(NSArray *)messageTimestamps; @end diff --git a/SignalServiceKit/src/Devices/OWSReadReceiptsForSenderMessage.m b/SignalServiceKit/src/Devices/OWSReceiptsForSenderMessage.m similarity index 60% rename from SignalServiceKit/src/Devices/OWSReadReceiptsForSenderMessage.m rename to SignalServiceKit/src/Devices/OWSReceiptsForSenderMessage.m index 84c193b43..7a7347601 100644 --- a/SignalServiceKit/src/Devices/OWSReadReceiptsForSenderMessage.m +++ b/SignalServiceKit/src/Devices/OWSReceiptsForSenderMessage.m @@ -2,25 +2,42 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSReadReceiptsForSenderMessage.h" +#import "OWSReceiptsForSenderMessage.h" #import "SignalRecipient.h" #import #import NS_ASSUME_NONNULL_BEGIN -@interface OWSReadReceiptsForSenderMessage () +@interface OWSReceiptsForSenderMessage () @property (nonatomic, readonly) NSArray *messageTimestamps; +@property (nonatomic, readonly) SSKProtoReceiptMessageType receiptType; + @end #pragma mark - -@implementation OWSReadReceiptsForSenderMessage +@implementation OWSReceiptsForSenderMessage -- (instancetype)initWithThread:(nullable TSThread *)thread messageTimestamps:(NSArray *)messageTimestamps -{ ++ (OWSReceiptsForSenderMessage *)deliveryReceiptsForSenderMessageWithThread:(nullable TSThread *)thread + messageTimestamps:(NSArray *)messageTimestamps { + return [[OWSReceiptsForSenderMessage alloc] initWithThread:thread + messageTimestamps:messageTimestamps + receiptType:SSKProtoReceiptMessageTypeDelivery]; +} + ++ (OWSReceiptsForSenderMessage *)readReceiptsForSenderMessageWithThread:(nullable TSThread *)thread + messageTimestamps:(NSArray *)messageTimestamps { + return [[OWSReceiptsForSenderMessage alloc] initWithThread:thread + messageTimestamps:messageTimestamps + receiptType:SSKProtoReceiptMessageTypeRead]; +} + +- (instancetype)initWithThread:(nullable TSThread *)thread + messageTimestamps:(NSArray *)messageTimestamps + receiptType:(SSKProtoReceiptMessageType)receiptType { self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread messageBody:nil @@ -42,20 +59,17 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - TSOutgoingMessage overrides -- (BOOL)shouldSyncTranscript -{ +- (BOOL)shouldSyncTranscript { return NO; } -- (BOOL)isSilent -{ +- (BOOL)isSilent { // Avoid "phantom messages" for "recipient read receipts". return YES; } -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient -{ +- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient { OWSAssertDebug(recipient); SSKProtoReceiptMessage *_Nullable receiptMessage = [self buildReceiptMessage:recipient.recipientId]; @@ -76,9 +90,8 @@ NS_ASSUME_NONNULL_BEGIN return contentData; } -- (nullable SSKProtoReceiptMessage *)buildReceiptMessage:(NSString *)recipientId -{ - SSKProtoReceiptMessageBuilder *builder = [SSKProtoReceiptMessage builderWithType:SSKProtoReceiptMessageTypeRead]; +- (nullable SSKProtoReceiptMessage *)buildReceiptMessage:(NSString *)recipientId { + SSKProtoReceiptMessageBuilder *builder = [SSKProtoReceiptMessage builderWithType:self.receiptType]; OWSAssertDebug(self.messageTimestamps.count > 0); for (NSNumber *messageTimestamp in self.messageTimestamps) { @@ -96,14 +109,13 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - TSYapDatabaseObject overrides -- (BOOL)shouldBeSaved -{ +- (BOOL)shouldBeSaved { return NO; } -- (NSString *)debugDescription -{ - return [NSString stringWithFormat:@"%@ with message timestamps: %lu", self.logTag, (unsigned long)self.messageTimestamps.count]; +- (NSString *)debugDescription { + return [NSString + stringWithFormat:@"%@ with message timestamps: %lu", self.logTag, (unsigned long)self.messageTimestamps.count]; } @end diff --git a/SignalServiceKit/src/Messages/OWSDeliveryReceiptManager.h b/SignalServiceKit/src/Messages/OWSDeliveryReceiptManager.h new file mode 100644 index 000000000..2d411a13d --- /dev/null +++ b/SignalServiceKit/src/Messages/OWSDeliveryReceiptManager.h @@ -0,0 +1,90 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +NS_ASSUME_NONNULL_BEGIN + +//@class SSKProtoSyncMessageRead; +//@class TSIncomingMessage; +//@class TSOutgoingMessage; +//@class TSThread; +//@class YapDatabaseReadTransaction; +//@class YapDatabaseReadWriteTransaction; + +@class OWSPrimaryStorage; +@class SSKProtoEnvelope; + +// extern NSString *const kIncomingMessageMarkedAsReadNotification; + +// There are four kinds of read receipts: +// +// * Read receipts that this client sends to linked +// devices to inform them that a message has been read. +// * Read receipts that this client receives from linked +// devices that inform this client that a message has been read. +// * These read receipts are saved so that they can be applied +// if they arrive before the corresponding message. +// * Read receipts that this client sends to other users +// to inform them that a message has been read. +// * Read receipts that this client receives from other users +// that inform this client that a message has been read. +// * These read receipts are saved so that they can be applied +// if they arrive before the corresponding message. +// +// This manager is responsible for handling and emitting all four kinds. +@interface OWSDeliveryReceiptManager : NSObject + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; ++ (instancetype)sharedManager; + +//#pragma mark - Sender/Recipient Read Receipts +// +//// This method should be called when we receive a read receipt +//// from a user to whom we have sent a message. +//// +//// This method can be called from any thread. +//- (void)processDeliveryReceiptsFromRecipientId:(NSString *)recipientId +// sentTimestamps:(NSArray *)sentTimestamps +// readTimestamp:(uint64_t)readTimestamp; +// +//- (void)applyEarlyDeliveryReceiptsForOutgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message +// transaction:(YapDatabaseReadWriteTransaction *)transaction; +// +//#pragma mark - Linked Device Read Receipts +// +//- (void)processDeliveryReceiptsFromLinkedDevice:(NSArray *)DeliveryReceiptProtos +// readTimestamp:(uint64_t)readTimestamp +// transaction:(YapDatabaseReadWriteTransaction *)transaction; +// +//- (void)applyEarlyDeliveryReceiptsForIncomingMessage:(TSIncomingMessage *)message +// transaction:(YapDatabaseReadWriteTransaction *)transaction; +// +//#pragma mark - Locally Read +// +//// This method cues this manager: +//// +//// * ...to inform the sender that this message was read (if read receipts +//// are enabled). +//// * ...to inform the local user's other devices that this message was read. +//// +//// Both types of messages are deduplicated. +//// +//// This method can be called from any thread. +//- (void)messageWasReadLocally:(TSIncomingMessage *)message; +// +//- (void)markAsReadLocallyBeforeTimestamp:(uint64_t)timestamp thread:(TSThread *)thread; +// +//#pragma mark - Settings +// +//- (void)prepareCachedValues; +// +//- (BOOL)areDeliveryReceiptsEnabled; +//- (BOOL)areDeliveryReceiptsEnabledWithTransaction:(YapDatabaseReadTransaction *)transaction; +//- (void)setAreDeliveryReceiptsEnabled:(BOOL)value; + +- (void)envelopeWasReceived:(SSKProtoEnvelope *)envelope; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSDeliveryReceiptManager.m b/SignalServiceKit/src/Messages/OWSDeliveryReceiptManager.m new file mode 100644 index 000000000..f0d12f195 --- /dev/null +++ b/SignalServiceKit/src/Messages/OWSDeliveryReceiptManager.m @@ -0,0 +1,228 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWSDeliveryReceiptManager.h" +#import "AppReadiness.h" +#import "OWSMessageSender.h" +#import "OWSPrimaryStorage.h" +#import "OWSReceiptsForSenderMessage.h" +#import "SSKEnvironment.h" +#import "TSContactThread.h" +#import "TSYapDatabaseObject.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +NSString *const kDeliveryReceiptManagerCollection = @"kDeliveryReceiptManagerCollection"; + +@interface OWSDeliveryReceiptManager () + +@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; + +// Should only be accessed on the serialQueue. +@property (nonatomic) BOOL isProcessing; + +// A map of "recipient id"-to-"timestamp list" for delivery receipts that +// we will send to senders. +// +// Should only be accessed on the serialQueue. +@property (nonatomic, readonly) NSMutableDictionary *> *deliveryReceiptMap; + +@end + +#pragma mark - + +@implementation OWSDeliveryReceiptManager + ++ (instancetype)sharedManager { + OWSAssert(SSKEnvironment.shared.deliveryReceiptManager); + + return SSKEnvironment.shared.deliveryReceiptManager; +} + +- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage { + self = [super init]; + + if (!self) { + return self; + } + + _dbConnection = primaryStorage.newDatabaseConnection; + + _deliveryReceiptMap = [NSMutableDictionary new]; + + OWSSingletonAssert(); + + // Start processing. + [AppReadiness runNowOrWhenAppIsReady:^{ + [self scheduleProcessing]; + }]; + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Dependencies + +- (OWSMessageSender *)messageSender { + OWSAssertDebug(SSKEnvironment.shared.messageSender); + + return SSKEnvironment.shared.messageSender; +} + +#pragma mark - + +- (dispatch_queue_t)serialQueue { + static dispatch_queue_t _serialQueue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _serialQueue = dispatch_queue_create("org.whispersystems.deliveryReceipts", DISPATCH_QUEUE_SERIAL); + }); + + return _serialQueue; +} + +// Schedules a processing pass, unless one is already scheduled. +- (void)scheduleProcessing { + OWSAssertDebug(AppReadiness.isAppReady); + + dispatch_async(self.serialQueue, ^{ + if (self.isProcessing) { + return; + } + + self.isProcessing = YES; + + [self process]; + }); +} + +- (void)process { + OWSLogVerbose(@"Processing outbound delivery receipts."); + + NSMutableDictionary *> *deliveryReceiptMap = [NSMutableDictionary new]; + [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [transaction enumerateKeysAndObjectsInCollection:kDeliveryReceiptManagerCollection + usingBlock:^(NSString *key, id object, BOOL *stop) { + NSString *recipientId = key; + NSSet *timestamps = object; + deliveryReceiptMap[recipientId] = timestamps; + }]; + }]; + + BOOL didWork = NO; + + for (NSString *recipientId in deliveryReceiptMap) { + NSSet *timestamps = deliveryReceiptMap[recipientId]; + if (timestamps.count < 1) { + OWSFailDebug(@"Missing timestamps."); + continue; + } + + TSThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; + OWSReceiptsForSenderMessage *message = + [OWSReceiptsForSenderMessage deliveryReceiptsForSenderMessageWithThread:thread + messageTimestamps:timestamps.allObjects]; + + [self.messageSender enqueueMessage:message + success:^{ + OWSLogInfo(@"Successfully sent %lu delivery receipts to sender.", (unsigned long)timestamps.count); + } + failure:^(NSError *error) { + OWSLogError(@"Failed to send delivery receipts to sender with error: %@", error); + }]; + + didWork = YES; + } + + // Now that they've been processed, remove all enqueued delivery receipts. + // + // NOTE: we don't need to worry about race conditions; this + // collection will only be mutated on serialQueue. + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [transaction removeAllObjectsInCollection:kDeliveryReceiptManagerCollection]; + }]; + + if (!didWork) { + self.isProcessing = NO; + return; + } + + // Wait N seconds before processing delivery receipts again. + // This allows time for a batch to accumulate. + // + // We want a value high enough to allow us to effectively de-duplicate, + // delivery receipts without being so high that we risk not sending delivery + // receipts due to app exit. + const CGFloat kProcessingFrequencySeconds = 3.f; + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kProcessingFrequencySeconds * NSEC_PER_SEC)), self.serialQueue, ^{ + [self process]; + }); +} + +- (void)envelopeWasReceived:(SSKProtoEnvelope *)envelope { + OWSLogVerbose(@""); + + [self enqueueDeliveryReceiptWithRecipientId:envelope.source timestamp:envelope.timestamp]; +} + +- (void)enqueueDeliveryReceiptWithRecipientId:(NSString *)recipientId timestamp:(uint64_t)timestamp { + OWSLogVerbose(@""); + + if (recipientId.length < 1) { + OWSFailDebug(@"Invalid recipient id."); + return; + } + if (timestamp < 1) { + OWSFailDebug(@"Invalid timestamp."); + return; + } + dispatch_async(self.serialQueue, ^{ + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + NSSet *_Nullable oldTimestamps = [transaction objectForKey:recipientId + inCollection:kDeliveryReceiptManagerCollection]; + NSMutableSet *newTimestamps + = (oldTimestamps ? [oldTimestamps mutableCopy] : [NSMutableSet new]); + [newTimestamps addObject:@(timestamp)]; + + [transaction setObject:newTimestamps forKey:recipientId inCollection:kDeliveryReceiptManagerCollection]; + }]; + + [self scheduleProcessing]; + }); +} + +- (void)dequeueDeliveryReceiptsWithRecipientId:(NSString *)recipientId timestamps:(NSSet *)timestamps { + if (recipientId.length < 1) { + OWSFailDebug(@"Invalid recipient id."); + return; + } + if (timestamps.count < 1) { + OWSFailDebug(@"Invalid timestamps."); + return; + } + dispatch_async(self.serialQueue, ^{ + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + NSSet *_Nullable oldTimestamps = [transaction objectForKey:recipientId + inCollection:kDeliveryReceiptManagerCollection]; + NSMutableSet *newTimestamps + = (oldTimestamps ? [oldTimestamps mutableCopy] : [NSMutableSet new]); + [newTimestamps minusSet:timestamps]; + + if (newTimestamps.count > 0) { + [transaction setObject:newTimestamps forKey:recipientId inCollection:kDeliveryReceiptManagerCollection]; + } else { + [transaction removeObjectForKey:recipientId inCollection:kDeliveryReceiptManagerCollection]; + } + }]; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSIdentityManager.m b/SignalServiceKit/src/Messages/OWSIdentityManager.m index 06ecc7b89..590209bdf 100644 --- a/SignalServiceKit/src/Messages/OWSIdentityManager.m +++ b/SignalServiceKit/src/Messages/OWSIdentityManager.m @@ -98,6 +98,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa [[NSNotificationCenter defaultCenter] removeObserver:self]; } +#pragma mark - Dependencies + - (OWSMessageSender *)messageSender { OWSAssertDebug(SSKEnvironment.shared.messageSender); @@ -105,6 +107,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa return SSKEnvironment.shared.messageSender; } +#pragma mark - + - (void)observeNotifications { [[NSNotificationCenter defaultCenter] addObserver:self diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 57a30c3e1..50c295310 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -12,6 +12,7 @@ #import "OWSBlockingManager.h" #import "OWSCallMessageHandler.h" #import "OWSContact.h" +#import "OWSDeliveryReceiptManager.h" #import "OWSDevice.h" #import "OWSDisappearingConfigurationUpdateInfoMessage.h" #import "OWSDisappearingMessagesConfiguration.h" @@ -131,6 +132,14 @@ NS_ASSUME_NONNULL_BEGIN return SSKEnvironment.shared.networkManager; } +- (OWSDeliveryReceiptManager *)deliveryReceiptManager { + OWSAssertDebug(SSKEnvironment.shared.deliveryReceiptManager); + + return SSKEnvironment.shared.deliveryReceiptManager; +} + +#pragma mark - + - (void)startObserving { [[NSNotificationCenter defaultCenter] addObserver:self @@ -490,6 +499,15 @@ NS_ASSUME_NONNULL_BEGIN [self handleReceivedGroupAvatarUpdateWithEnvelope:envelope dataMessage:dataMessage transaction:transaction]; } } + + // Send delivery receipts for "valid data" messages. + [self.deliveryReceiptManager envelopeWasReceived:envelope]; +} + +- (void)sendDeliveryReceiptForEnvelope:(SSKProtoEnvelope *)envelope { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^ { + }); } - (void)sendGroupInfoRequest:(NSData *)groupId diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.h b/SignalServiceKit/src/Messages/OWSReadReceiptManager.h index f97e32ab7..4280e5e84 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.h +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.h @@ -4,6 +4,7 @@ NS_ASSUME_NONNULL_BEGIN +@class OWSPrimaryStorage; @class SSKProtoSyncMessageRead; @class TSIncomingMessage; @class TSOutgoingMessage; @@ -32,6 +33,7 @@ extern NSString *const kIncomingMessageMarkedAsReadNotification; @interface OWSReadReceiptManager : NSObject - (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; + (instancetype)sharedManager; #pragma mark - Sender/Recipient Read Receipts diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m index 77e391d26..9244ef491 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m @@ -9,7 +9,7 @@ #import "OWSMessageSender.h" #import "OWSPrimaryStorage.h" #import "OWSReadReceiptsForLinkedDevicesMessage.h" -#import "OWSReadReceiptsForSenderMessage.h" +#import "OWSReceiptsForSenderMessage.h" #import "OWSStorage.h" #import "OWSSyncConfigurationMessage.h" #import "SSKEnvironment.h" @@ -117,8 +117,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE @interface OWSReadReceiptManager () -@property (nonatomic, readonly) OWSMessageSender *messageSender; - @property (nonatomic, readonly) YapDatabaseConnection *dbConnection; // A map of "thread unique id"-to-"read receipt" for read receipts that @@ -146,32 +144,18 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE + (instancetype)sharedManager { - static OWSReadReceiptManager *sharedMyManager = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedMyManager = [[self alloc] initDefault]; - }); - return sharedMyManager; + OWSAssert(SSKEnvironment.shared.readReceiptManager); + + return SSKEnvironment.shared.readReceiptManager; } -- (instancetype)initDefault -{ - OWSMessageSender *messageSender = SSKEnvironment.shared.messageSender; - OWSPrimaryStorage *primaryStorage = [OWSPrimaryStorage sharedManager]; - - return [self initWithMessageSender:messageSender primaryStorage:primaryStorage]; -} - -- (instancetype)initWithMessageSender:(OWSMessageSender *)messageSender - primaryStorage:(OWSPrimaryStorage *)primaryStorage -{ +- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage { self = [super init]; if (!self) { return self; } - _messageSender = messageSender; _dbConnection = primaryStorage.newDatabaseConnection; _toLinkedDevicesReadReceiptMap = [NSMutableDictionary new]; @@ -192,6 +176,16 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE [[NSNotificationCenter defaultCenter] removeObserver:self]; } +#pragma mark - Dependencies + +- (OWSMessageSender *)messageSender { + OWSAssertDebug(SSKEnvironment.shared.messageSender); + + return SSKEnvironment.shared.messageSender; +} + +#pragma mark - + // Schedules a processing pass, unless one is already scheduled. - (void)scheduleProcessing { @@ -243,9 +237,9 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE OWSAssertDebug(timestamps.count > 0); TSThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - OWSReadReceiptsForSenderMessage *message = - [[OWSReadReceiptsForSenderMessage alloc] initWithThread:thread - messageTimestamps:timestamps.allObjects]; + OWSReceiptsForSenderMessage *message = + [OWSReceiptsForSenderMessage readReceiptsForSenderMessageWithThread:thread + messageTimestamps:timestamps.allObjects]; [self.messageSender enqueueMessage:message success:^{ diff --git a/SignalServiceKit/src/SSKEnvironment.h b/SignalServiceKit/src/SSKEnvironment.h index d97b1f2ca..ca862ae96 100644 --- a/SignalServiceKit/src/SSKEnvironment.h +++ b/SignalServiceKit/src/SSKEnvironment.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWS2FAManager; @class OWSBatchMessageProcessor; @class OWSBlockingManager; +@class OWSDeliveryReceiptManager; @class OWSDisappearingMessagesJob; @class OWSIdentityManager; @class OWSMessageDecrypter; @@ -16,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWSMessageReceiver; @class OWSMessageSender; @class OWSPrimaryStorage; +@class OWSReadReceiptManager; @class TSAccountManager; @class TSNetworkManager; @class TSSocketManager; @@ -46,7 +48,9 @@ NS_ASSUME_NONNULL_BEGIN tsAccountManager:(TSAccountManager *)tsAccountManager ows2FAManager:(OWS2FAManager *)ows2FAManager disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob - contactDiscoveryService:(ContactDiscoveryService *)contactDiscoveryService NS_DESIGNATED_INITIALIZER; + contactDiscoveryService:(ContactDiscoveryService *)contactDiscoveryService + disappearingMessagesJob:(OWSReadReceiptManager *)readReceiptManager + contactDiscoveryService:(OWSDeliveryReceiptManager *)deliveryReceiptManager NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE; @@ -77,6 +81,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) OWS2FAManager *ows2FAManager; @property (nonatomic, readonly) OWSDisappearingMessagesJob *disappearingMessagesJob; @property (nonatomic, readonly) ContactDiscoveryService *contactDiscoveryService; +@property (nonatomic, readonly) OWSReadReceiptManager *readReceiptManager; +@property (nonatomic, readonly) OWSDeliveryReceiptManager *deliveryReceiptManager; // This property is configured after Environment is created. @property (atomic, nullable) id callMessageHandler; diff --git a/SignalServiceKit/src/SSKEnvironment.m b/SignalServiceKit/src/SSKEnvironment.m index 4a8ef5b91..92a471120 100644 --- a/SignalServiceKit/src/SSKEnvironment.m +++ b/SignalServiceKit/src/SSKEnvironment.m @@ -30,6 +30,8 @@ static SSKEnvironment *sharedSSKEnvironment; @property (nonatomic) OWS2FAManager *ows2FAManager; @property (nonatomic) OWSDisappearingMessagesJob *disappearingMessagesJob; @property (nonatomic) ContactDiscoveryService *contactDiscoveryService; +@property (nonatomic) OWSReadReceiptManager *readReceiptManager; +@property (nonatomic) OWSDeliveryReceiptManager *deliveryReceiptManager; @end @@ -58,7 +60,9 @@ static SSKEnvironment *sharedSSKEnvironment; tsAccountManager:(TSAccountManager *)tsAccountManager ows2FAManager:(OWS2FAManager *)ows2FAManager disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob - contactDiscoveryService:(ContactDiscoveryService *)contactDiscoveryService { + contactDiscoveryService:(ContactDiscoveryService *)contactDiscoveryService + disappearingMessagesJob:(OWSReadReceiptManager *)readReceiptManager + contactDiscoveryService:(OWSDeliveryReceiptManager *)deliveryReceiptManager { self = [super init]; if (!self) { return self; @@ -82,6 +86,8 @@ static SSKEnvironment *sharedSSKEnvironment; OWSAssertDebug(ows2FAManager); OWSAssertDebug(disappearingMessagesJob); OWSAssertDebug(contactDiscoveryService); + OWSAssertDebug(readReceiptManager); + OWSAssertDebug(deliveryReceiptManager); _contactsManager = contactsManager; _messageSender = messageSender; @@ -101,6 +107,8 @@ static SSKEnvironment *sharedSSKEnvironment; _ows2FAManager = ows2FAManager; _disappearingMessagesJob = disappearingMessagesJob; _contactDiscoveryService = contactDiscoveryService; + _readReceiptManager = readReceiptManager; + _deliveryReceiptManager = deliveryReceiptManager; return self; } diff --git a/SignalServiceKit/src/Tests/MockSSKEnvironment.m b/SignalServiceKit/src/Tests/MockSSKEnvironment.m index f33cfe558..b32eaebc7 100644 --- a/SignalServiceKit/src/Tests/MockSSKEnvironment.m +++ b/SignalServiceKit/src/Tests/MockSSKEnvironment.m @@ -7,6 +7,7 @@ #import "OWS2FAManager.h" #import "OWSBatchMessageProcessor.h" #import "OWSBlockingManager.h" +#import "OWSDeliveryReceiptManager.h" #import "OWSDisappearingMessagesJob.h" #import "OWSFakeCallMessageHandler.h" #import "OWSFakeContactsManager.h" @@ -20,6 +21,7 @@ #import "OWSMessageManager.h" #import "OWSMessageReceiver.h" #import "OWSPrimaryStorage.h" +#import "OWSReadReceiptManager.h" #import "TSAccountManager.h" #import "TSSocketManager.h" #import @@ -67,6 +69,9 @@ NS_ASSUME_NONNULL_BEGIN OWSDisappearingMessagesJob *disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithPrimaryStorage:primaryStorage]; ContactDiscoveryService *contactDiscoveryService = [[ContactDiscoveryService alloc] initDefault]; + OWSReadReceiptManager *readReceiptManager = [[OWSReadReceiptManager alloc] initWithPrimaryStorage:primaryStorage]; + OWSDeliveryReceiptManager *deliveryReceiptManager = + [[OWSDeliveryReceiptManager alloc] initWithPrimaryStorage:primaryStorage]; self = [super initWithContactsManager:contactsManager messageSender:messageSender @@ -85,7 +90,9 @@ NS_ASSUME_NONNULL_BEGIN tsAccountManager:tsAccountManager ows2FAManager:ows2FAManager disappearingMessagesJob:disappearingMessagesJob - contactDiscoveryService:contactDiscoveryService]; + contactDiscoveryService:contactDiscoveryService + disappearingMessagesJob:readReceiptManager + contactDiscoveryService:deliveryReceiptManager]; if (!self) { return nil; }