From d04f1e6e36b75acc7332421d528edd61d58db153 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Nov 2018 10:04:33 -0400 Subject: [PATCH 1/5] Add debug UI for multi-image sends. --- .../ViewControllers/DebugUI/DebugUIMessages.m | 42 ++++++++++++++++++- SignalMessaging/utils/ThreadUtil.h | 7 ++-- SignalMessaging/utils/ThreadUtil.m | 27 ++++++------ 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index ebab8c895..f82105167 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -127,6 +127,10 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ [DebugUIMessages sendNTextMessagesInThread:thread]; }], + [OWSTableItem itemWithTitle:@"Send multi-image messages" + actionBlock:^{ + [DebugUIMessages sendMultiImageMessageInThread:thread]; + }], [OWSTableItem itemWithTitle:@"Select Fake" actionBlock:^{ [DebugUIMessages selectFakeAction:thread]; @@ -246,7 +250,6 @@ NS_ASSUME_NONNULL_BEGIN [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.messageSenderJobQueue addMessage:syncGroupsRequestMessage transaction:transaction]; }]; - }], [OWSTableItem itemWithTitle:@"Message with stalled timer" actionBlock:^{ @@ -3357,7 +3360,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac // style them indistinguishably from a separate text message. attachment.captionText = [self randomCaptionText]; } - [ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil ignoreErrors:YES]; + [ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil]; } + (SSKProtoEnvelope *)createEnvelopeForThread:(TSThread *)thread @@ -4631,6 +4634,41 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac } } ++ (void)sendMultiImageMessageInThread:(TSThread *)thread +{ + OWSLogInfo(@""); + + const uint32_t kMinImageCount = 2; + const uint32_t kMaxImageCount = 10; + uint32_t imageCount = kMinImageCount + arc4random_uniform(kMaxImageCount - kMinImageCount); + + NSMutableArray *attachments = [NSMutableArray new]; + for (uint32_t i = 0; i < imageCount; i++) { + UIColor *imageColor = [UIColor colorWithRed:arc4random_uniform(256) / 255.f + green:arc4random_uniform(256) / 255.f + blue:arc4random_uniform(256) / 255.f + alpha:1.f]; + UIImage *image = [UIImage imageWithColor:imageColor size:CGSizeMake(10.f, 10.f)]; + OWSAssertDebug(image); + NSData *pngData = UIImagePNGRepresentation(image); + OWSAssertDebug(pngData); + NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"png"]; + [pngData writeToFile:filePath atomically:YES]; + OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:filePath]); + DataSource *dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:YES]; + SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource + dataUTI:(NSString *)kUTTypePNG + imageQuality:TSImageQualityOriginal]; + [attachments addObject:attachment]; + } + + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + TSOutgoingMessage *message = + [ThreadUtil enqueueMessageWithAttachments:attachments inThread:thread quotedReplyModel:nil]; + OWSLogError(@"timestamp: %llu.", message.timestamp); + }]; +} + #endif @end diff --git a/SignalMessaging/utils/ThreadUtil.h b/SignalMessaging/utils/ThreadUtil.h index e882e98a1..1afec1ba7 100644 --- a/SignalMessaging/utils/ThreadUtil.h +++ b/SignalMessaging/utils/ThreadUtil.h @@ -53,10 +53,9 @@ NS_ASSUME_NONNULL_BEGIN inThread:(TSThread *)thread quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel; -+ (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - ignoreErrors:(BOOL)ignoreErrors; ++ (TSOutgoingMessage *)enqueueMessageWithAttachments:(NSArray *)attachments + inThread:(TSThread *)thread + quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel; + (TSOutgoingMessage *)enqueueMessageWithContactShare:(OWSContact *)contactShare inThread:(TSThread *)thread; + (void)enqueueLeaveGroupMessageInThread:(TSGroupThread *)thread; diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index 87174ff80..51d78d3e5 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -93,35 +93,36 @@ NS_ASSUME_NONNULL_BEGIN inThread:(TSThread *)thread quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel { - return [self enqueueMessageWithAttachment:attachment - inThread:thread - quotedReplyModel:quotedReplyModel - ignoreErrors:NO]; + return [self enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:quotedReplyModel]; } -+ (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - ignoreErrors:(BOOL)ignoreErrors ++ (TSOutgoingMessage *)enqueueMessageWithAttachments:(NSArray *)attachments + inThread:(TSThread *)thread + quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel { OWSAssertIsOnMainThread(); - OWSAssertDebug(attachment); - OWSAssertDebug(!attachment.hasError); - OWSAssertDebug(attachment.mimeType.length > 0); + OWSAssertDebug(attachments.count > 0); OWSAssertDebug(thread); + for (SignalAttachment *attachment in attachments) { + OWSAssertDebug(!attachment.hasError); + OWSAssertDebug(attachment.mimeType.length > 0); + } OWSDisappearingMessagesConfiguration *configuration = [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId]; uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0); + BOOL isVoiceMessage = (attachments.count == 1 && attachments.lastObject.isVoiceMessage); + // TODO: Support multi-image captions. + NSString *_Nullable messageBody = attachments.lastObject.captionText; TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread - messageBody:attachment.captionText + messageBody:messageBody attachmentIds:[NSMutableArray new] expiresInSeconds:expiresInSeconds expireStartedAt:0 - isVoiceMessage:[attachment isVoiceMessage] + isVoiceMessage:isVoiceMessage groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:[quotedReplyModel buildQuotedMessageForSending] contactShare:nil]; From f6591fac257a19338ae0da4a549e42d149e92c41 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Nov 2018 11:33:05 -0400 Subject: [PATCH 2/5] Add debug UI for multi-image sends. --- .../ViewControllers/DebugUI/DebugUIMessages.m | 2 +- .../MediaGalleryViewController.swift | 3 +- .../ViewModels/OWSQuotedReplyModel.m | 2 +- .../attachments/SignalAttachment.swift | 5 + SignalMessaging/utils/ThreadUtil.m | 10 +- .../Messages/Attachments/TSAttachmentStream.h | 3 - .../Messages/Attachments/TSAttachmentStream.m | 21 ---- .../src/Messages/Interactions/OWSContact.m | 1 - .../src/Messages/Interactions/TSMessage.h | 4 +- .../src/Messages/Interactions/TSMessage.m | 64 ++++++---- .../Messages/Interactions/TSQuotedMessage.m | 3 +- .../src/Messages/OWSMessageSender.h | 28 ++++- .../src/Messages/OWSMessageSender.m | 109 +++++++++++------- .../src/Network/MessageSenderJobQueue.swift | 31 ++--- .../src/Storage/FullTextSearchFinder.swift | 24 +--- .../src/Storage/OWSMediaGalleryFinder.m | 19 +-- 16 files changed, 185 insertions(+), 144 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index f82105167..ad4a722f7 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -127,7 +127,7 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ [DebugUIMessages sendNTextMessagesInThread:thread]; }], - [OWSTableItem itemWithTitle:@"Send multi-image messages" + [OWSTableItem itemWithTitle:@"Send Multi-Image Message" actionBlock:^{ [DebugUIMessages sendMultiImageMessageInThread:thread]; }], diff --git a/Signal/src/ViewControllers/MediaGalleryViewController.swift b/Signal/src/ViewControllers/MediaGalleryViewController.swift index a222b7ec1..2319f74a2 100644 --- a/Signal/src/ViewControllers/MediaGalleryViewController.swift +++ b/Signal/src/ViewControllers/MediaGalleryViewController.swift @@ -634,7 +634,8 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel var hasFetchedMostRecent = false func buildGalleryItem(message: TSMessage, transaction: YapDatabaseReadTransaction) -> MediaGalleryItem? { - guard let attachmentStream = message.attachment(with: transaction) as? TSAttachmentStream else { + // TODO: Support multi-image messages. + guard let attachmentStream = message.attachments(with: transaction).first as? TSAttachmentStream else { owsFailDebug("attachment was unexpectedly empty") return nil } diff --git a/SignalMessaging/ViewModels/OWSQuotedReplyModel.m b/SignalMessaging/ViewModels/OWSQuotedReplyModel.m index b7be0720e..ec31ccb10 100644 --- a/SignalMessaging/ViewModels/OWSQuotedReplyModel.m +++ b/SignalMessaging/ViewModels/OWSQuotedReplyModel.m @@ -167,7 +167,7 @@ NS_ASSUME_NONNULL_BEGIN BOOL hasText = quotedText.length > 0; BOOL hasAttachment = NO; - TSAttachment *_Nullable attachment = [message attachmentWithTransaction:transaction]; + TSAttachment *_Nullable attachment = [message attachmentsWithTransaction:transaction].firstObject; TSAttachmentStream *quotedAttachment; if (attachment && [attachment isKindOfClass:[TSAttachmentStream class]]) { diff --git a/SignalMessaging/attachments/SignalAttachment.swift b/SignalMessaging/attachments/SignalAttachment.swift index c41370a80..0953efe5b 100644 --- a/SignalMessaging/attachments/SignalAttachment.swift +++ b/SignalMessaging/attachments/SignalAttachment.swift @@ -239,6 +239,11 @@ public class SignalAttachment: NSObject { return errorDescription } + @objc + public var outgoingAttachmentInfo: OutgoingAttachmentInfo { + return OutgoingAttachmentInfo(dataSource: dataSource, contentType: mimeType, sourceFilename: filenameOrDefault) + } + @objc public func image() -> UIImage? { if let cachedImage = cachedImage { diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index 51d78d3e5..3952e97ce 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -127,11 +127,11 @@ NS_ASSUME_NONNULL_BEGIN quotedMessage:[quotedReplyModel buildQuotedMessageForSending] contactShare:nil]; - [self.messageSenderJobQueue addMediaMessage:message - dataSource:attachment.dataSource - contentType:attachment.mimeType - sourceFilename:attachment.filenameOrDefault - isTemporaryAttachment:NO]; + NSMutableArray *attachmentInfos = [NSMutableArray new]; + for (SignalAttachment *attachment in attachments) { + [attachmentInfos addObject:attachment.outgoingAttachmentInfo]; + } + [self.messageSenderJobQueue addMediaMessage:message attachmentInfos:attachmentInfos isTemporaryAttachment:NO]; return message; } diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h index 06ad4f80f..553619328 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h @@ -60,9 +60,6 @@ typedef void (^OWSThumbnailFailure)(void); - (BOOL)writeData:(NSData *)data error:(NSError **)error; - (BOOL)writeDataSource:(DataSource *)dataSource; -- (BOOL)isOversizeText; -- (nullable NSString *)readOversizeText; - + (void)deleteAttachments; + (NSString *)attachmentsFolder; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index ccdf0d407..cc19429f9 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -630,27 +630,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); return [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId]; } -- (BOOL)isOversizeText -{ - return [self.contentType isEqualToString:OWSMimeTypeOversizeTextMessage]; -} - -- (nullable NSString *)readOversizeText -{ - if (!self.isOversizeText) { - OWSFailDebug(@"oversize text attachment has unexpected content type."); - return nil; - } - NSError *error; - NSData *_Nullable data = [self readDataFromFileWithError:&error]; - if (error || !data) { - OWSFailDebug(@"could not read oversize text attachment: %@.", error); - return nil; - } - NSString *_Nullable string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - return string; -} - #pragma mark - Thumbnails - (nullable UIImage *)thumbnailImageWithSizeHint:(CGSize)sizeHint diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index 80c9d9bb2..1a4aa9485 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -489,7 +489,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) return [TSAttachment fetchObjectWithUniqueID:self.avatarAttachmentId transaction:transaction]; } - - (void)saveAvatarImage:(UIImage *)image transaction:(YapDatabaseReadWriteTransaction *)transaction { NSData *imageData = UIImageJPEGRepresentation(image, (CGFloat)0.9); diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.h b/SignalServiceKit/src/Messages/Interactions/TSMessage.h index 869ccdc41..99273bda4 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.h @@ -41,9 +41,11 @@ NS_ASSUME_NONNULL_BEGIN - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - (BOOL)hasAttachments; -- (nullable TSAttachment *)attachmentWithTransaction:(YapDatabaseReadTransaction *)transaction; +- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction; - (void)setQuotedMessageThumbnailAttachmentStream:(TSAttachmentStream *)attachmentStream; + +- (nullable NSString *)oversizeTextWithTransaction:(YapDatabaseReadTransaction *)transaction; - (nullable NSString *)bodyTextWithTransaction:(YapDatabaseReadTransaction *)transaction; - (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index 78381f9f8..7182a0e8d 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -199,14 +199,19 @@ static const NSUInteger OWSMessageSchemaVersion = 4; return self.attachmentIds ? (self.attachmentIds.count > 0) : NO; } -- (nullable TSAttachment *)attachmentWithTransaction:(YapDatabaseReadTransaction *)transaction +- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction { - if (!self.hasAttachments) { - return nil; + NSMutableArray *attachments = [NSMutableArray new]; + for (NSString *attachmentId in self.attachmentIds) { + TSAttachment *_Nullable attachment = + [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; + if (attachment) { + [attachments addObject:attachment]; + } else { + OWSFailDebug(@"Missing attachment for: %@.", attachmentId); + } } - - OWSAssertDebug(self.attachmentIds.count == 1); - return [TSAttachment fetchObjectWithUniqueID:self.attachmentIds.firstObject transaction:transaction]; + return [attachments copy]; } - (NSString *)debugDescription @@ -223,23 +228,40 @@ static const NSUInteger OWSMessageSchemaVersion = 4; } } +- (nullable NSString *)oversizeTextWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + if (self.attachmentIds.count != 1) { + return nil; + } + + TSAttachment *_Nullable attachment = [self attachmentsWithTransaction:transaction].firstObject; + OWSAssertDebug(attachment); + + if (![OWSMimeTypeOversizeTextMessage isEqualToString:attachment.contentType] + || ![attachment isKindOfClass:TSAttachmentStream.class]) { + return nil; + } + + TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; + + NSData *_Nullable data = [NSData dataWithContentsOfFile:attachmentStream.originalFilePath]; + if (!data) { + OWSFailDebug(@"Can't load oversize text data."); + return nil; + } + NSString *_Nullable text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (!text) { + OWSFailDebug(@"Can't parse oversize text data."); + return nil; + } + return text.filterStringForDisplay; +} + - (nullable NSString *)bodyTextWithTransaction:(YapDatabaseReadTransaction *)transaction { - if (self.hasAttachments) { - TSAttachment *_Nullable attachment = [self attachmentWithTransaction:transaction]; - - if ([OWSMimeTypeOversizeTextMessage isEqualToString:attachment.contentType] && - [attachment isKindOfClass:TSAttachmentStream.class]) { - TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; - - NSData *_Nullable data = [NSData dataWithContentsOfFile:attachmentStream.originalFilePath]; - if (data) { - NSString *_Nullable text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (text) { - return text.filterStringForDisplay; - } - } - } + NSString *_Nullable oversizeText = [self oversizeTextWithTransaction:transaction]; + if (oversizeText) { + return oversizeText; } if (self.body.length > 0) { diff --git a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m index 27a6a408a..5bb9bd265 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m @@ -253,7 +253,8 @@ NS_ASSUME_NONNULL_BEGIN return nil; } - TSAttachment *attachment = [quotedMessage attachmentWithTransaction:transaction]; + // We quote _the first_ attachment, if any. + TSAttachment *_Nullable attachment = [quotedMessage attachmentsWithTransaction:transaction].firstObject; if (![attachment isKindOfClass:[TSAttachmentStream class]]) { return nil; } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.h b/SignalServiceKit/src/Messages/OWSMessageSender.h index a7b182ebc..483d75c0b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.h +++ b/SignalServiceKit/src/Messages/OWSMessageSender.h @@ -33,6 +33,23 @@ typedef void (^RetryableFailureHandler)(NSError *_Nonnull error); #pragma mark - +NS_SWIFT_NAME(OutgoingAttachmentInfo) +@interface OWSOutgoingAttachmentInfo : NSObject + +@property (nonatomic, readonly) DataSource *dataSource; +@property (nonatomic, readonly) NSString *contentType; +@property (nonatomic, readonly, nullable) NSString *sourceFilename; + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithDataSource:(DataSource *)dataSource + contentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename NS_DESIGNATED_INITIALIZER; + +@end + +#pragma mark - + NS_SWIFT_NAME(MessageSender) @interface OWSMessageSender : NSObject @@ -71,6 +88,8 @@ NS_SWIFT_NAME(MessageSender) @end +#pragma mark - + @interface OutgoingMessagePreparer : NSObject /// Persists all necessary data to disk before sending, e.g. generate thumbnails @@ -80,11 +99,10 @@ NS_SWIFT_NAME(MessageSender) transaction:(YapDatabaseReadWriteTransaction *)transaction; /// Writes attachment to disk and applies original filename to message attributes -+ (void)prepareAttachmentWithDataSource:(DataSource *)dataSource - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - inMessage:(TSOutgoingMessage *)outgoingMessage - completionHandler:(void (^)(NSError *_Nullable error))completionHandler; ++ (void)prepareAttachments:(NSArray *)attachmentInfos + inMessage:(TSOutgoingMessage *)outgoingMessage + completionHandler:(void (^)(NSError *_Nullable error))completionHandler + NS_SWIFT_NAME(prepareAttachments(_:inMessage:completionHandler:)); @end diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 737a57b4f..9edc3a6a9 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -81,6 +81,28 @@ void AssertIsOnSendingQueue() #pragma mark - +@implementation OWSOutgoingAttachmentInfo + +- (instancetype)initWithDataSource:(DataSource *)dataSource + contentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename +{ + self = [super init]; + if (!self) { + return self; + } + + _dataSource = dataSource; + _contentType = contentType; + _sourceFilename = sourceFilename; + + return self; +} + +@end + +#pragma mark - + /** * OWSSendMessageOperation encapsulates all the work associated with sending a message, e.g. uploading attachments, * getting proper keys, and retrying upon failure. @@ -156,13 +178,14 @@ void AssertIsOnSendingQueue() // Sanity check preconditions if (self.message.hasAttachments) { - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * transaction) { - TSAttachmentStream *attachmentStream - = (TSAttachmentStream *)[self.message attachmentWithTransaction:transaction]; - OWSAssertDebug(attachmentStream); - OWSAssertDebug([attachmentStream isKindOfClass:[TSAttachmentStream class]]); - OWSAssertDebug(attachmentStream.serverId); - OWSAssertDebug(attachmentStream.isUploaded); + [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + for (TSAttachment *attachment in [self.message attachmentsWithTransaction:transaction]) { + OWSAssertDebug([attachment isKindOfClass:[TSAttachmentStream class]]); + TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; + OWSAssertDebug(attachmentStream); + OWSAssertDebug(attachmentStream.serverId); + OWSAssertDebug(attachmentStream.isUploaded); + } }]; } @@ -431,17 +454,18 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; failure:(void (^)(NSError *error))failureHandler { OWSAssertDebug(dataSource); - [OutgoingMessagePreparer prepareAttachmentWithDataSource:dataSource - contentType:contentType - sourceFilename:sourceFilename - inMessage:message - completionHandler:^(NSError *_Nullable error) { - if (error) { - failureHandler(error); - return; - } - [self sendMessage:message success:successHandler failure:failureHandler]; - }]; + OWSOutgoingAttachmentInfo *attachmentInfo = [[OWSOutgoingAttachmentInfo alloc] initWithDataSource:dataSource + contentType:contentType + sourceFilename:sourceFilename]; + [OutgoingMessagePreparer prepareAttachments:@[ attachmentInfo ] + inMessage:message + completionHandler:^(NSError *_Nullable error) { + if (error) { + failureHandler(error); + return; + } + [self sendMessage:message success:successHandler failure:failureHandler]; + }]; } - (void)sendMessageToService:(TSOutgoingMessage *)message @@ -1768,35 +1792,42 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [message updateWithMarkingAllUnsentRecipientsAsSendingWithTransaction:transaction]; } -+ (void)prepareAttachmentWithDataSource:(DataSource *)dataSource - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - inMessage:(TSOutgoingMessage *)outgoingMessage - completionHandler:(void (^)(NSError *_Nullable error))completionHandler ++ (void)prepareAttachments:(NSArray *)attachmentInfos + inMessage:(TSOutgoingMessage *)outgoingMessage + completionHandler:(void (^)(NSError *_Nullable error))completionHandler { - OWSAssertDebug(dataSource); + OWSAssertDebug(attachmentInfos.count > 0); + OWSAssertDebug(outgoingMessage); dispatch_async([OWSDispatch attachmentsQueue], ^{ - TSAttachmentStream *attachmentStream = - [[TSAttachmentStream alloc] initWithContentType:contentType - byteCount:(UInt32)dataSource.dataLength - sourceFilename:sourceFilename]; - if (outgoingMessage.isVoiceMessage) { - attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage; - } + NSMutableArray *attachmentStreams = [NSMutableArray new]; + for (OWSOutgoingAttachmentInfo *attachmentInfo in attachmentInfos) { + TSAttachmentStream *attachmentStream = + [[TSAttachmentStream alloc] initWithContentType:attachmentInfo.contentType + byteCount:(UInt32)attachmentInfo.dataSource.dataLength + sourceFilename:attachmentInfo.sourceFilename]; + if (outgoingMessage.isVoiceMessage) { + attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage; + } - if (![attachmentStream writeDataSource:dataSource]) { - OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotWriteAttachment]); - NSError *error = OWSErrorMakeWriteAttachmentDataError(); - completionHandler(error); + if (![attachmentStream writeDataSource:attachmentInfo.dataSource]) { + OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotWriteAttachment]); + NSError *error = OWSErrorMakeWriteAttachmentDataError(); + completionHandler(error); + return; + } + + [attachmentStreams addObject:attachmentStream]; } [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [attachmentStream saveWithTransaction:transaction]; + for (TSAttachmentStream *attachmentStream in attachmentStreams) { + [attachmentStream saveWithTransaction:transaction]; - [outgoingMessage.attachmentIds addObject:attachmentStream.uniqueId]; - if (sourceFilename) { - outgoingMessage.attachmentFilenameMap[attachmentStream.uniqueId] = sourceFilename; + [outgoingMessage.attachmentIds addObject:attachmentStream.uniqueId]; + if (attachmentStream.sourceFilename) { + outgoingMessage.attachmentFilenameMap[attachmentStream.uniqueId] = attachmentStream.sourceFilename; + } } [outgoingMessage saveWithTransaction:transaction]; }]; diff --git a/SignalServiceKit/src/Network/MessageSenderJobQueue.swift b/SignalServiceKit/src/Network/MessageSenderJobQueue.swift index 7976a3a0f..755f6ecdb 100644 --- a/SignalServiceKit/src/Network/MessageSenderJobQueue.swift +++ b/SignalServiceKit/src/Network/MessageSenderJobQueue.swift @@ -34,20 +34,25 @@ public class MessageSenderJobQueue: NSObject, JobQueue { @objc(addMediaMessage:dataSource:contentType:sourceFilename:isTemporaryAttachment:) public func add(mediaMessage: TSOutgoingMessage, dataSource: DataSource, contentType: String, sourceFilename: String?, isTemporaryAttachment: Bool) { - OutgoingMessagePreparer.prepareAttachment(with: dataSource, - contentType: contentType, - sourceFilename: sourceFilename, - in: mediaMessage) { error in - if let error = error { - self.dbConnection.readWrite { transaction in - mediaMessage.update(sendingError: error, transaction: transaction) - } - } else { - self.dbConnection.readWrite { transaction in - self.add(message: mediaMessage, removeMessageAfterSending: isTemporaryAttachment, transaction: transaction) - } + let attachmentInfo = OutgoingAttachmentInfo(dataSource: dataSource, contentType: contentType, sourceFilename: sourceFilename) + add(mediaMessage: mediaMessage, attachmentInfos: [attachmentInfo], isTemporaryAttachment: isTemporaryAttachment) + } + + @objc(addMediaMessage:attachmentInfos:isTemporaryAttachment:) + public func add(mediaMessage: TSOutgoingMessage, attachmentInfos: [OutgoingAttachmentInfo], isTemporaryAttachment: Bool) { + OutgoingMessagePreparer.prepareAttachments(attachmentInfos, + inMessage: mediaMessage, + completionHandler: { error in + if let error = error { + self.dbConnection.readWrite { transaction in + mediaMessage.update(sendingError: error, transaction: transaction) } - } + } else { + self.dbConnection.readWrite { transaction in + self.add(message: mediaMessage, removeMessageAfterSending: isTemporaryAttachment, transaction: transaction) + } + } + }) } private func add(message: TSOutgoingMessage, removeMessageAfterSending: Bool, transaction: YapDatabaseReadWriteTransaction) { diff --git a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift index 1ccf7f988..626304e92 100644 --- a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift +++ b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift @@ -204,29 +204,7 @@ public class FullTextSearchFinder: NSObject { } private static func oversizeText(forMessage message: TSMessage, transaction: YapDatabaseReadTransaction) -> String? { - guard message.hasAttachments() else { - return nil - } - - guard let attachment = message.attachment(with: transaction) else { - owsFailDebug("attachment was unexpectedly nil") - return nil - } - - guard let attachmentStream = attachment as? TSAttachmentStream else { - return nil - } - - guard attachmentStream.isOversizeText() else { - return nil - } - - guard let text = attachmentStream.readOversizeText() else { - owsFailDebug("Could not load oversize text attachment") - return nil - } - - return text + return message.oversizeText(with: transaction) } private class func indexContent(object: Any, transaction: YapDatabaseReadTransaction) -> String? { diff --git a/SignalServiceKit/src/Storage/OWSMediaGalleryFinder.m b/SignalServiceKit/src/Storage/OWSMediaGalleryFinder.m index 4c9c0a11e..b3a0b3919 100644 --- a/SignalServiceKit/src/Storage/OWSMediaGalleryFinder.m +++ b/SignalServiceKit/src/Storage/OWSMediaGalleryFinder.m @@ -147,17 +147,20 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin return nil; } TSMessage *message = (TSMessage *)object; - - OWSAssertDebug(message.attachmentIds.count <= 1); - NSString *attachmentId = message.attachmentIds.firstObject; - if (attachmentId.length == 0) { - return nil; + + BOOL allAttachmentsAreMedia = message.attachmentIds.count > 0; + for (NSString *attachmentId in message.attachmentIds) { + OWSAssertDebug(attachmentId.length > 0); + if (![self attachmentIdShouldAppearInMediaGallery:attachmentId transaction:transaction]) { + allAttachmentsAreMedia = NO; + break; + } } - - if ([self attachmentIdShouldAppearInMediaGallery:attachmentId transaction:transaction]) { + + if (allAttachmentsAreMedia) { return [self mediaGroupWithThreadId:message.uniqueThreadId]; } - + return nil; }]; From ecba67b511e7d8a8e5125533d93fd0d201825f8c Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Nov 2018 11:37:35 -0400 Subject: [PATCH 3/5] Add debug UI for multi-image sends. --- .../ConversationView/ConversationViewItem.m | 1 + .../src/ViewControllers/MessageDetailViewController.swift | 1 + .../ViewControllers/SharingThreadPickerViewController.m | 1 + SignalServiceKit/src/Messages/OWSMessageSender.m | 7 +++---- SignalShareExtension/ShareViewController.swift | 1 + 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m index ddfa18d34..be855291b 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m @@ -481,6 +481,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) if (message.attachmentIds.count == 0) { return nil; } + // TODO: Support multi-image messages. NSString *_Nullable attachmentId = message.attachmentIds.firstObject; if (attachmentId.length == 0) { return nil; diff --git a/Signal/src/ViewControllers/MessageDetailViewController.swift b/Signal/src/ViewControllers/MessageDetailViewController.swift index 005f9a426..d026a050f 100644 --- a/Signal/src/ViewControllers/MessageDetailViewController.swift +++ b/Signal/src/ViewControllers/MessageDetailViewController.swift @@ -398,6 +398,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele } private func fetchAttachment(transaction: YapDatabaseReadTransaction) -> TSAttachment? { + // TODO: Support multi-image messages. guard let attachmentId = message.attachmentIds.firstObject as? String else { return nil } diff --git a/SignalMessaging/ViewControllers/SharingThreadPickerViewController.m b/SignalMessaging/ViewControllers/SharingThreadPickerViewController.m index 1ba5c8189..f4fcb51a6 100644 --- a/SignalMessaging/ViewControllers/SharingThreadPickerViewController.m +++ b/SignalMessaging/ViewControllers/SharingThreadPickerViewController.m @@ -579,6 +579,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); return; } + // TODO: Support multi-image messages. NSString *_Nullable attachmentRecordId = self.outgoingMessage.attachmentIds.firstObject; if (!attachmentRecordId) { OWSLogDebug(@"Ignoring upload progress until outgoing message has an attachment record id"); diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 9edc3a6a9..613bc1407 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -376,11 +376,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; success:successHandler failure:failureHandler]; - // TODO de-dupe attachment enque logic. - if (message.hasAttachments) { + // TODO: de-dupe attachment enqueue logic. + for (NSString *attachmentId in message.attachmentIds) { OWSUploadOperation *uploadAttachmentOperation = - [[OWSUploadOperation alloc] initWithAttachmentId:message.attachmentIds.firstObject - dbConnection:self.dbConnection]; + [[OWSUploadOperation alloc] initWithAttachmentId:attachmentId dbConnection:self.dbConnection]; [sendMessageOperation addDependency:uploadAttachmentOperation]; [sendingQueue addOperation:uploadAttachmentOperation]; } diff --git a/SignalShareExtension/ShareViewController.swift b/SignalShareExtension/ShareViewController.swift index 38c42875e..7dbe23962 100644 --- a/SignalShareExtension/ShareViewController.swift +++ b/SignalShareExtension/ShareViewController.swift @@ -609,6 +609,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed } // Prefer a URL provider if available + // TODO: Support multi-image messages. if let preferredAttachment = attachments.first(where: { (attachment: Any) -> Bool in guard let itemProvider = attachment as? NSItemProvider else { return false From 47fda2e3774751e9fd776dc50db663ea83ea4a25 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Nov 2018 12:11:15 -0400 Subject: [PATCH 4/5] Add debug UI for multi-image sends. --- .../ConversationViewController.m | 6 ++- .../src/Devices/OWSRecordTranscriptJob.h | 2 +- .../src/Devices/OWSRecordTranscriptJob.m | 6 ++- .../Attachments/OWSAttachmentsProcessor.h | 4 +- .../Attachments/OWSAttachmentsProcessor.m | 50 ++++++++++++++++--- .../src/Messages/OWSMessageManager.m | 50 +++++++++++-------- 6 files changed, 84 insertions(+), 34 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 571ae69ef..8bea0709c 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -1650,7 +1650,7 @@ typedef enum : NSUInteger { networkManager:self.networkManager]; [processor fetchAttachmentsForMessage:message primaryStorage:self.primaryStorage - success:^(TSAttachmentStream *attachmentStream) { + success:^(NSArray *attachmentStreams) { OWSLogInfo(@"Successfully redownloaded attachment in thread: %@", message.thread); } failure:^(NSError *error) { @@ -2208,7 +2208,9 @@ typedef enum : NSUInteger { [self.editingDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [processor fetchAttachmentsForMessage:nil transaction:transaction - success:^(TSAttachmentStream *attachmentStream) { + success:^(NSArray *attachmentStreams) { + OWSAssertDebug(attachmentStreams.count == 1); + TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; [self.editingDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) { [message setQuotedMessageThumbnailAttachmentStream:attachmentStream]; diff --git a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.h b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.h index b6bac2b07..83892e887 100644 --- a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.h +++ b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN contactsManager:(id)contactsManager NS_DESIGNATED_INITIALIZER; -- (void)runWithAttachmentHandler:(void (^)(TSAttachmentStream *attachmentStream))attachmentHandler +- (void)runWithAttachmentHandler:(void (^)(NSArray *attachmentStreams))attachmentHandler transaction:(YapDatabaseReadWriteTransaction *)transaction; @end diff --git a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m index a376dce94..2875b9a47 100644 --- a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m +++ b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m @@ -59,7 +59,7 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (void)runWithAttachmentHandler:(void (^)(TSAttachmentStream *attachmentStream))attachmentHandler +- (void)runWithAttachmentHandler:(void (^)(NSArray *attachmentStreams))attachmentHandler transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssertDebug(transaction); @@ -112,7 +112,9 @@ NS_ASSUME_NONNULL_BEGIN OWSLogDebug(@"downloading thumbnail for transcript: %lu", (unsigned long)transcript.timestamp); [attachmentProcessor fetchAttachmentsForMessage:outgoingMessage transaction:transaction - success:^(TSAttachmentStream *_Nonnull attachmentStream) { + success:^(NSArray *attachmentStreams) { + OWSAssertDebug(attachmentStreams.count == 1); + TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; [self.primaryStorage.newDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [outgoingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream]; diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h index 30bfd0f1d..effbbec23 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h @@ -41,11 +41,11 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey; - (void)fetchAttachmentsForMessage:(nullable TSMessage *)message primaryStorage:(OWSPrimaryStorage *)primaryStorage - success:(void (^)(TSAttachmentStream *attachmentStream))successHandler + success:(void (^)(NSArray *attachmentStreams))successHandler failure:(void (^)(NSError *error))failureHandler; - (void)fetchAttachmentsForMessage:(nullable TSMessage *)message transaction:(YapDatabaseReadWriteTransaction *)transaction - success:(void (^)(TSAttachmentStream *attachmentStream))successHandler + success:(void (^)(NSArray *attachmentStreams))successHandler failure:(void (^)(NSError *error))failureHandler; @end diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m index a9c08fae2..941388d0a 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m @@ -20,6 +20,7 @@ #import "TSMessage.h" #import "TSNetworkManager.h" #import "TSThread.h" +#import #import #import #import @@ -93,7 +94,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f; // PERF: Remove this and use a pre-existing dbConnection - (void)fetchAttachmentsForMessage:(nullable TSMessage *)message primaryStorage:(OWSPrimaryStorage *)primaryStorage - success:(void (^)(TSAttachmentStream *attachmentStream))successHandler + success:(void (^)(NSArray *attachmentStreams))successHandler failure:(void (^)(NSError *error))failureHandler { [[primaryStorage newDatabaseConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { @@ -106,18 +107,53 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f; - (void)fetchAttachmentsForMessage:(nullable TSMessage *)message transaction:(YapDatabaseReadWriteTransaction *)transaction - success:(void (^)(TSAttachmentStream *attachmentStream))successHandler + success:(void (^)(NSArray *attachmentStreams))successHandler failure:(void (^)(NSError *error))failureHandler { OWSAssertDebug(transaction); + OWSAssertDebug(self.attachmentPointers.count > 0); + + NSMutableArray *promises = [NSMutableArray array]; + NSMutableArray *attachmentStreams = [NSMutableArray array]; for (TSAttachmentPointer *attachmentPointer in self.attachmentPointers) { - [self retrieveAttachment:attachmentPointer - message:message - transaction:transaction - success:successHandler - failure:failureHandler]; + AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { + [self retrieveAttachment:attachmentPointer + message:message + transaction:transaction + success:^(TSAttachmentStream *attachmentStream) { + OWSLogVerbose(@"Attachment download succeeded."); + @synchronized(attachmentStreams) { + [attachmentStreams addObject:attachmentStream]; + } + resolve(@(1)); + } + failure:^(NSError *error) { + OWSLogError(@"Attachment download failed with error: %@", error); + resolve(error); + }]; + }]; + [promises addObject:promise]; } + + // We use PMKJoin(), not PMKWhen(), because we don't want the + // completion promise to execute until _all_ promises + // have either succeeded or failed. PMKWhen() executes as + // soon as any of its input promises fail. + AnyPromise *completionPromise + = PMKJoin(promises) + .then(^(id value) { + NSArray *attachmentStreamsCopy; + @synchronized(attachmentStreams) { + attachmentStreamsCopy = [attachmentStreams copy]; + } + OWSLogInfo(@"Attachment downloads succeeded: %lu.", (unsigned long)attachmentStreamsCopy.count); + successHandler(attachmentStreamsCopy); + }) + .catch(^(NSError *error) { + failureHandler(error); + }); + [completionPromise retainUntilComplete]; } - (void)retrieveAttachment:(TSAttachmentPointer *)attachment diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 130116e79..39fee3fac 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -731,7 +731,9 @@ NS_ASSUME_NONNULL_BEGIN } [attachmentsProcessor fetchAttachmentsForMessage:nil transaction:transaction - success:^(TSAttachmentStream *attachmentStream) { + success:^(NSArray *attachmentStreams) { + OWSAssertDebug(attachmentStreams.count == 1); + TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; [groupThread updateAvatarWithAttachmentStream:attachmentStream]; } failure:^(NSError *error) { @@ -786,8 +788,10 @@ NS_ASSUME_NONNULL_BEGIN [attachmentsProcessor fetchAttachmentsForMessage:createdMessage transaction:transaction - success:^(TSAttachmentStream *attachmentStream) { - OWSLogDebug(@"successfully fetched attachment: %@ for message: %@", attachmentStream, createdMessage); + success:^(NSArray *attachmentStreams) { + OWSLogDebug(@"successfully fetched attachments: %lu for message: %@", + (unsigned long)attachmentStreams.count, + createdMessage); } failure:^(NSError *error) { OWSLogError(@"failed to fetch attachments for message: %@ with error: %@", createdMessage, error); @@ -843,23 +847,27 @@ NS_ASSUME_NONNULL_BEGIN } if ([self isDataMessageGroupAvatarUpdate:syncMessage.sent.message]) { - [recordJob runWithAttachmentHandler:^(TSAttachmentStream *attachmentStream) { - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSGroupThread *_Nullable groupThread = - [TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction]; - if (!groupThread) { - OWSFailDebug(@"ignoring sync group avatar update for unknown group."); - return; - } - - [groupThread updateAvatarWithAttachmentStream:attachmentStream transaction:transaction]; - }]; - } - transaction:transaction]; + [recordJob + runWithAttachmentHandler:^(NSArray *attachmentStreams) { + OWSAssertDebug(attachmentStreams.count == 1); + TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + TSGroupThread *_Nullable groupThread = + [TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction]; + if (!groupThread) { + OWSFailDebug(@"ignoring sync group avatar update for unknown group."); + return; + } + + [groupThread updateAvatarWithAttachmentStream:attachmentStream transaction:transaction]; + }]; + } + transaction:transaction]; } else { [recordJob - runWithAttachmentHandler:^(TSAttachmentStream *attachmentStream) { - OWSLogDebug(@"successfully fetched transcript attachment: %@", attachmentStream); + runWithAttachmentHandler:^(NSArray *attachmentStreams) { + OWSLogDebug( + @"successfully fetched transcript attachments: %lu", (unsigned long)attachmentStreams.count); } transaction:transaction]; } @@ -1350,7 +1358,9 @@ NS_ASSUME_NONNULL_BEGIN OWSLogDebug(@"downloading thumbnail for message: %lu", (unsigned long)incomingMessage.timestamp); [attachmentProcessor fetchAttachmentsForMessage:incomingMessage transaction:transaction - success:^(TSAttachmentStream *attachmentStream) { + success:^(NSArray *attachmentStreams) { + OWSAssertDebug(attachmentStreams.count == 1); + TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; [self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [incomingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream]; [incomingMessage saveWithTransaction:transaction]; @@ -1379,7 +1389,7 @@ NS_ASSUME_NONNULL_BEGIN OWSLogDebug(@"downloading contact avatar for message: %lu", (unsigned long)incomingMessage.timestamp); [attachmentProcessor fetchAttachmentsForMessage:incomingMessage transaction:transaction - success:^(TSAttachmentStream *attachmentStream) { + success:^(NSArray *attachmentStreams) { [self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [incomingMessage touchWithTransaction:transaction]; }]; From c7d427029bffda052989345de58a471d32a86781 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Nov 2018 13:17:36 -0400 Subject: [PATCH 5/5] Respond to CR. --- SignalMessaging/utils/ThreadUtil.m | 6 +++++- .../src/Storage/FullTextSearchFinder.swift | 11 ++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index 3952e97ce..c7a3a296a 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -93,7 +93,11 @@ NS_ASSUME_NONNULL_BEGIN inThread:(TSThread *)thread quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel { - return [self enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:quotedReplyModel]; + return [self enqueueMessageWithAttachments:@[ + attachment, + ] + inThread:thread + quotedReplyModel:quotedReplyModel]; } + (TSOutgoingMessage *)enqueueMessageWithAttachments:(NSArray *)attachments diff --git a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift index 626304e92..53e3e7147 100644 --- a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift +++ b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift @@ -194,19 +194,12 @@ public class FullTextSearchFinder: NSObject { } private static let messageIndexer: SearchIndexer = SearchIndexer { (message: TSMessage, transaction: YapDatabaseReadTransaction) in - if let body = message.body, body.count > 0 { - return body - } - if let oversizeText = oversizeText(forMessage: message, transaction: transaction) { - return oversizeText + if let bodyText = message.bodyText(with: transaction) { + return bodyText } return "" } - private static func oversizeText(forMessage message: TSMessage, transaction: YapDatabaseReadTransaction) -> String? { - return message.oversizeText(with: transaction) - } - private class func indexContent(object: Any, transaction: YapDatabaseReadTransaction) -> String? { if let groupThread = object as? TSGroupThread { return self.groupThreadIndexer.index(groupThread, transaction: transaction)