From 90e7df55154649fda8d2420b1901b130a81d503b Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Nov 2018 11:38:29 -0500 Subject: [PATCH 1/6] Use attachment pointers to restore attachments from backup. --- Signal/src/util/Backup/OWSBackup.h | 2 +- Signal/src/util/Backup/OWSBackup.m | 33 ++++------ Signal/src/util/Backup/OWSBackupImportJob.m | 9 ++- .../src/Messages/Attachments/TSAttachment.h | 9 ++- .../src/Messages/Attachments/TSAttachment.m | 29 +++++++++ .../Attachments/TSAttachmentPointer.h | 32 +++++++-- .../Attachments/TSAttachmentPointer.m | 65 +++++++++++++++++++ .../Messages/Attachments/TSAttachmentStream.h | 10 --- .../Messages/Attachments/TSAttachmentStream.m | 47 -------------- SignalServiceKit/src/Storage/TSDatabaseView.m | 54 +++++++-------- 10 files changed, 178 insertions(+), 112 deletions(-) diff --git a/Signal/src/util/Backup/OWSBackup.h b/Signal/src/util/Backup/OWSBackup.h index e7a1d1476..6cb703ac4 100644 --- a/Signal/src/util/Backup/OWSBackup.h +++ b/Signal/src/util/Backup/OWSBackup.h @@ -79,7 +79,7 @@ typedef NS_ENUM(NSUInteger, OWSBackupState) { - (NSArray *)attachmentIdsForLazyRestore; -- (void)lazyRestoreAttachment:(TSAttachmentStream *)attachment +- (void)lazyRestoreAttachment:(TSAttachmentPointer *)attachment backupIO:(OWSBackupIO *)backupIO completion:(OWSBackupBoolBlock)completion; diff --git a/Signal/src/util/Backup/OWSBackup.m b/Signal/src/util/Backup/OWSBackup.m index 9069f7fc7..b3288c510 100644 --- a/Signal/src/util/Backup/OWSBackup.m +++ b/Signal/src/util/Backup/OWSBackup.m @@ -500,18 +500,18 @@ NS_ASSUME_NONNULL_BEGIN [ext enumerateKeysAndObjectsInGroup:TSLazyRestoreAttachmentsGroup usingBlock:^( NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { - if (![object isKindOfClass:[TSAttachmentStream class]]) { + if (![object isKindOfClass:[TSAttachmentPointer class]]) { OWSFailDebug( @"Unexpected object: %@ in collection:%@", [object class], collection); return; } - TSAttachmentStream *attachmentStream = object; - if (!attachmentStream.lazyRestoreFragment) { + TSAttachmentPointer *attachmentPointer = object; + if (!attachmentPointer.lazyRestoreFragment) { OWSFailDebug( @"Invalid object: %@ in collection:%@", [object class], collection); return; } - [recordNames addObject:attachmentStream.lazyRestoreFragment.recordName]; + [recordNames addObject:attachmentPointer.lazyRestoreFragment.recordName]; }]; }]; return recordNames; @@ -535,7 +535,7 @@ NS_ASSUME_NONNULL_BEGIN return attachmentIds; } -- (void)lazyRestoreAttachment:(TSAttachmentStream *)attachment +- (void)lazyRestoreAttachment:(TSAttachmentPointer *)attachment backupIO:(OWSBackupIO *)backupIO completion:(OWSBackupBoolBlock)completion { @@ -543,16 +543,6 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(backupIO); OWSAssertDebug(completion); - NSString *_Nullable attachmentFilePath = [attachment originalFilePath]; - if (attachmentFilePath.length < 1) { - OWSLogError(@"Attachment has invalid file path."); - return completion(NO); - } - if ([NSFileManager.defaultManager fileExistsAtPath:attachmentFilePath]) { - OWSLogError(@"Attachment already has file."); - return completion(NO); - } - OWSBackupFragment *_Nullable lazyRestoreFragment = attachment.lazyRestoreFragment; if (!lazyRestoreFragment) { OWSLogWarn(@"Attachment missing lazy restore metadata."); @@ -587,13 +577,13 @@ NS_ASSUME_NONNULL_BEGIN }]; } -- (void)lazyRestoreAttachment:(TSAttachmentStream *)attachment +- (void)lazyRestoreAttachment:(TSAttachmentPointer *)attachmentPointer backupIO:(OWSBackupIO *)backupIO encryptedFilePath:(NSString *)encryptedFilePath encryptionKey:(NSData *)encryptionKey completion:(OWSBackupBoolBlock)completion { - OWSAssertDebug(attachment); + OWSAssertDebug(attachmentPointer); OWSAssertDebug(backupIO); OWSAssertDebug(encryptedFilePath.length > 0); OWSAssertDebug(encryptionKey.length > 0); @@ -614,7 +604,9 @@ NS_ASSUME_NONNULL_BEGIN } } - NSString *_Nullable attachmentFilePath = [attachment originalFilePath]; + TSAttachmentStream *stream = [[TSAttachmentStream alloc] initWithPointer:attachmentPointer]; + + NSString *attachmentFilePath = stream.originalFilePath; if (attachmentFilePath.length < 1) { OWSLogError(@"Attachment has invalid file path."); return completion(NO); @@ -634,7 +626,10 @@ NS_ASSUME_NONNULL_BEGIN return completion(NO); } - [attachment updateWithLazyRestoreComplete]; + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + // This should overwrite the attachment pointer with an attachment stream. + [stream saveWithTransaction:transaction]; + }]; completion(YES); } diff --git a/Signal/src/util/Backup/OWSBackupImportJob.m b/Signal/src/util/Backup/OWSBackupImportJob.m index 57b6e3607..64080ea8b 100644 --- a/Signal/src/util/Backup/OWSBackupImportJob.m +++ b/Signal/src/util/Backup/OWSBackupImportJob.m @@ -281,13 +281,18 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe // Attachment-related errors are recoverable and can be ignored. continue; } - TSAttachmentStream *_Nullable attachment = - [TSAttachmentStream fetchObjectWithUniqueID:item.attachmentId transaction:transaction]; + TSAttachmentPointer *_Nullable attachment = + [TSAttachmentPointer fetchObjectWithUniqueID:item.attachmentId transaction:transaction]; if (!attachment) { OWSLogError(@"attachment to restore could not be found."); // Attachment-related errors are recoverable and can be ignored. continue; } + if (![attachment isKindOfClass:[TSAttachmentPointer class]]) { + OWSFailDebug(@"attachment has unexpected type: %@.", attachment.class); + // Attachment-related errors are recoverable and can be ignored. + continue; + } [attachment markForLazyRestoreWithFragment:item transaction:transaction]; count++; [self updateProgressWithDescription:NSLocalizedString(@"BACKUP_IMPORT_PHASE_RESTORING_FILES", diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h index 302fd8417..dffa586f7 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h @@ -27,7 +27,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { // TSAttachmentPointer, which can be distinguished by the isDownloaded // property. @property (atomic, readwrite) UInt64 serverId; -@property (atomic, readwrite) NSData *encryptionKey; +@property (atomic, readwrite, nullable) NSData *encryptionKey; @property (nonatomic, readonly) NSString *contentType; @property (atomic, readwrite) BOOL isDownloaded; @property (nonatomic) TSAttachmentType attachmentType; @@ -62,6 +62,13 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { caption:(nullable NSString *)caption albumMessageId:(nullable NSString *)albumMessageId; +// This constructor is used for new instances of TSAttachmentPointer, +// i.e. undownloaded restoring attachments. +- (instancetype)initWithContentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId; + // This constructor is used for new instances of TSAttachmentStream // that represent new, un-uploaded outgoing attachments. - (instancetype)initWithContentType:(NSString *)contentType diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m index edc60ded3..0ad173aba 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m @@ -65,6 +65,35 @@ NSUInteger const TSAttachmentSchemaVersion = 4; return self; } +// This constructor is used for new instances of TSAttachmentPointer, +// i.e. undownloaded restoring attachments. +- (instancetype)initWithContentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId +{ + if (contentType.length < 1) { + OWSLogWarn(@"incoming attachment has invalid content type"); + + contentType = OWSMimeTypeApplicationOctetStream; + } + OWSAssertDebug(contentType.length > 0); + + self = [super init]; + if (!self) { + return self; + } + + _contentType = contentType; + _sourceFilename = sourceFilename; + _caption = caption; + _albumMessageId = albumMessageId; + + _attachmentSchemaVersion = TSAttachmentSchemaVersion; + + return self; +} + // This constructor is used for new instances of TSAttachmentStream // that represent new, un-uploaded outgoing attachments. - (instancetype)initWithContentType:(NSString *)contentType diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h index 12a8382cf..9005d1326 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h @@ -6,9 +6,15 @@ NS_ASSUME_NONNULL_BEGIN +@class OWSBackupFragment; @class SSKProtoAttachmentPointer; @class TSMessage; +typedef NS_ENUM(NSUInteger, TSAttachmentPointerType) { + TSAttachmentPointerTypeIncoming = 0, + TSAttachmentPointerTypeRestoring = 2, +}; + typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { TSAttachmentPointerStateEnqueued = 0, TSAttachmentPointerStateDownloading = 1, @@ -20,6 +26,17 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { */ @interface TSAttachmentPointer : TSAttachment +@property (nonatomic) TSAttachmentPointerType pointerType; +@property (atomic) TSAttachmentPointerState state; +@property (nullable, atomic) NSString *mostRecentFailureLocalizedText; + +// Though now required, `digest` may be null for pre-existing records or from +// messages received from other clients +@property (nullable, nonatomic, readonly) NSData *digest; + +// Non-nil for attachments which need "lazy backup restore." +- (nullable OWSBackupFragment *)lazyRestoreFragment; + - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - (instancetype)initWithServerId:(UInt64)serverId @@ -32,6 +49,12 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { albumMessageId:(nullable NSString *)albumMessageId attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER; +- (instancetype)initForRestoreWithContentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId + attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER; + + (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto albumMessage:(nullable TSMessage *)message; @@ -39,12 +62,11 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { (NSArray *)attachmentProtos albumMessage:(TSMessage *)message; -@property (atomic) TSAttachmentPointerState state; -@property (nullable, atomic) NSString *mostRecentFailureLocalizedText; +#pragma mark - Update With... Methods -// Though now required, `digest` may be null for pre-existing records or from -// messages received from other clients -@property (nullable, nonatomic, readonly) NSData *digest; +// Marks attachment as needing "lazy backup restore." +- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment + transaction:(YapDatabaseReadWriteTransaction *)transaction; @end diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m index 2af896187..eca2a4666 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m @@ -3,11 +3,22 @@ // #import "TSAttachmentPointer.h" +#import "OWSBackupFragment.h" #import #import +#import NS_ASSUME_NONNULL_BEGIN +@interface TSAttachmentPointer () + +// Optional property. Only set for attachments which need "lazy backup restore." +@property (nonatomic, nullable) NSString *lazyRestoreFragmentId; + +@end + +#pragma mark - + @implementation TSAttachmentPointer - (nullable instancetype)initWithCoder:(NSCoder *)coder @@ -24,6 +35,10 @@ NS_ASSUME_NONNULL_BEGIN _state = TSAttachmentPointerStateFailed; } + if (![coder containsValueForKey:@"pointerType"]) { + _pointerType = TSAttachmentPointerTypeIncoming; + } + return self; } @@ -51,6 +66,28 @@ NS_ASSUME_NONNULL_BEGIN _digest = digest; _state = TSAttachmentPointerStateEnqueued; self.attachmentType = attachmentType; + _pointerType = TSAttachmentPointerTypeIncoming; + + return self; +} + +- (instancetype)initForRestoreWithContentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId + attachmentType:(TSAttachmentType)attachmentType +{ + self = [super initWithContentType:contentType + sourceFilename:sourceFilename + caption:caption + albumMessageId:albumMessageId]; + if (!self) { + return self; + } + + _state = TSAttachmentPointerStateEnqueued; + self.attachmentType = attachmentType; + _pointerType = TSAttachmentPointerTypeRestoring; return self; } @@ -141,6 +178,34 @@ NS_ASSUME_NONNULL_BEGIN } } +- (nullable OWSBackupFragment *)lazyRestoreFragment +{ + if (!self.lazyRestoreFragmentId) { + return nil; + } + return [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId]; +} + +#pragma mark - Update With... Methods + +- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssertDebug(lazyRestoreFragment); + OWSAssertDebug(transaction); + + if (!lazyRestoreFragment.uniqueId) { + // If metadata hasn't been saved yet, save now. + [lazyRestoreFragment saveWithTransaction:transaction]; + + OWSAssertDebug(lazyRestoreFragment.uniqueId); + } + [self applyChangeToSelfAndLatestCopy:transaction + changeBlock:^(TSAttachmentPointer *attachment) { + [attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId]; + }]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h index 1658f21bf..3c071d152 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h @@ -3,7 +3,6 @@ // #import "DataSource.h" -#import "OWSBackupFragment.h" #import "TSAttachment.h" #if TARGET_OS_IPHONE @@ -70,9 +69,6 @@ typedef void (^OWSThumbnailFailure)(void); + (nullable NSError *)migrateToSharedData; -// Non-nil for attachments which need "lazy backup restore." -- (nullable OWSBackupFragment *)lazyRestoreFragment; - #pragma mark - Thumbnails // On cache hit, the thumbnail will be returned synchronously and completion will never be invoked. @@ -99,12 +95,6 @@ typedef void (^OWSThumbnailFailure)(void); #pragma mark - Update With... Methods -// Marks attachment as needing "lazy backup restore." -- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment - transaction:(YapDatabaseReadWriteTransaction *)transaction; -// Marks attachment as having completed "lazy backup restore." -- (void)updateWithLazyRestoreComplete; - - (nullable TSAttachmentStream *)cloneAsThumbnail; #pragma mark - Protobuf diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index c5e70b384..52f693603 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -39,9 +39,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); // This property should only be accessed on the main thread. @property (nullable, nonatomic) NSNumber *cachedAudioDurationSeconds; -// Optional property. Only set for attachments which need "lazy backup restore." -@property (nonatomic, nullable) NSString *lazyRestoreFragmentId; - @property (atomic, nullable) NSNumber *isValidImageCached; @property (atomic, nullable) NSNumber *isValidVideoCached; @@ -358,10 +355,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); { OWSAssertDebug(self.isImage || self.isAnimated); - if (self.lazyRestoreFragment) { - return NO; - } - @synchronized(self) { if (!self.isValidImageCached) { self.isValidImageCached = @@ -375,10 +368,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); { OWSAssertDebug(self.isVideo); - if (self.lazyRestoreFragment) { - return NO; - } - @synchronized(self) { if (!self.isValidVideoCached) { self.isValidVideoCached = @([OWSMediaUtils isValidVideoWithPath:self.originalFilePath]); @@ -629,14 +618,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); return audioDurationSeconds; } -- (nullable OWSBackupFragment *)lazyRestoreFragment -{ - if (!self.lazyRestoreFragmentId) { - return nil; - } - return [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId]; -} - #pragma mark - Thumbnails - (nullable UIImage *)thumbnailImageWithSizeHint:(CGSize)sizeHint @@ -819,34 +800,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); #pragma mark - Update With... Methods -- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(lazyRestoreFragment); - OWSAssertDebug(transaction); - - if (!lazyRestoreFragment.uniqueId) { - // If metadata hasn't been saved yet, save now. - [lazyRestoreFragment saveWithTransaction:transaction]; - - OWSAssertDebug(lazyRestoreFragment.uniqueId); - } - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSAttachmentStream *attachment) { - [attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId]; - }]; -} - -- (void)updateWithLazyRestoreComplete -{ - [self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSAttachmentStream *attachment) { - [attachment setLazyRestoreFragmentId:nil]; - }]; - }]; -} - - (nullable TSAttachmentStream *)cloneAsThumbnail { NSData *_Nullable thumbnailData = self.thumbnailDataSmallSync; diff --git a/SignalServiceKit/src/Storage/TSDatabaseView.m b/SignalServiceKit/src/Storage/TSDatabaseView.m index ce24c1087..ade284d92 100644 --- a/SignalServiceKit/src/Storage/TSDatabaseView.m +++ b/SignalServiceKit/src/Storage/TSDatabaseView.m @@ -6,7 +6,7 @@ #import "OWSDevice.h" #import "OWSReadTracking.h" #import "TSAttachment.h" -#import "TSAttachmentStream.h" +#import "TSAttachmentPointer.h" #import "TSIncomingMessage.h" #import "TSInvalidIdentityKeyErrorMessage.h" #import "TSOutgoingMessage.h" @@ -369,47 +369,47 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); return nil; } - if (![object isKindOfClass:[TSAttachmentStream class]]) { + if (![object isKindOfClass:[TSAttachmentPointer class]]) { return nil; } - TSAttachmentStream *attachmentStream = (TSAttachmentStream *)object; - if (attachmentStream.lazyRestoreFragment) { + TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)object; + if (attachmentPointer.lazyRestoreFragment) { return TSLazyRestoreAttachmentsGroup; } else { return nil; } }]; - YapDatabaseViewSorting *viewSorting = [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult( - YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[TSAttachmentStream class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - if (![object2 isKindOfClass:[TSAttachmentStream class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } + YapDatabaseViewSorting *viewSorting = + [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, + NSString *group, + NSString *collection1, + NSString *key1, + id object1, + NSString *collection2, + NSString *key2, + id object2) { + if (![object1 isKindOfClass:[TSAttachmentPointer class]]) { + OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); + return NSOrderedSame; + } + if (![object2 isKindOfClass:[TSAttachmentPointer class]]) { + OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); + return NSOrderedSame; + } - // Specific ordering doesn't matter; we just need a stable ordering. - TSAttachmentStream *attachmentStream1 = (TSAttachmentStream *)object1; - TSAttachmentStream *attachmentStream2 = (TSAttachmentStream *)object2; - return [attachmentStream2.creationTimestamp compare:attachmentStream1.creationTimestamp]; - }]; + // Specific ordering doesn't matter; we just need a stable ordering. + TSAttachmentPointer *attachmentPointer1 = (TSAttachmentPointer *)object1; + TSAttachmentPointer *attachmentPointer2 = (TSAttachmentPointer *)object2; + return [attachmentPointer1.uniqueId compare:attachmentPointer2.uniqueId]; + }]; YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; options.isPersistent = YES; options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSAttachment collection]]]; YapDatabaseView *view = - [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options]; + [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"4" options:options]; [storage asyncRegisterExtension:view withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName]; } From e72dafb08e60618336e8291fd16f743b664ad986 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Nov 2018 11:53:27 -0500 Subject: [PATCH 2/6] Use attachment pointers to restore attachments from backup. --- .../Cells/ConversationMediaView.swift | 6 +++ .../Cells/ConversationViewCell.h | 1 - .../Cells/OWSMessageBubbleView.m | 2 + Signal/src/util/Backup/OWSBackup.h | 2 +- .../util/Backup/OWSBackupLazyRestoreJob.swift | 5 ++- .../Attachments/OWSAttachmentDownloads.m | 4 ++ .../Attachments/OWSAttachmentsProcessor.h | 42 ------------------- 7 files changed, 16 insertions(+), 46 deletions(-) delete mode 100644 SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift index af3702dc2..6473a3e50 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift @@ -86,6 +86,12 @@ public class ConversationMediaView: UIView { configure(forError: .invalid) return } + guard attachmentPointer.pointerType == .incoming else { + // TODO: Show "restoring" indicator and possibly progress. + owsFailDebug("Attachment is restorying from backup.") + configure(forError: .missing) + return + } guard let attachmentId = attachmentPointer.uniqueId else { owsFailDebug("Attachment missing unique ID.") configure(forError: .invalid) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h index cc2c1a022..1b4f94496 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h +++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h @@ -8,7 +8,6 @@ NS_ASSUME_NONNULL_BEGIN @class ConversationViewCell; @class OWSContactOffersInteraction; @class OWSContactsManager; -@class TSAttachmentPointer; @class TSAttachmentStream; @class TSCall; @class TSErrorMessage; diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index b323e39b4..4b9adb061 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -835,6 +835,8 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes { OWSAssertDebug(self.attachmentPointer); + // TODO: We probably want to do something different for attachments + // being restored from backup. AttachmentPointerView *downloadView = [[AttachmentPointerView alloc] initWithAttachmentPointer:self.attachmentPointer isIncoming:self.isIncoming diff --git a/Signal/src/util/Backup/OWSBackup.h b/Signal/src/util/Backup/OWSBackup.h index 6cb703ac4..6894a33d1 100644 --- a/Signal/src/util/Backup/OWSBackup.h +++ b/Signal/src/util/Backup/OWSBackup.h @@ -22,7 +22,7 @@ typedef NS_ENUM(NSUInteger, OWSBackupState) { @class OWSBackupIO; @class OWSPrimaryStorage; -@class TSAttachmentStream; +@class TSAttachmentPointer; @class TSThread; @interface OWSBackup : NSObject diff --git a/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift b/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift index 184572823..2aace7dd1 100644 --- a/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift +++ b/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift @@ -68,7 +68,8 @@ public class OWSBackupLazyRestoreJob: NSObject { return } attachmentIdsCopy.removeLast() - guard let attachment = TSAttachmentStream.fetch(uniqueId: attachmentId) else { + guard let attachment = TSAttachment.fetch(uniqueId: attachmentId), + let attachmentPointer = attachment as? TSAttachmentPointer else { Logger.warn("could not load attachment.") // Not necessarily an error. // The attachment might have been deleted since the job began. @@ -76,7 +77,7 @@ public class OWSBackupLazyRestoreJob: NSObject { tryToRestoreNextAttachment(attachmentIds: attachmentIds, backupIO: backupIO) return } - OWSBackup.shared().lazyRestoreAttachment(attachment, + OWSBackup.shared().lazyRestoreAttachment(attachmentPointer, backupIO: backupIO, completion: { (success) in if success { diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentDownloads.m b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentDownloads.m index a5d3d3a94..fc855804a 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentDownloads.m +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentDownloads.m @@ -147,6 +147,10 @@ typedef void (^AttachmentDownloadFailure)(NSError *error); [attachmentStreams addObject:attachmentStream]; } else if ([attachment isKindOfClass:[TSAttachmentPointer class]]) { TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)attachment; + if (attachmentPointer.pointerType != TSAttachmentPointerTypeIncoming) { + OWSLogInfo(@"Ignoring restoring attachment."); + continue; + } [attachmentPointers addObject:attachmentPointer]; } else { OWSFailDebug(@"Unexpected attachment type: %@", attachment.class); diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h deleted file mode 100644 index 44fadda8d..000000000 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const kAttachmentDownloadProgressNotification; -extern NSString *const kAttachmentDownloadProgressKey; -extern NSString *const kAttachmentDownloadAttachmentIDKey; - -@class OWSPrimaryStorage; -@class SSKProtoAttachmentPointer; -@class TSAttachmentPointer; -@class TSAttachmentStream; -@class TSMessage; -@class TSNetworkManager; -@class TSThread; -@class YapDatabaseReadWriteTransaction; - -/** - * Given incoming attachment protos, determines which we support. - * It can download those that we support and notifies threads when it receives unsupported attachments. - */ -@interface OWSAttachmentsProcessor : NSObject - -@property (nonatomic, readonly) NSArray *attachmentPointers; - -- (instancetype)init NS_UNAVAILABLE; - -/* - * Retry fetching failed attachment download - */ -- (instancetype)initWithAttachmentPointers:(NSArray *)attachmentPointers - NS_DESIGNATED_INITIALIZER; - -- (void)fetchAttachmentsForMessage:(nullable TSMessage *)message - transaction:(YapDatabaseReadWriteTransaction *)transaction - success:(void (^)(NSArray *attachmentStreams))successHandler - failure:(void (^)(NSError *error))failureHandler; -@end - -NS_ASSUME_NONNULL_END From d76bdf3a58d61c6991feb85b741f3c52048fa253 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Nov 2018 14:28:28 -0500 Subject: [PATCH 3/6] Use attachment pointers to restore attachments from backup. --- Signal/src/util/Backup/OWSBackup.m | 5 ++++ Signal/src/util/Backup/OWSBackupExportJob.m | 12 ++++++++ .../src/Messages/Attachments/TSAttachment.h | 12 ++++---- .../src/Messages/Attachments/TSAttachment.m | 28 +++++++++++-------- .../Attachments/TSAttachmentPointer.h | 7 ++--- .../Attachments/TSAttachmentPointer.m | 20 ++++++------- .../src/Messages/OWSMessageSender.m | 2 +- 7 files changed, 54 insertions(+), 32 deletions(-) diff --git a/Signal/src/util/Backup/OWSBackup.m b/Signal/src/util/Backup/OWSBackup.m index b3288c510..e470f6a58 100644 --- a/Signal/src/util/Backup/OWSBackup.m +++ b/Signal/src/util/Backup/OWSBackup.m @@ -618,6 +618,11 @@ NS_ASSUME_NONNULL_BEGIN return completion(NO); } + if (![OWSFileSystem deleteFileIfExists:attachmentFilePath]) { + OWSLogError(@"Couldn't delete exist file at attachment path."); + return completion(NO); + } + NSError *error; BOOL success = [NSFileManager.defaultManager moveItemAtPath:decryptedFilePath toPath:attachmentFilePath error:&error]; diff --git a/Signal/src/util/Backup/OWSBackupExportJob.m b/Signal/src/util/Backup/OWSBackupExportJob.m index f3208051b..21c9f6e75 100644 --- a/Signal/src/util/Backup/OWSBackupExportJob.m +++ b/Signal/src/util/Backup/OWSBackupExportJob.m @@ -507,6 +507,17 @@ NS_ASSUME_NONNULL_BEGIN TSYapDatabaseObject *entity = object; count++; + if ([entity isKindOfClass:[TSAttachmentStream class]]) { + // Convert attachment streams to pointers, + // since we'll need to restore them. + TSAttachmentStream *attachmentStream + = (TSAttachmentStream *)entity; + TSAttachmentPointer *attachmentPointer = + [[TSAttachmentPointer alloc] + initForRestoreWithAttachmentStream:attachmentStream]; + entity = attachmentPointer; + } + if (![exportStream writeObject:entity entityType:entityType]) { *stop = YES; aborted = YES; @@ -536,6 +547,7 @@ NS_ASSUME_NONNULL_BEGIN [TSAttachment class], ^(id object) { if (![object isKindOfClass:[TSAttachmentStream class]]) { + // No need to backup the contents of attachment pointers. return NO; } TSAttachmentStream *attachmentStream = object; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h index dffa586f7..9e50d6c1d 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h @@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN +@class TSAttachmentPointer; @class TSMessage; typedef NS_ENUM(NSUInteger, TSAttachmentType) { @@ -64,10 +65,11 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { // This constructor is used for new instances of TSAttachmentPointer, // i.e. undownloaded restoring attachments. -- (instancetype)initWithContentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId; +- (instancetype)initWithUniqueId:(NSString *)uniqueId + contentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId; // This constructor is used for new instances of TSAttachmentStream // that represent new, un-uploaded outgoing attachments. @@ -79,7 +81,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { // This constructor is used for new instances of TSAttachmentStream // that represent downloaded incoming attachments. -- (instancetype)initWithPointer:(TSAttachment *)pointer; +- (instancetype)initWithPointer:(TSAttachmentPointer *)pointer; - (nullable instancetype)initWithCoder:(NSCoder *)coder; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m index 0ad173aba..3f7c1c22e 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m @@ -4,6 +4,7 @@ #import "TSAttachment.h" #import "MIMETypeUtil.h" +#import "TSAttachmentPointer.h" #import "TSMessage.h" #import #import @@ -67,11 +68,13 @@ NSUInteger const TSAttachmentSchemaVersion = 4; // This constructor is used for new instances of TSAttachmentPointer, // i.e. undownloaded restoring attachments. -- (instancetype)initWithContentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId +- (instancetype)initWithUniqueId:(NSString *)uniqueId + contentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId { + OWSAssertDebug(uniqueId.length > 0); if (contentType.length < 1) { OWSLogWarn(@"incoming attachment has invalid content type"); @@ -79,7 +82,8 @@ NSUInteger const TSAttachmentSchemaVersion = 4; } OWSAssertDebug(contentType.length > 0); - self = [super init]; + // Once saved, this AttachmentStream will replace the AttachmentPointer in the attachments collection. + self = [super initWithUniqueId:uniqueId]; if (!self) { return self; } @@ -128,13 +132,15 @@ NSUInteger const TSAttachmentSchemaVersion = 4; // This constructor is used for new instances of TSAttachmentStream // that represent downloaded incoming attachments. -- (instancetype)initWithPointer:(TSAttachment *)pointer +- (instancetype)initWithPointer:(TSAttachmentPointer *)pointer { - OWSAssertDebug(pointer.serverId > 0); - OWSAssertDebug(pointer.encryptionKey.length > 0); - if (pointer.byteCount <= 0) { - // This will fail with legacy iOS clients which don't upload attachment size. - OWSLogWarn(@"Missing pointer.byteCount for attachment with serverId: %lld", pointer.serverId); + if (!pointer.lazyRestoreFragment) { + OWSAssertDebug(pointer.serverId > 0); + OWSAssertDebug(pointer.encryptionKey.length > 0); + if (pointer.byteCount <= 0) { + // This will fail with legacy iOS clients which don't upload attachment size. + OWSLogWarn(@"Missing pointer.byteCount for attachment with serverId: %lld", pointer.serverId); + } } OWSAssertDebug(pointer.contentType.length > 0); diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h index 9005d1326..156c88d7d 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h @@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWSBackupFragment; @class SSKProtoAttachmentPointer; +@class TSAttachmentStream; @class TSMessage; typedef NS_ENUM(NSUInteger, TSAttachmentPointerType) { @@ -49,11 +50,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { albumMessageId:(nullable NSString *)albumMessageId attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER; -- (instancetype)initForRestoreWithContentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId - attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER; +- (instancetype)initForRestoreWithAttachmentStream:(TSAttachmentStream *)attachmentStream NS_DESIGNATED_INITIALIZER; + (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto albumMessage:(nullable TSMessage *)message; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m index eca2a4666..49e62a349 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m @@ -4,6 +4,7 @@ #import "TSAttachmentPointer.h" #import "OWSBackupFragment.h" +#import "TSAttachmentStream.h" #import #import #import @@ -71,22 +72,21 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (instancetype)initForRestoreWithContentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId - attachmentType:(TSAttachmentType)attachmentType +- (instancetype)initForRestoreWithAttachmentStream:(TSAttachmentStream *)attachmentStream { - self = [super initWithContentType:contentType - sourceFilename:sourceFilename - caption:caption - albumMessageId:albumMessageId]; + OWSAssertDebug(attachmentStream); + + self = [super initWithUniqueId:attachmentStream.uniqueId + contentType:attachmentStream.contentType + sourceFilename:attachmentStream.sourceFilename + caption:attachmentStream.caption + albumMessageId:attachmentStream.albumMessageId]; if (!self) { return self; } _state = TSAttachmentPointerStateEnqueued; - self.attachmentType = attachmentType; + self.attachmentType = attachmentStream.attachmentType; _pointerType = TSAttachmentPointerTypeRestoring; return self; diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index e327b7f0b..d06c6aa5e 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -566,7 +566,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } } else { // Neither a group nor contact thread? This should never happen. - OWSFailDebug(@"Unknown message type: %@", [message class]); + OWSLogError(@"Unknown message type: %@", [message class]); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); [error setIsRetryable:NO]; *errorHandle = error; From f5ba8048b71a3059707f87dacf7e5e4970be5a2f Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Nov 2018 14:32:11 -0500 Subject: [PATCH 4/6] Clean up ahead of PR. --- .../ConversationView/Cells/ConversationMediaView.swift | 2 +- SignalServiceKit/src/Messages/OWSMessageSender.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift index 6473a3e50..4389d6a50 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift @@ -88,7 +88,7 @@ public class ConversationMediaView: UIView { } guard attachmentPointer.pointerType == .incoming else { // TODO: Show "restoring" indicator and possibly progress. - owsFailDebug("Attachment is restorying from backup.") + owsFailDebug("Attachment is restoring from backup.") configure(forError: .missing) return } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index d06c6aa5e..e327b7f0b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -566,7 +566,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } } else { // Neither a group nor contact thread? This should never happen. - OWSLogError(@"Unknown message type: %@", [message class]); + OWSFailDebug(@"Unknown message type: %@", [message class]); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); [error setIsRetryable:NO]; *errorHandle = error; From 5f8755f2eb94b4ac52d2857135dabb8e2f7dffaa Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 21 Nov 2018 09:25:24 -0800 Subject: [PATCH 5/6] Respond to CR. --- Signal/src/environment/AppEnvironment.swift | 3 +- Signal/src/util/Backup/OWSBackup.h | 4 +-- Signal/src/util/Backup/OWSBackup.m | 36 ++++++++++++------- Signal/src/util/Backup/OWSBackupExportJob.m | 6 ++-- .../util/Backup/OWSBackupLazyRestoreJob.swift | 3 +- .../src/Messages/Attachments/TSAttachment.h | 10 +++--- .../src/Messages/Attachments/TSAttachment.m | 14 ++++---- .../Attachments/TSAttachmentPointer.h | 3 +- .../Attachments/TSAttachmentPointer.m | 12 +++---- 9 files changed, 52 insertions(+), 39 deletions(-) diff --git a/Signal/src/environment/AppEnvironment.swift b/Signal/src/environment/AppEnvironment.swift index 1c70054b6..44368d989 100644 --- a/Signal/src/environment/AppEnvironment.swift +++ b/Signal/src/environment/AppEnvironment.swift @@ -69,8 +69,7 @@ import SignalMessaging self.pushRegistrationManager = PushRegistrationManager() self.pushManager = PushManager() self.sessionResetJobQueue = SessionResetJobQueue() - assert(SSKEnvironment.shared.primaryStorage != nil) - self.backup = OWSBackup(primaryStorage: SSKEnvironment.shared.primaryStorage) + self.backup = OWSBackup() super.init() diff --git a/Signal/src/util/Backup/OWSBackup.h b/Signal/src/util/Backup/OWSBackup.h index 6894a33d1..0f0823b0f 100644 --- a/Signal/src/util/Backup/OWSBackup.h +++ b/Signal/src/util/Backup/OWSBackup.h @@ -21,14 +21,12 @@ typedef NS_ENUM(NSUInteger, OWSBackupState) { }; @class OWSBackupIO; -@class OWSPrimaryStorage; @class TSAttachmentPointer; @class TSThread; @interface OWSBackup : NSObject -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_DESIGNATED_INITIALIZER; + (instancetype)sharedManager NS_SWIFT_NAME(shared()); diff --git a/Signal/src/util/Backup/OWSBackup.m b/Signal/src/util/Backup/OWSBackup.m index e470f6a58..8e3ea7a93 100644 --- a/Signal/src/util/Backup/OWSBackup.m +++ b/Signal/src/util/Backup/OWSBackup.m @@ -51,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN return AppEnvironment.shared.backup; } -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage +- (instancetype)init { self = [super init]; @@ -59,10 +59,6 @@ NS_ASSUME_NONNULL_BEGIN return self; } - OWSAssertDebug(primaryStorage); - - _dbConnection = primaryStorage.newDatabaseConnection; - _backupExportState = OWSBackupState_Idle; _backupImportState = OWSBackupState_Idle; @@ -101,6 +97,25 @@ NS_ASSUME_NONNULL_BEGIN }); } +- (YapDatabaseConnection *)dbConnection +{ + @synchronized(self) { + if (!_dbConnection) { + _dbConnection = self.primaryStorage.newDatabaseConnection; + } + return _dbConnection; + } +} + +#pragma mark - Dependencies + +- (OWSPrimaryStorage *)primaryStorage +{ + OWSAssertDebug(SSKEnvironment.shared.primaryStorage); + + return SSKEnvironment.shared.primaryStorage; +} + #pragma mark - Backup Export - (void)tryToExportBackup @@ -121,8 +136,7 @@ NS_ASSUME_NONNULL_BEGIN _backupExportState = OWSBackupState_InProgress; - self.backupExportJob = - [[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:[OWSPrimaryStorage sharedManager]]; + self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:self.primaryStorage]; [self.backupExportJob startAsync]; [self postDidChangeNotification]; @@ -254,8 +268,7 @@ NS_ASSUME_NONNULL_BEGIN [self.backupExportJob cancel]; self.backupExportJob = nil; } else if (self.shouldHaveBackupExport && !self.backupExportJob) { - self.backupExportJob = - [[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:[OWSPrimaryStorage sharedManager]]; + self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:self.primaryStorage]; [self.backupExportJob startAsync]; } @@ -321,8 +334,7 @@ NS_ASSUME_NONNULL_BEGIN _backupImportState = OWSBackupState_InProgress; - self.backupImportJob = - [[OWSBackupImportJob alloc] initWithDelegate:self primaryStorage:[OWSPrimaryStorage sharedManager]]; + self.backupImportJob = [[OWSBackupImportJob alloc] initWithDelegate:self primaryStorage:self.primaryStorage]; [self.backupImportJob startAsync]; [self postDidChangeNotification]; @@ -619,7 +631,7 @@ NS_ASSUME_NONNULL_BEGIN } if (![OWSFileSystem deleteFileIfExists:attachmentFilePath]) { - OWSLogError(@"Couldn't delete exist file at attachment path."); + OWSFailDebug(@"Couldn't delete existing file at attachment path."); return completion(NO); } diff --git a/Signal/src/util/Backup/OWSBackupExportJob.m b/Signal/src/util/Backup/OWSBackupExportJob.m index 21c9f6e75..9a052dfd5 100644 --- a/Signal/src/util/Backup/OWSBackupExportJob.m +++ b/Signal/src/util/Backup/OWSBackupExportJob.m @@ -547,8 +547,10 @@ NS_ASSUME_NONNULL_BEGIN [TSAttachment class], ^(id object) { if (![object isKindOfClass:[TSAttachmentStream class]]) { - // No need to backup the contents of attachment pointers. - return NO; + // No need to backup the contents (e.g. the file on disk) + // of attachment pointers. + // After a restore, users will be able "tap to retry". + return YES; } TSAttachmentStream *attachmentStream = object; NSString *_Nullable filePath = attachmentStream.originalFilePath; diff --git a/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift b/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift index 2aace7dd1..e58189cce 100644 --- a/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift +++ b/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift @@ -68,8 +68,7 @@ public class OWSBackupLazyRestoreJob: NSObject { return } attachmentIdsCopy.removeLast() - guard let attachment = TSAttachment.fetch(uniqueId: attachmentId), - let attachmentPointer = attachment as? TSAttachmentPointer else { + guard let attachmentPointer = TSAttachment.fetch(uniqueId: attachmentId) as? TSAttachmentPointer else { Logger.warn("could not load attachment.") // Not necessarily an error. // The attachment might have been deleted since the job began. diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h index 9e50d6c1d..01bb3c40f 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h @@ -65,11 +65,11 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { // This constructor is used for new instances of TSAttachmentPointer, // i.e. undownloaded restoring attachments. -- (instancetype)initWithUniqueId:(NSString *)uniqueId - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId; +- (instancetype)initForRestoreWithUniqueId:(NSString *)uniqueId + contentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId; // This constructor is used for new instances of TSAttachmentStream // that represent new, un-uploaded outgoing attachments. diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m index 3f7c1c22e..22955fc29 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m @@ -68,11 +68,11 @@ NSUInteger const TSAttachmentSchemaVersion = 4; // This constructor is used for new instances of TSAttachmentPointer, // i.e. undownloaded restoring attachments. -- (instancetype)initWithUniqueId:(NSString *)uniqueId - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId +- (instancetype)initForRestoreWithUniqueId:(NSString *)uniqueId + contentType:(NSString *)contentType + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId { OWSAssertDebug(uniqueId.length > 0); if (contentType.length < 1) { @@ -82,7 +82,9 @@ NSUInteger const TSAttachmentSchemaVersion = 4; } OWSAssertDebug(contentType.length > 0); - // Once saved, this AttachmentStream will replace the AttachmentPointer in the attachments collection. + // If saved, this AttachmentPointer would replace the AttachmentStream in the attachments collection. + // However we only use this AttachmentPointer should only be used during the export process so it + // won't be saved until we restore the backup (when there will be no AttachmentStream to replace). self = [super initWithUniqueId:uniqueId]; if (!self) { return self; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h index 156c88d7d..a4a19bd28 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h @@ -12,7 +12,8 @@ NS_ASSUME_NONNULL_BEGIN @class TSMessage; typedef NS_ENUM(NSUInteger, TSAttachmentPointerType) { - TSAttachmentPointerTypeIncoming = 0, + TSAttachmentPointerTypeUnknown = 0, + TSAttachmentPointerTypeIncoming = 1, TSAttachmentPointerTypeRestoring = 2, }; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m index 49e62a349..1fc16e38d 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m @@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN _state = TSAttachmentPointerStateFailed; } - if (![coder containsValueForKey:@"pointerType"]) { + if (_pointerType == TSAttachmentPointerTypeUnknown) { _pointerType = TSAttachmentPointerTypeIncoming; } @@ -76,11 +76,11 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertDebug(attachmentStream); - self = [super initWithUniqueId:attachmentStream.uniqueId - contentType:attachmentStream.contentType - sourceFilename:attachmentStream.sourceFilename - caption:attachmentStream.caption - albumMessageId:attachmentStream.albumMessageId]; + self = [super initForRestoreWithUniqueId:attachmentStream.uniqueId + contentType:attachmentStream.contentType + sourceFilename:attachmentStream.sourceFilename + caption:attachmentStream.caption + albumMessageId:attachmentStream.albumMessageId]; if (!self) { return self; } From de6c058acdf60feacc9a5677b12ec7aabdac9668 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 21 Nov 2018 09:26:02 -0800 Subject: [PATCH 6/6] Update Cocoapods. --- Pods | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pods b/Pods index 95badd82b..22f27f0bc 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 95badd82b9f1c193b729617d00db0b71ead8eacf +Subproject commit 22f27f0bc4e1ed8a3a0a4c08272783bf6954e022